|
|
1.1 root 1: /*
2: * An editor.
3: * Commands.
4: */
5: #include <stdio.h>
6: #include <ctype.h>
7: #include "ed.h"
8:
9: /*
10: * Edit a file. The filename is stored in `file'.
11: */
12: edit()
13: {
14: register int ret, i;
15:
16: if (doladd > 0)
17: delete(1, doladd);
18: tmpseek = CLSIZE;
19: rcurbno = -1;
20: wcurbno = -1;
21: if ((fp=xfopen(file, "r")) == NULL) {
22: derror("Cannot open file");
23: return (0);
24: }
25: #if RSX
26: if ((i=fp->v_efbk+1-tmp->v_hibk) > 0) {
27: if (grow(i) == 0) {
28: terror("Temp file error");
29: return (0);
30: }
31: }
32: #endif
33: ret = 1;
34: if (append(0, readfil) == 0)
35: ret = 0;
36: else if (ferror(fp)) {
37: derror("Read error");
38: ret = 0;
39: }
40: fclose(fp);
41: for (i=0; i<MKSIZE; i++)
42: marklin[i] = 0;
43: saved = 1;
44: if (cflag != 0) {
45: printl(stdout, !oflag ? cct : lct);
46: printc(stdout, '\n');
47: }
48: return (ret);
49: }
50:
51: /*
52: * Make sure that the previous command is terminated either
53: * immediately by a newline or has a 'p' or a 'l' which is
54: * then terminated by a newline. The variable `vcom' is set
55: * to the verify command. A zero is returned if there were
56: * bad characters before the newline, otherwise a one.
57: */
58: verify(flag)
59: {
60: register int c;
61:
62: vcom = ' ';
63: if (flag==0 && mflag!=0)
64: return (1);
65: if ((c=getx()) == '\n') {
66: ungetx(c);
67: return (1);
68: }
69: if (c=='l' || c=='p') {
70: if (getx() == '\n') {
71: ungetx('\n');
72: vcom = c;
73: return (1);
74: }
75: }
76: derror("Bad command");
77: return (0);
78: }
79:
80: /*
81: * Get a filename of the form required for the r command.
82: * which is returned in `name'. If no name is specified,
83: * the one stored in `file' is copied. If a file name is
84: * specified and none exists in `file', it is copied to
85: * `file'. If an illegal name is given, an error is derrord.
86: */
87: getfile(name)
88: char name[FNSIZE+1];
89: {
90: register int c;
91: register char *p1, *p2;
92:
93: switch (c=getx()) {
94: case '\n':
95: p1 = name;
96: p2 = file;
97: while (*p1++ = *p2++)
98: ;
99: break;
100: case ' ':
101: case '\t':
102: p1 = name;
103: p2 = &name[FNSIZE];
104: while ((c=getx()) == ' ' || c == '\t')
105: ;
106: *p1++ = c;
107: while ((c=getx()) != EOF && c != '\n') {
108: if (p1 >= p2) {
109: derror("File name too long");
110: name[0] = '\0';
111: return (0);
112: }
113: *p1++ = c;
114: }
115: *p1 = '\0';
116: if (c == EOF) {
117: derror("EOF in file name");
118: name[0] = '\0';
119: return (0);
120: }
121: if (file[0] == '\0') {
122: p1 = file;
123: p2 = name;
124: while (*p1++ = *p2++)
125: ;
126: }
127: break;
128: default:
129: while (getx() != '\n')
130: ;
131: derror("Bad command");
132: return (0);
133: }
134: if (name[0] == '\0') {
135: derror("Null file name");
136: return (0);
137: }
138: return (1);
139: }
140:
141: /*
142: * Read the rest of the input line into `tempbuf'.
143: */
144: rest()
145: {
146: register int c;
147: register char *cp;
148:
149: cp = tempbuf;
150: while ((c=getx())!=EOF && c!='\n') {
151: if (cp >= &tempbuf[TBSIZE-1]) {
152: derror("Line too long");
153: return (0);
154: }
155: *cp++ = c;
156: }
157: *cp = '\0';
158: return (1);
159: }
160:
161: /*
162: * Append text after the given address. A line of text is gotten
163: * by calling the given function until it returns NULL.
164: */
165: append(a, f)
166: int (*f)();
167: {
168: int seek;
169: register int n;
170:
171: cct = 0;
172: lct = 0;
173: if (a<0 || a>doladd) {
174: derror("Address out of range");
175: return (0);
176: }
177: dotadd = a;
178: while ((n=(*f)()) != 0) {
179: if (intflag)
180: return (1);
181: seek = linead();
182: if (putline(linebuf, n) == 0)
183: return (0);
184: saved = 0;
185: cct += n;
186: lct++;
187: if (expand(dotadd) == 0)
188: return (0);
189: line[++dotadd] = seek;
190: }
191: return (1);
192: }
193:
194: /*
195: * Expand the line table and leave a hole at the given address.
196: */
197: expand(a)
198: {
199: register LINE *lp1;
200: register LINE *lp2;
201: register int n;
202:
203: if (doladd+3 >= lnsize) {
204: lp1 = (LINE *)realloc(line, (n=lnsize*2)*sizeof(LINE));
205: if (lp1 == NULL) {
206: derror("Line table overflow");
207: return (0);
208: }
209: line = lp1;
210: lnsize = n;
211: }
212: lp1 = &line[doladd+2];
213: lp2 = &line[doladd+1];
214: n = doladd++ - a;
215: while (n--)
216: *--lp1 = *--lp2;
217: return (1);
218: }
219:
220: /*
221: * Get a line of text from the terminal. The number of characters
222: * including the null terminator at the end of the string is returned.
223: * If end of file or a line containing only a single dot is found,
224: * 0 is returned.
225: */
226: readtty()
227: {
228: register int c;
229: register char *lp;
230:
231: appflag++;
232: lp = linebuf;
233: while ((c=getx())!=EOF && c!='\n') {
234: if (lp < &linebuf[LBSIZE-1])
235: *lp++ = c;
236: }
237: --appflag;
238: if (c==EOF && lp==linebuf) {
239: lastchr = '\n';
240: if (gcp == NULL)
241: clearerr(stdin);
242: return (0);
243: }
244: if (linebuf[0]=='.' && lp==linebuf+1)
245: return (0);
246: *lp++ = '\0';
247: return (lp-linebuf);
248: }
249:
250: /*
251: * Get a line of text from the file open on file pointer `fp'.
252: * Return the number of characters in the line including the
253: * null terminator at the end. On end of file, 0 is returned.
254: */
255: readfil()
256: {
257: register int c, n;
258: register char *lp;
259:
260: if ((c=getc(fp)) == EOF)
261: return (0);
262: lp = linebuf;
263: n = LBSIZE-1;
264: while (c!=EOF && c!='\n') {
265: *lp++ = c;
266: if (--n == 0)
267: break;
268: c = getc(fp);
269: }
270: *lp++ = '\0';
271: return (lp-linebuf);
272: }
273:
274: /*
275: * Delete the given line range.
276: */
277: delete(a1, a2)
278: {
279: register LINE *p1, *p2;
280: register int n;
281:
282: if (a1>a2 || a1<1 || a2>doladd) {
283: derror("Address out of range");
284: return (0);
285: }
286: p1 = &line[a1];
287: p2 = &line[a2+1];
288: n = doladd - a2;
289: while (n--)
290: *p1++ = *p2++;
291: doladd -= (a2+1) - a1;
292: if ((dotadd=a1) > doladd)
293: --dotadd;
294: saved = doladd==0;
295: return (1);
296: }
297:
298: /*
299: * Concatenate the lines in the given range to form
300: * a single line.
301: */
302: join(a1, a2)
303: {
304: long seek;
305: int bn, a;
306: register int n;
307: register char *lp, *tp;
308:
309: if (a1>a2 || a1<1 || a2>doladd) {
310: derror("Address out of range");
311: return (0);
312: }
313: bn = 0;
314: lp = linebuf;
315: for (a=a1; a<=a2; a++) {
316: if ((n=getline(a, tempbuf)) == 0)
317: return (0);
318: if ((bn+=--n) >= LBSIZE-1) {
319: derror("Temporary buffer overflow");
320: return (0);
321: }
322: tp = tempbuf;
323: while (n--)
324: *lp++ = *tp++;
325: }
326: *lp++ = '\0';
327: seek = linead();
328: if (putline(linebuf, ++bn) == 0)
329: return (0);
330: line[a1] = seek;
331: a = doladd - a2;
332: for (n=0; n<a; n++)
333: line[a1+1+n] = line[a2+1+n];
334: dotadd = a1;
335: doladd -= a2 - a1;
336: return (1);
337: }
338:
339: /*
340: * List the given line range. All non-printing characters are
341: * escaped.
342: */
343: list(a1, a2)
344: {
345: int a;
346: register int n;
347: register char *p;
348:
349: if (a1>a2 || a1<1 || a2>doladd) {
350: derror("Address out of range");
351: return (0);
352: }
353: for (a=a1; a<=a2; a++) {
354: if (intflag)
355: return (1);
356: if (getline(a, linebuf) == 0)
357: break;
358: n = 0;
359: for (p=linebuf; *p; p++) {
360: if (n++ >= 72) {
361: n = 0;
362: prints(stdout, "\\\n");
363: }
364: switch (*p) {
365: case '\b':
366: prints(stdout, "-\b<");
367: continue;
368: case '\t':
369: prints(stdout, "-\b>");
370: continue;
371: case '\\':
372: prints(stdout, "\\\\");
373: continue;
374: default:
375: if (isascii(*p) && !iscntrl(*p)) {
376: printc(stdout, *p);
377: continue;
378: }
379: printc(stdout, '\\');
380: printo(stdout, *p);
381: n += 3;
382: }
383: }
384: prints(stdout, "\\n");
385: printc(stdout, '\n');
386: dotadd = a;
387: }
388: return (1);
389: }
390:
391: /*
392: * Take the text that is between lines `a1' and `a2' and
393: * place it after line `a3'.
394: */
395: move(a1, a2, a3)
396: int a1, a2, a3;
397: {
398: LINE l;
399: register int a, n, x;
400:
401: if (a1>a2 || a1<1 || a2>doladd || a3<0 || a3>doladd) {
402: derror("Address out of range");
403: return (0);
404: }
405: if (a3>=a1-1 && a3<=a2) {
406: dotadd = a2;
407: return (1);
408: }
409: if (a3 < a1) {
410: for (a=a1, x=a3+1; a<=a2; a++, x++) {
411: l = line[a];
412: for (n=a; n>x; --n)
413: line[n] = line[n-1];
414: line[x] = l;
415: }
416: dotadd = a3 + a2+1 - a1;
417: } else {
418: for (a=a2, x=a3; a>=a1; --a, --x) {
419: l = line[a];
420: for (n=a; n<x; n++)
421: line[n] = line[n+1];
422: line[x] = l;
423: }
424: dotadd = a3;
425: }
426: saved = 0;
427: return (1);
428: }
429:
430: /*
431: * Given a string describing a set of options, set them.
432: */
433: setoptf(sp)
434: register char *sp;
435: {
436: register int t;
437:
438: t = 1;
439: while (*sp != '\0') {
440: switch (*sp++) {
441: case '+':
442: t = 1;
443: continue;
444: case '-':
445: t = 0;
446: continue;
447: case 'c':
448: cflag = t;
449: continue;
450: case 'm':
451: mflag = t;
452: continue;
453: case 'o':
454: oflag = t;
455: continue;
456: case 'p':
457: pflag = t;
458: continue;
459: case 's':
460: sflag = t;
461: continue;
462: case 'v':
463: vflag = t;
464: continue;
465: default:
466: derror("Bad option");
467: return;
468: }
469: }
470: }
471:
472: /*
473: * Display options.
474: */
475: disoptf()
476: {
477: if (cflag)
478: printc(stdout, 'c');
479: if (mflag)
480: printc(stdout, 'm');
481: if (oflag)
482: printc(stdout, 'o');
483: if (pflag)
484: printc(stdout, 'p');
485: if (sflag)
486: printc(stdout, 's');
487: if (vflag)
488: printc(stdout, 'v');
489: if (keyp != NULL)
490: printc(stdout, 'x');
491: printc(stdout, '\n');
492: }
493:
494: /*
495: * Print the given line range.
496: */
497: print(a1, a2)
498: {
499: register int a;
500: register char *p;
501:
502: if (a1>a2 || a1<1 || a2>doladd) {
503: derror("Address out of range");
504: return (0);
505: }
506: for (a=a1; a<=a2; a++) {
507: if (intflag)
508: return (1);
509: if (getline(a, linebuf) == 0)
510: break;
511: p = linebuf;
512: while (*p)
513: printc(stdout, *p++);
514: printc(stdout, '\n');
515: dotadd = a;
516: }
517: return (1);
518: }
519:
520: /*
521: * Make a copy of the text between lines `a1' and `a2'
522: * and place them after `a3'.
523: */
524: copy(a1, a2, a3)
525: {
526: register int i, j, n;
527:
528: if (a1>a2 || a1<1 || a2>doladd || a3<0 || a3>doladd) {
529: derror("Address out of range");
530: return (0);
531: }
532: n = (a2+1) - a1;
533: if (doladd+n+2 > lnsize) {
534: derror("Line table overflow");
535: return (0);
536: }
537: for (i=doladd; i>a3; --i)
538: line[i+n] = line[i];
539: for (i=0; i<n; i++) {
540: if ((j=i+a1) > a3)
541: j += n;
542: if ((j=getline(j, linebuf)) == 0)
543: goto err;
544: line[a3+1+i] = linead();
545: if (putline(linebuf, j) == 0)
546: goto err;
547: }
548: dotadd = a3+n;
549: doladd += n;
550: saved = 0;
551: return (1);
552:
553: err:
554: for (i=a3+1; i<=doladd; i++)
555: line[i] = line[i+n];
556: return (0);
557: }
558:
559: /*
560: * Write the given line range onto the file whose name is
561: * stored in `file'. `perm' is the permission string we
562: * want the file opened with.
563: */
564: wfile(a1, a2, name, perm, sflag)
565: char *name, *perm;
566: {
567: register int a;
568: register char *cp;
569:
570: if (doladd!=0 || addspec!=0) {
571: if (a1>a2 || a1<1 || a2>doladd) {
572: derror("Address out of range");
573: return (0);
574: }
575: }
576: if ((fp=xfopen(name, perm)) == NULL) {
577: derror("Cannot open file");
578: return (0);
579: }
580: cct = 0;
581: lct = 0;
582: for (a=a1; a<=a2; a++) {
583: if (getline(a, linebuf) == 0)
584: break;
585: cp = linebuf;
586: while (*cp) {
587: printc(fp, *cp++);
588: cct++;
589: }
590: printc(fp, '\n');
591: if (ferror(fp))
592: break;
593: cct++;
594: lct++;
595: }
596: if (sflag==0 && cflag!=0) {
597: printl(stdout, !oflag ? cct : lct);
598: printc(stdout, '\n');
599: }
600: if ((a=ferror(fp)) == 0)
601: saved = 1;
602: else {
603: if (sflag == 0)
604: derror("Write error");
605: }
606: fclose(fp);
607: #if COHERENT
608: sync();
609: #endif
610: return (!a);
611: }
612:
613: /*
614: * Open a file. If we are in encryption mode, the open unit is really a
615: * file descriptor piped to the crypt command.
616: */
617: FILE *
618: xfopen(fn, mode)
619: char *fn;
620: char *mode;
621: {
622: #if COHERENT
623: register FILE *fp;
624: register int f;
625: register int u;
626: register int a;
627: register int b;
628: int pv[2];
629:
630: if (keyp == NULL)
631: fp = fopen(fn, mode);
632: else {
633: switch (mode[0]) {
634: case 'a':
635: return (NULL);
636: case 'r':
637: a = 0;
638: b = 1;
639: break;
640: case 'w':
641: a = 1;
642: b = 0;
643: break;
644: }
645: if (pipe(pv) < 0)
646: return (NULL);
647: if ((f=fork()) < 0) {
648: close(pv[0]);
649: close(pv[1]);
650: return (NULL);
651: }
652: if (f == 0) {
653: if ((u=(a==0)?open(fn, 0):creat(fn, 0644)) < 0)
654: exit(1);
655: dup2(u, a);
656: dup2(pv[b], b);
657: close(u);
658: close(pv[0]);
659: close(pv[1]);
660: execl("/bin/crypt", "crypt", keyp, NULL);
661: exit(1);
662: }
663: close(pv[b]);
664: fp = fdopen(pv[a], mode);
665: }
666: return (fp);
667: #else
668: return(fopen(fn, mode));
669: #endif
670: }
671:
672: /*
673: * Read a key from the standard input.
674: */
675: setkey()
676: {
677: #if COHERENT
678: register int n;
679:
680: keyp = getpass("key? ");
681: if ((n=strlen(keyp)) > CKSIZE) {
682: derror("Key too long");
683: keyp = NULL;
684: return (0);
685: }
686: if (n == 0)
687: keyp = NULL;
688: return (1);
689: #else
690: derror("Cannot set key");
691: return (0);
692: #endif
693: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.