|
|
1.1 root 1: /*
2: * An editor.
3: * Main, command parser and general routines.
4: */
5: #include <stdio.h>
6: #if COHERENT || GEMDOS
7: #include <signal.h>
8: #endif
9: #include <ctype.h>
10: #include "ed.h"
11:
12: main(argc, argv)
13: char *argv[];
14: {
15: #if COHERENT
16: extern int sighang();
17: #endif
18: #if COHERENT || GEMDOS
19: extern int sigintr();
20: #endif
21: #if COHERENT || MSDOS || GEMDOS
22: register char *cp;
23: #endif
24: initialise();
25: #if COHERENT || MSDOS || GEMDOS
26: if ((cp=getenv("ED")) != NULL)
27: setoptf(cp);
28: #endif
29: #if COHERENT
30: signal(SIGHUP, sighang);
31: #endif
32: #if COHERENT || GEMDOS
33: signal(SIGINT, sigintr);
34: signal(SIGQUIT, sigintr);
35: #endif
36: setup(argc, argv);
37: for (;;) {
38: if (intflag) {
39: /*
40: finit(stdout);
41: clearerr(stdin);
42: clearerr(stdout);
43: clearerr(stderr);
44: */
45: savechr = '\0';
46: intflag = 0;
47: derror("Interrupt");
48: }
49: command();
50: }
51: }
52:
53: /*
54: * Initialisation.
55: */
56: initialise()
57: {
58: register int i;
59: register char *bp;
60: #if COHERENT || MSDOS || GEMDOS
61: extern char *tempnam();
62: #endif
63:
64: if ((bp=malloc(BUFSIZ)) != NULL)
65: setbuf(stdout, bp);
66: #if RSX
67: if ((tmp=fopen("edtmp", "r+")) == NULL) {
68: #endif
69: #if COHERENT || MSDOS || GEMDOS
70: tfn = tempnam(NULL, "ed");
71: if ((tmp=fopen(tfn, "w")) == NULL) {
72: terror("Cannot create temp file");
73: exit(1);
74: }
75: if ((tmp=freopen(tfn, "r+", tmp)) == NULL) {
76: #endif
77: terror("Cannot open temp file");
78: unlink(tfn);
79: exit(1);
80: }
81: #if COHERENT
82: chmod(tfn, 0);
83: #endif
84:
85: #if RSX
86: fmkdl(tmp);
87: qio(001400, stdin->v_lun, 1, NULL, NULL);
88: wtse(1);
89: #endif
90: mflag = 0;
91: oflag = 0;
92: pflag = 0;
93: sflag = 0;
94: tflag = 0;
95: vflag = 0;
96: cflag = 1;
97: intflag = 0;
98: tmpseek = CLSIZE;
99: rcurbno = -1;
100: wcurbno = -1;
101: lnsize = LNSIZE;
102: if ((line=(LINE *)calloc(lnsize, sizeof(LINE))) == NULL) {
103: prints(stderr, "Cannot allocate line number table\n");
104: exit(1);
105: }
106: savechr = '\0';
107: lastchr = '\n';
108: gcp = NULL;
109: codebuf[0] = CSNUL;
110: file[0] = '\0';
111: for (i=0; i<MKSIZE; i++)
112: marklin[i] = 0;
113: dotadd = 0;
114: doladd = 0;
115: saved = 1;
116: subseek = 0;
117: keyp = NULL;
118: }
119:
120: /*
121: * Process command line arguments.
122: */
123: setup(argc, argv)
124: char *argv[];
125: {
126: register char *cp;
127: register int i;
128: register int f;
129:
130: f = 0;
131: for (i=1; i<argc; i++) {
132: cp = argv[i];
133: switch (*cp++) {
134: case '-':
135: switch (*cp++) {
136: case '\0':
137: cflag = 0;
138: continue;
139: #if COHERENT
140: case 't':
141: tflag = 1;
142: signal(SIGINT, SIG_IGN);
143: signal(SIGQUIT, SIG_IGN);
144: continue;
145: #endif
146: case 'u':
147: setbuf(stdout, NULL);
148: continue;
149: case 'x':
150: setkey();
151: continue;
152: default:
153: usage();
154: }
155: case '+':
156: setoptf(argv[i]);
157: continue;
158: default:
159: if (f++ != 0)
160: usage();
161: if (strlen(argv[i]) > FNSIZE)
162: derror("File name too long");
163: else {
164: strcpy(file, argv[i]);
165: edit();
166: }
167: }
168: }
169: }
170:
171: /*
172: * Print out a usage message.
173: */
174: usage()
175: {
176: prints(stderr, "Usage: ed [-[x]] [+cmopsv] [file]\n");
177: exit(1);
178: }
179:
180: /*
181: * Set a flag indicating that interrupt has been hit.
182: * Used for SIGQUIT and SIGINT.
183: */
184: #if COHERENT || GEMDOS
185: sigintr(s)
186: {
187: intflag++;
188: signal(s, sigintr);
189: }
190: #endif
191:
192: /*
193: * If we get a hangup signal, write the file onto the file
194: * `ed.hup' and leave.
195: */
196: #if COHERENT
197: sighang()
198: {
199: if (doladd != 0)
200: wfile(1, doladd, "ed.hup", "w", 1);
201: leave();
202: }
203: #endif
204:
205: /*
206: * Leave the editor.
207: */
208: leave()
209: {
210: fclose(tmp);
211: unlink(tfn);
212: exit(0);
213: }
214:
215: /*
216: * Process a command.
217: */
218: command()
219: {
220: extern int sigintr();
221: int c1, n, a3;
222: char name[FNSIZE+1];
223: register int a1, a2, c;
224:
225: for (;;) {
226: addspec = 0;
227: a1 = a2 = getaddr();
228: if (intflag)
229: return (0);
230: if (adderrr)
231: goto err;
232: c = getx();
233: if (addspec != 0) {
234: while (c==',' || c==';') {
235: a1 = a2;
236: if (c == ';')
237: dotadd = a1;
238: a2 = getaddr();
239: if (adderrr)
240: goto err;
241: if (addspec == 0) {
242: derror("Missing address");
243: goto err;
244: }
245: c = getx();
246: }
247: }
248: if (c == '*') {
249: if (addspec++ == 0) {
250: a1 = 1;
251: addspec++;
252: }
253: a2 = doladd;
254: c = getx();
255: }
256: switch (c) {
257: case EOF:
258: if (intflag == 0) {
259: if (saved != 0)
260: leave();
261: saved = 1;
262: derror("File not saved");
263: }
264: return;
265: case '\n':
266: if (addques) {
267: if (errstr) {
268: prints(stdout, errstr);
269: printc(stdout, '\n');
270: }
271: return (0);
272: }
273: if (addpage) {
274: a1 = a2;
275: a2 = a1 + PGSIZE;
276: if (a2 > doladd)
277: a2 = doladd;
278: if (print(a1, a2) == 0)
279: return (0);
280: return (1);
281: }
282: if (addspec == 0)
283: a2 = dotadd+1;
284: if (print(a2, a2) == 0)
285: return (0);
286: return (1);
287: case '!':
288: if (rest() == 0)
289: goto err;
290: n = system(tempbuf);
291: if (n < 0) {
292: derror("Call failed");
293: return (0);
294: } else {
295: prints(stdout, "!\n");
296: return (1);
297: }
298: case '=':
299: if (verify(0) == 0)
300: goto err;
301: if (addspec == 0)
302: a2 = doladd;
303: printd(stdout, a2);
304: printc(stdout, '\n');
305: break;
306: case 'a':
307: if (verify(1) == 0)
308: goto err;
309: getx();
310: if (append(a2, readtty) == 0)
311: return (0);
312: ungetx('\n');
313: break;
314: case 'c':
315: if (verify(1) == 0)
316: goto err;
317: getx();
318: if (delete(a1, a2) == 0)
319: return (0);
320: if (append(a1-1, readtty) == 0)
321: return (0);
322: ungetx('\n');
323: break;
324: case 'd':
325: if (verify(0) == 0)
326: goto err;
327: if (delete(a1, a2) == 0)
328: goto err;
329: break;
330: case 'e':
331: n = saved;
332: if (getfile(n?file:name) == 0)
333: return (0);
334: if (n == 0) {
335: saved = 1;
336: derror("File not saved");
337: return (0);
338: }
339: return (edit());
340: case 'E':
341: if (getfile(file) == 0)
342: return (0);
343: return (edit());
344: case 'f':
345: if ((c=getx()) == ' ') {
346: ungetx(' ');
347: getfile(file);
348: c = '\n';
349: }
350: if (c != '\n') {
351: derror("Bad command");
352: goto err;
353: }
354: if (file[0] != '\0') {
355: prints(stdout, file);
356: printc(stdout, '\n');
357: }
358: return (1);
359: case 'g':
360: if (addspec == 0) {
361: a1 = 1;
362: a2 = doladd;
363: }
364: if (global(a1, a2, 0) == 0)
365: goto err;
366: if (verify(1) == 0)
367: goto err;
368: break;
369: case 'i':
370: if (verify(1) == 0)
371: goto err;
372: getx();
373: if (doladd==0 && a2==0)
374: a2 = 1;
375: if (append(a2-1, readtty) == 0)
376: return (0);
377: ungetx('\n');
378: break;
379: case 'j':
380: if (addspec < 2)
381: a2 = a1+1;
382: if (verify(0) == 0)
383: goto err;
384: if (join(a1, a2) == 0)
385: goto err;
386: break;
387: case 'k':
388: if ((c=getx()) == '\n') {
389: derror("No mark name specified");
390: return (0);
391: }
392: if (verify(0) == 0)
393: goto err;
394: if (a2<1 || a2>doladd) {
395: derror("Illegal address range");
396: goto err;
397: }
398: if (!isascii(c) || !islower(c)) {
399: derror("Bad mark name");
400: goto err;
401: }
402: marklin[c-'a'] = line[a2]|1;
403: break;
404: case 'l':
405: if (verify(0) == 0)
406: goto err;
407: if (list(a1, a2) == 0)
408: goto err;
409: break;
410: case 'm':
411: a3 = getaddr();
412: if (adderrr)
413: goto err;
414: if (verify(0) == 0)
415: goto err;
416: if (move(a1, a2, a3) == 0)
417: goto err;
418: break;
419: case 'o':
420: if (rest() == 0)
421: goto err;
422: if (tempbuf[0] == '\0')
423: disoptf();
424: else
425: setoptf(tempbuf);
426: return (1);
427: case 'p':
428: case 'P':
429: if (verify(0) == 0)
430: goto err;
431: if (print(a1, a2) == 0)
432: goto err;
433: break;
434: case 'q':
435: if (verify(1) == 0)
436: goto err;
437: if (addspec != 0) {
438: derror("Cannot specify address");
439: goto err;
440: }
441: if (saved == 0) {
442: saved = 1;
443: derror("File not saved");
444: goto err;
445: }
446: leave();
447: case 'Q':
448: if (verify(1) == 0)
449: goto err;
450: leave();
451: case 'r':
452: if (getfile(name) == 0)
453: return (0);
454: if (addspec == 0)
455: a2 = doladd;
456: if ((fp=xfopen(name, "r")) == NULL) {
457: derror("Cannot open file");
458: return (0);
459: }
460: n = 1;
461: if (append(a2, readfil) == 0)
462: n = 0;
463: else if (ferror(fp)) {
464: derror("Read error");
465: n = 0;
466: }
467: fclose(fp);
468: if (cflag != 0) {
469: printl(stdout, !oflag ? cct : lct);
470: printc(stdout, '\n');
471: }
472: return (n);
473: case 's':
474: if (subs1(a1, a2) == 0)
475: goto err;
476: if (verify(0) == 0)
477: goto err;
478: if (subs2(a1, a2) == 0)
479: goto err;
480: break;
481: case 't':
482: a3 = getaddr();
483: if (adderrr)
484: goto err;
485: if (verify(0) == 0)
486: goto err;
487: if (copy(a1, a2, a3) == 0)
488: goto err;
489: break;
490: case 'u':
491: if (verify(0) == 0)
492: goto err;
493: if (a2<1 || a2>doladd) {
494: derror("Illegal address range");
495: goto err;
496: }
497: if ((line[a2]|1) != subseek) {
498: derror("Cannot undo substitute");
499: goto err;
500: }
501: line[a2] = suborig;
502: subseek = 0;
503: break;
504: case 'v':
505: if (addspec == 0) {
506: a1 = 1;
507: a2 = doladd;
508: }
509: if (global(a1, a2, 1) == 0)
510: goto err;
511: if (verify(1) == 0)
512: goto err;
513: break;
514: case 'w':
515: case 'W':
516: if ((c1=getx()) != 'q')
517: ungetx(c1);
518: if (getfile(name) == 0)
519: return (0);
520: if (addspec == 0) {
521: a1 = 1;
522: a2 = doladd;
523: }
524: if (c=='W' && keyp!=NULL) {
525: derror("Cannot append in encryption mode");
526: goto err;
527: }
528: if (wfile(a1, a2, name, c=='w'?"w":"a", 0) && c1=='q')
529: leave();
530: return (1);
531: case 'x':
532: if (verify(1) == 0)
533: goto err;
534: if (setkey() == 0)
535: goto err;
536: break;
537: default:
538: derror("Bad command");
539: err:
540: while ((c=getx())!=EOF && c!='\n')
541: ;
542: return (0);
543: }
544: if (intflag)
545: return (0);
546: switch (vcom) {
547: case 'l':
548: list(dotadd, dotadd);
549: break;
550: case 'p':
551: print(dotadd, dotadd);
552: break;
553: }
554: if ((c=getx()) == '\n')
555: return (1);
556: if (mflag == 0) {
557: derror("Internal error");
558: goto err;
559: }
560: ungetx(c);
561: }
562: }
563:
564: /*
565: * Get an address.
566: */
567: getaddr()
568: {
569: LINE seek;
570: int absolute, abs, sign;
571: register int a, c, n;
572:
573: adderrr = 0;
574: addpage = 0;
575: addques = 0;
576: absolute = 0;
577: abs = 1;
578: sign = 0;
579: a = dotadd;
580: for (;;) {
581: switch (c=getx()) {
582: case '.':
583: n = dotadd;
584: abs = 1;
585: break;
586: case '$':
587: n = doladd;
588: abs = 1;
589: break;
590: case '&':
591: if (sign == 0) {
592: addpage++;
593: continue;
594: }
595: n = PGSIZE;
596: abs = 0;
597: break;
598: case '\'':
599: if (!isascii(c=getx()) || !islower(c)) {
600: derror("Bad mark name");
601: adderrr++;
602: return (0);
603: }
604: seek = marklin[c-'a'];
605: for (n=1; n<=doladd; n++) {
606: if ((line[n]|1) == seek) {
607: abs = 0;
608: goto number;
609: }
610: }
611: derror("Mark value not initialised");
612: adderrr++;
613: return (0);
614: case '+':
615: sign++;
616: continue;
617: case '^':
618: case '-':
619: --sign;
620: continue;
621: case '?':
622: c = getx();
623: ungetx(c);
624: if (c == '\n') {
625: addques++;
626: return (0);
627: }
628: c = '?';
629: case '/':
630: if (compile(c) == 0) {
631: adderrr++;
632: return (0);
633: }
634: if (a<1 || a>doladd) {
635: derror("Bad initial address");
636: adderrr++;
637: return (0);
638: }
639: n = a;
640: abs = 1;
641: do {
642: if (intflag)
643: return;
644: if (c == '?') {
645: if (--n < 1)
646: n = doladd;
647: } else {
648: if (++n > doladd)
649: n = 1;
650: }
651: if (n == a) {
652: if (execute(n))
653: break;
654: derror("Search failed");
655: adderrr++;
656: return (0);
657: }
658: } while (execute(n) == 0);
659: break;
660: default:
661: if (isascii(c) && isdigit(c)) {
662: n = 0;
663: do
664: n = n*10 + c-'0';
665: while (isascii(c=getx()) && isdigit(c));
666: ungetx(c);
667: abs = 0;
668: break;
669: }
670: ungetx(c);
671: if (sign) {
672: a += sign;
673: addspec++;
674: }
675: return (a);
676: }
677: number:
678: if (sign == 0) {
679: a = n;
680: absolute = abs;
681: } else {
682: if ((absolute+=abs) > 1) {
683: derror("Relocation address error");
684: adderrr++;
685: return (0);
686: }
687: a += sign>0 ? n : -n;
688: sign = 0;
689: }
690: addspec++;
691: }
692: }
693:
694: /*
695: * Get a character.
696: */
697: getx()
698: {
699: register int c;
700:
701: if (intflag != 0)
702: return (EOF);
703: if (savechr != '\0') {
704: c = savechr;
705: savechr = '\0';
706: return (c);
707: }
708: if (gcp == NULL) {
709: if (lastchr=='\n' && appflag==0) {
710: if (pflag != 0) {
711: printc(stderr, '*');
712: fflush(stderr);
713: }
714: if (tflag != 0) {
715: printc(stdout, '\000');
716: printc(stdout, '\027');
717: fflush(stdout);
718: }
719: }
720: return (lastchr=getchar());
721: }
722: if ((c=*gcp++) != '\0')
723: return (c);
724: --gcp;
725: return (EOF);
726: }
727:
728: /*
729: * Put back a character.
730: */
731: ungetx(c)
732: {
733: savechr = c;
734: }
735:
736: /*
737: * Given a line number, `a', get a line from the temp file
738: * and store in the buffer `buffer'. The number of characters read
739: * including the null is returned.
740: */
741: getline(a, buffer)
742: char *buffer;
743: {
744: LINE l;
745: int bno, off;
746: register char *bp, *dp, *cp;
747:
748: l = line[a];
749: bno = blockn(l);
750: off = offset(l);
751: bp = buffer;
752: for (;;) {
753: if ((cp=getdisk(bno++)) == NULL)
754: return (0);
755: dp = &cp[off];
756: cp += DBSIZE;
757: while (dp < cp) {
758: if ((*bp++=*dp++) == '\0')
759: return (bp-buffer);
760: }
761: off = 0;
762: }
763: }
764:
765: /*
766: * Given a buffer, `bp', containing a line and a number of
767: * characters, `n', in the buffer, add the line onto the end of
768: * the temp file.
769: */
770: putline(bp, n)
771: register char *bp;
772: register int n;
773: {
774: int bno, off, inc;
775: register char *dp;
776:
777: inc = (n+CLSIZE-1) & ~(CLSIZE-1);
778: if (tmpseek+inc > (ULARGE/2)*CLSIZE) {
779: derror("Temp file overflow");
780: return (0);
781: }
782: bno = tmpseek / DBSIZE;
783: off = tmpseek % DBSIZE;
784: for (;;) {
785: if (wcurbno>=0 && bno!=wcurbno)
786: if (putdisk() == 0)
787: return (0);
788: wcurbno = bno;
789: dp = &wdbcbuf[off];
790: while (dp < &wdbcbuf[DBSIZE]) {
791: *dp++ = *bp++;
792: if (--n == 0) {
793: tmpseek += inc;
794: return (1);
795: }
796: }
797: bno++;
798: off = 0;
799: }
800: }
801:
802: /*
803: * Given a block number, bring it into a disk buffer. A pointer
804: * to the buffer is returned.
805: */
806: char *
807: getdisk(bno)
808: {
809: if (bno == wcurbno)
810: return (wdbcbuf);
811: if (bno == rcurbno)
812: return (rdbcbuf);
813: #if RSX
814: /* IO.RVB = 0010400 */
815: qio(010400, flun(tmp), 1, tmp->v_iosb, NULL,
816: rdbcbuf, sizeof(rdbcbuf), 0, 0, bno+1, 0);
817: wtse(1);
818: if ((tmp->v_iosb[0]&0377) != 1)
819: return (NULL);
820: #else
821: #if COHERENT || MSDOS
822: lseek(fileno(tmp), (long) bno * DBSIZE, 0);
823: #endif
824: #if GEMDOS
825: ffseek(tmp, (long) bno * DBSIZE, 0);
826: #endif
827: if (read(fileno(tmp), rdbcbuf, sizeof(rdbcbuf)) != sizeof(rdbcbuf)) {
828: terror("Read error");
829: return (NULL);
830: }
831: #endif
832: rcurbno = bno;
833: return (rdbcbuf);
834: }
835:
836: /*
837: * Write out the current disk buffer.
838: */
839: putdisk()
840: {
841: #if RSX
842: if (wcurbno >= tmp->v_hibk)
843: if (grow(1) == 0)
844: return (0);
845: /* IO.WVB = 0011000 */
846: qio(011000, flun(tmp), 1, tmp->v_iosb, NULL,
847: wdbcbuf, sizeof(wdbcbuf), 0, 0, wcurbno+1, 0);
848: wtse(1);
849: if ((tmp->v_iosb[0]&0377) != 1)
850: return (0);
851: #else
852: #if COHERENT || MSDOS
853: lseek(fileno(tmp), (long) wcurbno * DBSIZE, 0);
854: #endif
855: #if GEMDOS
856: ffseek(tmp, (long) wcurbno * DBSIZE, 0);
857: #endif
858: if (write(fileno(tmp), wdbcbuf, sizeof(wdbcbuf)) != sizeof(wdbcbuf)) {
859: terror("Write error");
860: return (0);
861: }
862: #endif
863: return (1);
864: }
865: #if RSX
866:
867: /*
868: * Grow the temp file.
869: */
870: grow(n)
871: {
872: /* IO.EXT = 0011400 */
873: qio(011400, flun(tmp), 1, tmp->v_iosb, NULL,
874: 0, 0, 0100000, n, 0, 0);
875: wtse(1);
876: if ((tmp->v_iosb[0]&0377) != 1)
877: return (0);
878: tmp->v_hibk += n;
879: return (1);
880: }
881: #endif
882:
883: /*
884: * A diagnostic error.
885: */
886: derror(str)
887: char *str;
888: {
889: errstr = str;
890: if (tflag != 0) {
891: printc(stdout, '\000');
892: printc(stdout, '\025');
893: fflush(stdout);
894: } else {
895: printc(stderr, '?');
896: if (vflag != 0)
897: prints(stderr, str);
898: printc(stderr, '\n');
899: }
900: }
901:
902: /*
903: * A temp file error.
904: */
905: terror(str)
906: char *str;
907: {
908: errstr = str;
909: if (tflag != 0) {
910: printc(stdout, '\000');
911: printc(stdout, '\025');
912: fflush(stdout);
913: } else {
914: printc(stderr, '?');
915: prints(stderr, str);
916: printc(stderr, '\n');
917: }
918: }
919:
920: /*
921: * Print out a decimal number.
922: */
923: printd(fp, n)
924: FILE *fp;
925: register int n;
926: {
927: register int c;
928:
929: if (n < 0) {
930: printc(fp, '-');
931: if ((n=-n) < 0)
932: n = 0;
933: }
934: c = n%10 + '0';
935: n /= 10;
936: if (n != 0)
937: printd(fp, n);
938: printc(fp, c);
939: }
940:
941: /*
942: * Print out a long integer.
943: */
944: printl(fp, n)
945: FILE *fp;
946: register long n;
947: {
948: register int c;
949:
950: if (n < 0) {
951: printc(fp, '-');
952: if ((n=-n) < 0)
953: n = 0;
954: }
955: c = n%10 + '0';
956: n /= 10;
957: if (n != 0)
958: printl(fp, n);
959: printc(fp, c);
960: }
961:
962: /*
963: * Print out an octal number.
964: */
965: printo(fp, n)
966: FILE *fp;
967: {
968: printc(fp, '0'+((n>>6)&03));
969: printc(fp, '0'+((n>>3)&07));
970: printc(fp, '0'+(n&07));
971: }
972:
973: /*
974: * Print out a string.
975: */
976: prints(fp, cp)
977: register FILE *fp;
978: register char *cp;
979: {
980: while (*cp)
981: printc(fp, *cp++);
982: }
983:
984: /*
985: * Print out a character.
986: */
987: printc(fp, c)
988: register FILE *fp;
989: {
990: putc(c, fp);
991: if (tflag==0 && c=='\n' && fp==stdout)
992: fflush(fp);
993: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.