file reorg
[unix-history] / usr / src / bin / ed / ed.c
CommitLineData
205a2d85 1#ifndef lint
54e0d068 2static char sccsid[] = "@(#)ed.c 4.9 (Berkeley) %G%";
205a2d85 3#endif
31e58db8
KM
4
5/*
6 * Editor
7 */
8
9#include <signal.h>
10#include <sgtty.h>
2dd1db50 11#undef CEOF
31e58db8 12#include <setjmp.h>
dc891cfc
KB
13#include "pathnames.h"
14
31e58db8
KM
15#define NULL 0
16#define FNSIZE 64
17#define LBSIZE 512
18#define ESIZE 128
19#define GBSIZE 256
20#define NBRA 5
21#define EOF -1
31e58db8
KM
22
23#define CBRA 1
24#define CCHR 2
25#define CDOT 4
26#define CCL 6
27#define NCCL 8
28#define CDOL 10
29#define CEOF 11
30#define CKET 12
31#define CBACK 14
32
33#define STAR 01
34
35char Q[] = "";
36char T[] = "TMP";
37#define READ 0
38#define WRITE 1
39
40int peekc;
41int lastc;
42char savedfile[FNSIZE];
43char file[FNSIZE];
44char linebuf[LBSIZE];
45char rhsbuf[LBSIZE/2];
46char expbuf[ESIZE+4];
47int circfl;
48int *zero;
49int *dot;
50int *dol;
51int *addr1;
52int *addr2;
53char genbuf[LBSIZE];
54long count;
55char *nextip;
56char *linebp;
57int ninbuf;
58int io;
59int pflag;
60long lseek();
61int (*oldhup)();
62int (*oldquit)();
63int vflag = 1;
62793f1c 64
62793f1c 65
31e58db8
KM
66int listf;
67int col;
68char *globp;
69int tfile = -1;
70int tline;
54e0d068 71char tfname[sizeof(_PATH_TMP) + 20];
31e58db8
KM
72char *loc1;
73char *loc2;
74char *locs;
75char ibuff[512];
76int iblock = -1;
77char obuff[512];
78int oblock = -1;
79int ichanged;
80int nleft;
81char WRERR[] = "WRITE ERROR";
82int names[26];
83int anymarks;
84char *braslist[NBRA];
85char *braelist[NBRA];
86int nbra;
87int subnewa;
88int subolda;
89int fchange;
90int wrapp;
91unsigned nlall = 128;
92
93int *address();
94char *getline();
95char *getblock();
96char *place();
97char *mktemp();
98char *malloc();
99char *realloc();
100jmp_buf savej;
101
102main(argc, argv)
103char **argv;
104{
105 register char *p1, *p2;
106 extern int onintr(), quit(), onhup();
107 int (*oldintr)();
108
109 oldquit = signal(SIGQUIT, SIG_IGN);
110 oldhup = signal(SIGHUP, SIG_IGN);
111 oldintr = signal(SIGINT, SIG_IGN);
112 if ((int)signal(SIGTERM, SIG_IGN) == 0)
113 signal(SIGTERM, quit);
114 argv++;
115 while (argc > 1 && **argv=='-') {
116 switch((*argv)[1]) {
117
118 case '\0':
119 vflag = 0;
120 break;
121
122 case 'q':
123 signal(SIGQUIT, SIG_DFL);
124 vflag = 1;
125 break;
126
31e58db8
KM
127 }
128 argv++;
129 argc--;
130 }
31e58db8
KM
131
132 if (argc>1) {
133 p1 = *argv;
134 p2 = savedfile;
135 while (*p2++ = *p1++)
136 ;
137 globp = "r";
138 }
139 zero = (int *)malloc(nlall*sizeof(int));
54e0d068
KB
140 (void)strcpy(tfname, _PATH_TMP);
141 (void)strcat(tfname, "_edXXXXXX");
142 (void)mktemp(tfname);
31e58db8
KM
143 init();
144 if (((int)oldintr&01) == 0)
145 signal(SIGINT, onintr);
146 if (((int)oldhup&01) == 0)
147 signal(SIGHUP, onhup);
148 setjmp(savej);
149 commands();
150 quit();
151}
152
153commands()
154{
155 int getfile(), gettty();
156 register *a1, c;
157
158 for (;;) {
159 if (pflag) {
160 pflag = 0;
161 addr1 = addr2 = dot;
162 goto print;
163 }
164 addr1 = 0;
165 addr2 = 0;
166 do {
167 addr1 = addr2;
168 if ((a1 = address())==0) {
169 c = getchr();
170 break;
171 }
172 addr2 = a1;
173 if ((c=getchr()) == ';') {
174 c = ',';
175 dot = a1;
176 }
177 } while (c==',');
178 if (addr1==0)
179 addr1 = addr2;
180 switch(c) {
181
182 case 'a':
183 setdot();
184 newline();
185 append(gettty, addr2);
186 continue;
187
188 case 'c':
189 delete();
190 append(gettty, addr1-1);
191 continue;
192
193 case 'd':
194 delete();
195 continue;
196
197 case 'E':
198 fchange = 0;
199 c = 'e';
200 case 'e':
201 setnoaddr();
202 if (vflag && fchange) {
203 fchange = 0;
204 error(Q);
205 }
206 filename(c);
207 init();
208 addr2 = zero;
209 goto caseread;
210
211 case 'f':
212 setnoaddr();
213 filename(c);
214 puts(savedfile);
215 continue;
216
217 case 'g':
218 global(1);
219 continue;
220
221 case 'i':
222 setdot();
223 nonzero();
224 newline();
225 append(gettty, addr2-1);
226 continue;
227
228
229 case 'j':
230 if (addr2==0) {
231 addr1 = dot;
232 addr2 = dot+1;
233 }
234 setdot();
235 newline();
236 nonzero();
237 join();
238 continue;
239
240 case 'k':
241 if ((c = getchr()) < 'a' || c > 'z')
242 error(Q);
243 newline();
244 setdot();
245 nonzero();
246 names[c-'a'] = *addr2 & ~01;
247 anymarks |= 01;
248 continue;
249
250 case 'm':
251 move(0);
252 continue;
253
254 case '\n':
255 if (addr2==0)
256 addr2 = dot+1;
257 addr1 = addr2;
258 goto print;
259
260 case 'l':
261 listf++;
262 case 'p':
263 case 'P':
264 newline();
265 print:
266 setdot();
267 nonzero();
268 a1 = addr1;
269 do {
270 puts(getline(*a1++));
271 } while (a1 <= addr2);
272 dot = addr2;
273 listf = 0;
274 continue;
275
276 case 'Q':
277 fchange = 0;
278 case 'q':
279 setnoaddr();
280 newline();
281 quit();
282
283 case 'r':
284 filename(c);
285 caseread:
286 if ((io = open(file, 0)) < 0) {
287 lastc = '\n';
288 error(file);
289 }
290 setall();
291 ninbuf = 0;
292 c = zero != dol;
293 append(getfile, addr2);
294 exfile();
295 fchange = c;
296 continue;
297
298 case 's':
299 setdot();
300 nonzero();
301 substitute(globp!=0);
302 continue;
303
304 case 't':
305 move(1);
306 continue;
307
308 case 'u':
309 setdot();
310 nonzero();
311 newline();
312 if ((*addr2&~01) != subnewa)
313 error(Q);
314 *addr2 = subolda;
315 dot = addr2;
316 continue;
317
318 case 'v':
319 global(0);
320 continue;
321
322 case 'W':
323 wrapp++;
324 case 'w':
325 setall();
326 nonzero();
327 filename(c);
328 if(!wrapp ||
329 ((io = open(file,1)) == -1) ||
330 ((lseek(io, 0L, 2)) == -1))
331 if ((io = creat(file, 0666)) < 0)
332 error(file);
333 wrapp = 0;
334 putfile();
335 exfile();
336 if (addr1==zero+1 && addr2==dol)
337 fchange = 0;
338 continue;
339
31e58db8
KM
340
341
342 case '=':
343 setall();
344 newline();
345 count = (addr2-zero)&077777;
346 putd();
347 putchr('\n');
348 continue;
349
350 case '!':
351 callunix();
352 continue;
353
354 case EOF:
355 return;
356
357 }
358 error(Q);
359 }
360}
361
362int *
363address()
364{
365 register *a1, minus, c;
366 int n, relerr;
367
368 minus = 0;
369 a1 = 0;
370 for (;;) {
371 c = getchr();
372 if ('0'<=c && c<='9') {
373 n = 0;
374 do {
375 n *= 10;
376 n += c - '0';
377 } while ((c = getchr())>='0' && c<='9');
378 peekc = c;
379 if (a1==0)
380 a1 = zero;
381 if (minus<0)
382 n = -n;
383 a1 += n;
384 minus = 0;
385 continue;
386 }
387 relerr = 0;
388 if (a1 || minus)
389 relerr++;
390 switch(c) {
391 case ' ':
392 case '\t':
393 continue;
394
395 case '+':
396 minus++;
397 if (a1==0)
398 a1 = dot;
399 continue;
400
401 case '-':
402 case '^':
403 minus--;
404 if (a1==0)
405 a1 = dot;
406 continue;
407
408 case '?':
409 case '/':
410 compile(c);
411 a1 = dot;
412 for (;;) {
413 if (c=='/') {
414 a1++;
415 if (a1 > dol)
416 a1 = zero;
417 } else {
418 a1--;
419 if (a1 < zero)
420 a1 = dol;
421 }
422 if (execute(0, a1))
423 break;
424 if (a1==dot)
425 error(Q);
426 }
427 break;
428
429 case '$':
430 a1 = dol;
431 break;
432
433 case '.':
434 a1 = dot;
435 break;
436
437 case '\'':
438 if ((c = getchr()) < 'a' || c > 'z')
439 error(Q);
440 for (a1=zero; a1<=dol; a1++)
441 if (names[c-'a'] == (*a1 & ~01))
442 break;
443 break;
444
445 default:
446 peekc = c;
447 if (a1==0)
448 return(0);
449 a1 += minus;
450 if (a1<zero || a1>dol)
451 error(Q);
452 return(a1);
453 }
454 if (relerr)
455 error(Q);
456 }
457}
458
459setdot()
460{
461 if (addr2 == 0)
462 addr1 = addr2 = dot;
463 if (addr1 > addr2)
464 error(Q);
465}
466
467setall()
468{
469 if (addr2==0) {
470 addr1 = zero+1;
471 addr2 = dol;
472 if (dol==zero)
473 addr1 = zero;
474 }
475 setdot();
476}
477
478setnoaddr()
479{
480 if (addr2)
481 error(Q);
482}
483
484nonzero()
485{
486 if (addr1<=zero || addr2>dol)
487 error(Q);
488}
489
490newline()
491{
492 register c;
493
494 if ((c = getchr()) == '\n')
495 return;
496 if (c=='p' || c=='l') {
497 pflag++;
498 if (c=='l')
499 listf++;
500 if (getchr() == '\n')
501 return;
502 }
503 error(Q);
504}
505
506filename(comm)
507{
508 register char *p1, *p2;
509 register c;
510
511 count = 0;
512 c = getchr();
513 if (c=='\n' || c==EOF) {
514 p1 = savedfile;
515 if (*p1==0 && comm!='f')
516 error(Q);
517 p2 = file;
518 while (*p2++ = *p1++)
519 ;
520 return;
521 }
522 if (c!=' ')
523 error(Q);
524 while ((c = getchr()) == ' ')
525 ;
526 if (c=='\n')
527 error(Q);
528 p1 = file;
529 do {
530 *p1++ = c;
531 if (c==' ' || c==EOF)
532 error(Q);
533 } while ((c = getchr()) != '\n');
534 *p1++ = 0;
535 if (savedfile[0]==0 || comm=='e' || comm=='f') {
536 p1 = savedfile;
537 p2 = file;
538 while (*p1++ = *p2++)
539 ;
540 }
541}
542
543exfile()
544{
545 close(io);
546 io = -1;
547 if (vflag) {
548 putd();
549 putchr('\n');
550 }
551}
552
553onintr()
554{
555 signal(SIGINT, onintr);
556 putchr('\n');
557 lastc = '\n';
558 error(Q);
559}
560
561onhup()
562{
563 signal(SIGINT, SIG_IGN);
564 signal(SIGHUP, SIG_IGN);
565 if (dol > zero) {
566 addr1 = zero+1;
567 addr2 = dol;
568 io = creat("ed.hup", 0666);
569 if (io > 0)
570 putfile();
571 }
572 fchange = 0;
573 quit();
574}
575
576error(s)
577char *s;
578{
579 register c;
580
581 wrapp = 0;
582 listf = 0;
583 putchr('?');
584 puts(s);
585 count = 0;
586 lseek(0, (long)0, 2);
587 pflag = 0;
588 if (globp)
589 lastc = '\n';
590 globp = 0;
591 peekc = lastc;
592 if(lastc)
593 while ((c = getchr()) != '\n' && c != EOF)
594 ;
595 if (io > 0) {
596 close(io);
597 io = -1;
598 }
599 longjmp(savej, 1);
600}
601
602getchr()
603{
604 char c;
605 if (lastc=peekc) {
606 peekc = 0;
607 return(lastc);
608 }
609 if (globp) {
610 if ((lastc = *globp++) != 0)
611 return(lastc);
612 globp = 0;
613 return(EOF);
614 }
615 if (read(0, &c, 1) <= 0)
616 return(lastc = EOF);
617 lastc = c&0177;
618 return(lastc);
619}
620
621gettty()
622{
623 register c;
624 register char *gf;
625 register char *p;
626
627 p = linebuf;
628 gf = globp;
629 while ((c = getchr()) != '\n') {
630 if (c==EOF) {
631 if (gf)
632 peekc = c;
633 return(c);
634 }
635 if ((c &= 0177) == 0)
636 continue;
637 *p++ = c;
638 if (p >= &linebuf[LBSIZE-2])
639 error(Q);
640 }
641 *p++ = 0;
642 if (linebuf[0]=='.' && linebuf[1]==0)
643 return(EOF);
644 return(0);
645}
646
647getfile()
648{
649 register c;
650 register char *lp, *fp;
651
652 lp = linebuf;
653 fp = nextip;
654 do {
655 if (--ninbuf < 0) {
656 if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0)
657 return(EOF);
658 fp = genbuf;
659 while(fp < &genbuf[ninbuf]) {
660 if (*fp++ & 0200) {
31e58db8
KM
661 break;
662 }
663 }
664 fp = genbuf;
665 }
666 c = *fp++;
667 if (c=='\0')
668 continue;
669 if (c&0200 || lp >= &linebuf[LBSIZE]) {
670 lastc = '\n';
671 error(Q);
672 }
673 *lp++ = c;
674 count++;
675 } while (c != '\n');
676 *--lp = 0;
677 nextip = fp;
678 return(0);
679}
680
681putfile()
682{
683 int *a1, n;
684 register char *fp, *lp;
685 register nib;
686
687 nib = 512;
688 fp = genbuf;
689 a1 = addr1;
690 do {
691 lp = getline(*a1++);
692 for (;;) {
693 if (--nib < 0) {
694 n = fp-genbuf;
31e58db8
KM
695 if(write(io, genbuf, n) != n) {
696 puts(WRERR);
697 error(Q);
698 }
699 nib = 511;
700 fp = genbuf;
701 }
702 count++;
703 if ((*fp++ = *lp++) == 0) {
704 fp[-1] = '\n';
705 break;
706 }
707 }
708 } while (a1 <= addr2);
709 n = fp-genbuf;
31e58db8
KM
710 if(write(io, genbuf, n) != n) {
711 puts(WRERR);
712 error(Q);
713 }
714}
715
716append(f, a)
717int *a;
718int (*f)();
719{
720 register *a1, *a2, *rdot;
721 int nline, tl;
722
723 nline = 0;
724 dot = a;
725 while ((*f)() == 0) {
726 if ((dol-zero)+1 >= nlall) {
727 int *ozero = zero;
728 nlall += 512;
31e58db8
KM
729 if ((zero = (int *)realloc((char *)zero, nlall*sizeof(int)))==NULL) {
730 lastc = '\n';
731 zero = ozero;
732 error("MEM?");
733 }
734 dot += zero - ozero;
735 dol += zero - ozero;
736 }
737 tl = putline();
738 nline++;
739 a1 = ++dol;
740 a2 = a1+1;
741 rdot = ++dot;
742 while (a1 > rdot)
743 *--a2 = *--a1;
744 *rdot = tl;
745 }
746 return(nline);
747}
748
749callunix()
750{
751 register (*savint)(), pid, rpid;
752 int retcode;
753
754 setnoaddr();
755 if ((pid = fork()) == 0) {
756 signal(SIGHUP, oldhup);
757 signal(SIGQUIT, oldquit);
dc891cfc 758 execl(_PATH_BSHELL, "sh", "-t", 0);
31e58db8
KM
759 exit(0100);
760 }
761 savint = signal(SIGINT, SIG_IGN);
762 while ((rpid = wait(&retcode)) != pid && rpid != -1)
763 ;
764 signal(SIGINT, savint);
765 puts("!");
766}
767
768quit()
769{
770 if (vflag && fchange && dol!=zero) {
771 fchange = 0;
772 error(Q);
773 }
774 unlink(tfname);
775 exit(0);
776}
777
778delete()
779{
780 setdot();
781 newline();
782 nonzero();
783 rdelete(addr1, addr2);
784}
785
786rdelete(ad1, ad2)
787int *ad1, *ad2;
788{
789 register *a1, *a2, *a3;
790
791 a1 = ad1;
792 a2 = ad2+1;
793 a3 = dol;
794 dol -= a2 - a1;
795 do {
796 *a1++ = *a2++;
797 } while (a2 <= a3);
798 a1 = ad1;
799 if (a1 > dol)
800 a1 = dol;
801 dot = a1;
802 fchange = 1;
803}
804
805gdelete()
806{
807 register *a1, *a2, *a3;
808
809 a3 = dol;
810 for (a1=zero+1; (*a1&01)==0; a1++)
811 if (a1>=a3)
812 return;
813 for (a2=a1+1; a2<=a3;) {
814 if (*a2&01) {
815 a2++;
816 dot = a1;
817 } else
818 *a1++ = *a2++;
819 }
820 dol = a1-1;
821 if (dot>dol)
822 dot = dol;
823 fchange = 1;
824}
825
826char *
827getline(tl)
828{
829 register char *bp, *lp;
830 register nl;
831
832 lp = linebuf;
833 bp = getblock(tl, READ);
834 nl = nleft;
835 tl &= ~0377;
836 while (*lp++ = *bp++)
837 if (--nl == 0) {
838 bp = getblock(tl+=0400, READ);
839 nl = nleft;
840 }
841 return(linebuf);
842}
843
844putline()
845{
846 register char *bp, *lp;
847 register nl;
848 int tl;
849
850 fchange = 1;
851 lp = linebuf;
852 tl = tline;
853 bp = getblock(tl, WRITE);
854 nl = nleft;
855 tl &= ~0377;
856 while (*bp = *lp++) {
857 if (*bp++ == '\n') {
858 *--bp = 0;
859 linebp = lp;
860 break;
861 }
862 if (--nl == 0) {
863 bp = getblock(tl+=0400, WRITE);
864 nl = nleft;
865 }
866 }
867 nl = tline;
868 tline += (((lp-linebuf)+03)>>1)&077776;
869 return(nl);
870}
871
872char *
873getblock(atl, iof)
874{
875 extern read(), write();
876 register bno, off;
877 register char *p1, *p2;
878 register int n;
879
880 bno = (atl>>8)&0377;
881 off = (atl<<1)&0774;
882 if (bno >= 255) {
883 lastc = '\n';
884 error(T);
885 }
886 nleft = 512 - off;
887 if (bno==iblock) {
888 ichanged |= iof;
889 return(ibuff+off);
890 }
891 if (bno==oblock)
892 return(obuff+off);
893 if (iof==READ) {
894 if (ichanged) {
31e58db8
KM
895 blkio(iblock, ibuff, write);
896 }
897 ichanged = 0;
898 iblock = bno;
899 blkio(bno, ibuff, read);
31e58db8
KM
900 return(ibuff+off);
901 }
902 if (oblock>=0) {
31e58db8
KM
903 blkio(oblock, obuff, write);
904 }
905 oblock = bno;
906 return(obuff+off);
907}
908
909blkio(b, buf, iofcn)
910char *buf;
911int (*iofcn)();
912{
913 lseek(tfile, (long)b<<9, 0);
914 if ((*iofcn)(tfile, buf, 512) != 512) {
915 error(T);
916 }
917}
918
919init()
920{
921 register *markp;
922
923 close(tfile);
924 tline = 2;
925 for (markp = names; markp < &names[26]; )
926 *markp++ = 0;
927 subnewa = 0;
928 anymarks = 0;
929 iblock = -1;
930 oblock = -1;
931 ichanged = 0;
932 close(creat(tfname, 0600));
933 tfile = open(tfname, 2);
31e58db8
KM
934 dot = dol = zero;
935}
936
937global(k)
938{
939 register char *gp;
940 register c;
941 register int *a1;
942 char globuf[GBSIZE];
943
944 if (globp)
945 error(Q);
946 setall();
947 nonzero();
948 if ((c=getchr())=='\n')
949 error(Q);
950 compile(c);
951 gp = globuf;
952 while ((c = getchr()) != '\n') {
953 if (c==EOF)
954 error(Q);
955 if (c=='\\') {
956 c = getchr();
957 if (c!='\n')
958 *gp++ = '\\';
959 }
960 *gp++ = c;
961 if (gp >= &globuf[GBSIZE-2])
962 error(Q);
963 }
964 *gp++ = '\n';
965 *gp++ = 0;
966 for (a1=zero; a1<=dol; a1++) {
967 *a1 &= ~01;
968 if (a1>=addr1 && a1<=addr2 && execute(0, a1)==k)
969 *a1 |= 01;
970 }
971 /*
972 * Special case: g/.../d (avoid n^2 algorithm)
973 */
974 if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
975 gdelete();
976 return;
977 }
978 for (a1=zero; a1<=dol; a1++) {
979 if (*a1 & 01) {
980 *a1 &= ~01;
981 dot = a1;
982 globp = globuf;
983 commands();
984 a1 = zero;
985 }
986 }
987}
988
989join()
990{
991 register char *gp, *lp;
992 register *a1;
993
994 gp = genbuf;
995 for (a1=addr1; a1<=addr2; a1++) {
996 lp = getline(*a1);
997 while (*gp = *lp++)
998 if (gp++ >= &genbuf[LBSIZE-2])
999 error(Q);
1000 }
1001 lp = linebuf;
1002 gp = genbuf;
1003 while (*lp++ = *gp++)
1004 ;
1005 *addr1 = putline();
1006 if (addr1<addr2)
1007 rdelete(addr1+1, addr2);
1008 dot = addr1;
1009}
1010
1011substitute(inglob)
1012{
1013 register *markp, *a1, nl;
1014 int gsubf;
1015 int getsub();
1016
1017 gsubf = compsub();
1018 for (a1 = addr1; a1 <= addr2; a1++) {
1019 int *ozero;
1020 if (execute(0, a1)==0)
1021 continue;
1022 inglob |= 01;
1023 dosub();
1024 if (gsubf) {
1025 while (*loc2) {
1026 if (execute(1, (int *)0)==0)
1027 break;
1028 dosub();
1029 }
1030 }
1031 subnewa = putline();
1032 *a1 &= ~01;
1033 if (anymarks) {
1034 for (markp = names; markp < &names[26]; markp++)
1035 if (*markp == *a1)
1036 *markp = subnewa;
1037 }
1038 subolda = *a1;
1039 *a1 = subnewa;
1040 ozero = zero;
1041 nl = append(getsub, a1);
1042 nl += zero-ozero;
1043 a1 += nl;
1044 addr2 += nl;
1045 }
1046 if (inglob==0)
1047 error(Q);
1048}
1049
1050compsub()
1051{
1052 register seof, c;
1053 register char *p;
1054
1055 if ((seof = getchr()) == '\n' || seof == ' ')
1056 error(Q);
1057 compile(seof);
1058 p = rhsbuf;
1059 for (;;) {
1060 c = getchr();
1061 if (c=='\\')
1062 c = getchr() | 0200;
1063 if (c=='\n') {
1064 if (globp)
1065 c |= 0200;
1066 else
1067 error(Q);
1068 }
1069 if (c==seof)
1070 break;
1071 *p++ = c;
1072 if (p >= &rhsbuf[LBSIZE/2])
1073 error(Q);
1074 }
1075 *p++ = 0;
1076 if ((peekc = getchr()) == 'g') {
1077 peekc = 0;
1078 newline();
1079 return(1);
1080 }
1081 newline();
1082 return(0);
1083}
1084
1085getsub()
1086{
1087 register char *p1, *p2;
1088
1089 p1 = linebuf;
1090 if ((p2 = linebp) == 0)
1091 return(EOF);
1092 while (*p1++ = *p2++)
1093 ;
1094 linebp = 0;
1095 return(0);
1096}
1097
1098dosub()
1099{
1100 register char *lp, *sp, *rp;
1101 int c;
1102
1103 lp = linebuf;
1104 sp = genbuf;
1105 rp = rhsbuf;
1106 while (lp < loc1)
1107 *sp++ = *lp++;
1108 while (c = *rp++&0377) {
1109 if (c=='&') {
1110 sp = place(sp, loc1, loc2);
1111 continue;
1112 } else if (c&0200 && (c &= 0177) >='1' && c < nbra+'1') {
1113 sp = place(sp, braslist[c-'1'], braelist[c-'1']);
1114 continue;
1115 }
1116 *sp++ = c&0177;
1117 if (sp >= &genbuf[LBSIZE])
1118 error(Q);
1119 }
1120 lp = loc2;
1121 loc2 = sp - genbuf + linebuf;
1122 while (*sp++ = *lp++)
1123 if (sp >= &genbuf[LBSIZE])
1124 error(Q);
1125 lp = linebuf;
1126 sp = genbuf;
1127 while (*lp++ = *sp++)
1128 ;
1129}
1130
1131char *
1132place(sp, l1, l2)
1133register char *sp, *l1, *l2;
1134{
1135
1136 while (l1 < l2) {
1137 *sp++ = *l1++;
1138 if (sp >= &genbuf[LBSIZE])
1139 error(Q);
1140 }
1141 return(sp);
1142}
1143
1144move(cflag)
1145{
1146 register int *adt, *ad1, *ad2;
1147 int getcopy();
1148
1149 setdot();
1150 nonzero();
1151 if ((adt = address())==0)
1152 error(Q);
1153 newline();
1154 if (cflag) {
1155 int *ozero, delta;
1156 ad1 = dol;
1157 ozero = zero;
1158 append(getcopy, ad1++);
1159 ad2 = dol;
1160 delta = zero - ozero;
1161 ad1 += delta;
1162 adt += delta;
1163 } else {
1164 ad2 = addr2;
1165 for (ad1 = addr1; ad1 <= ad2;)
1166 *ad1++ &= ~01;
1167 ad1 = addr1;
1168 }
1169 ad2++;
1170 if (adt<ad1) {
1171 dot = adt + (ad2-ad1);
1172 if ((++adt)==ad1)
1173 return;
1174 reverse(adt, ad1);
1175 reverse(ad1, ad2);
1176 reverse(adt, ad2);
1177 } else if (adt >= ad2) {
1178 dot = adt++;
1179 reverse(ad1, ad2);
1180 reverse(ad2, adt);
1181 reverse(ad1, adt);
1182 } else
1183 error(Q);
1184 fchange = 1;
1185}
1186
1187reverse(a1, a2)
1188register int *a1, *a2;
1189{
1190 register int t;
1191
1192 for (;;) {
1193 t = *--a2;
1194 if (a2 <= a1)
1195 return;
1196 *a2 = *a1;
1197 *a1++ = t;
1198 }
1199}
1200
1201getcopy()
1202{
1203 if (addr1 > addr2)
1204 return(EOF);
1205 getline(*addr1++);
1206 return(0);
1207}
1208
1209compile(aeof)
1210{
1211 register eof, c;
1212 register char *ep;
1213 char *lastep;
1214 char bracket[NBRA], *bracketp;
1215 int cclcnt;
1216
1217 ep = expbuf;
1218 eof = aeof;
1219 bracketp = bracket;
1220 if ((c = getchr()) == eof) {
1221 if (*ep==0)
1222 error(Q);
1223 return;
1224 }
1225 circfl = 0;
1226 nbra = 0;
1227 if (c=='^') {
1228 c = getchr();
1229 circfl++;
1230 }
1231 peekc = c;
1232 lastep = 0;
1233 for (;;) {
1234 if (ep >= &expbuf[ESIZE])
1235 goto cerror;
1236 c = getchr();
1237 if (c==eof) {
1238 if (bracketp != bracket)
1239 goto cerror;
1240 *ep++ = CEOF;
1241 return;
1242 }
1243 if (c!='*')
1244 lastep = ep;
1245 switch (c) {
1246
1247 case '\\':
1248 if ((c = getchr())=='(') {
1249 if (nbra >= NBRA)
1250 goto cerror;
1251 *bracketp++ = nbra;
1252 *ep++ = CBRA;
1253 *ep++ = nbra++;
1254 continue;
1255 }
1256 if (c == ')') {
1257 if (bracketp <= bracket)
1258 goto cerror;
1259 *ep++ = CKET;
1260 *ep++ = *--bracketp;
1261 continue;
1262 }
1263 if (c>='1' && c<'1'+NBRA) {
1264 *ep++ = CBACK;
1265 *ep++ = c-'1';
1266 continue;
1267 }
1268 *ep++ = CCHR;
1269 if (c=='\n')
1270 goto cerror;
1271 *ep++ = c;
1272 continue;
1273
1274 case '.':
1275 *ep++ = CDOT;
1276 continue;
1277
1278 case '\n':
1279 goto cerror;
1280
1281 case '*':
1282 if (lastep==0 || *lastep==CBRA || *lastep==CKET)
1283 goto defchar;
1284 *lastep |= STAR;
1285 continue;
1286
1287 case '$':
1288 if ((peekc=getchr()) != eof)
1289 goto defchar;
1290 *ep++ = CDOL;
1291 continue;
1292
1293 case '[':
1294 *ep++ = CCL;
1295 *ep++ = 0;
1296 cclcnt = 1;
1297 if ((c=getchr()) == '^') {
1298 c = getchr();
1299 ep[-2] = NCCL;
1300 }
1301 do {
1302 if (c=='\n')
1303 goto cerror;
1304 if (c=='-' && ep[-1]!=0) {
1305 if ((c=getchr())==']') {
1306 *ep++ = '-';
1307 cclcnt++;
1308 break;
1309 }
1310 while (ep[-1]<c) {
1311 *ep = ep[-1]+1;
1312 ep++;
1313 cclcnt++;
1314 if (ep>=&expbuf[ESIZE])
1315 goto cerror;
1316 }
1317 }
1318 *ep++ = c;
1319 cclcnt++;
1320 if (ep >= &expbuf[ESIZE])
1321 goto cerror;
1322 } while ((c = getchr()) != ']');
1323 lastep[1] = cclcnt;
1324 continue;
1325
1326 defchar:
1327 default:
1328 *ep++ = CCHR;
1329 *ep++ = c;
1330 }
1331 }
1332 cerror:
1333 expbuf[0] = 0;
1334 nbra = 0;
1335 error(Q);
1336}
1337
1338execute(gf, addr)
1339int *addr;
1340{
1341 register char *p1, *p2, c;
1342
1343 for (c=0; c<NBRA; c++) {
1344 braslist[c] = 0;
1345 braelist[c] = 0;
1346 }
1347 if (gf) {
1348 if (circfl)
1349 return(0);
1350 p1 = linebuf;
1351 p2 = genbuf;
1352 while (*p1++ = *p2++)
1353 ;
1354 locs = p1 = loc2;
1355 } else {
1356 if (addr==zero)
1357 return(0);
1358 p1 = getline(*addr);
1359 locs = 0;
1360 }
1361 p2 = expbuf;
1362 if (circfl) {
1363 loc1 = p1;
1364 return(advance(p1, p2));
1365 }
1366 /* fast check for first character */
1367 if (*p2==CCHR) {
1368 c = p2[1];
1369 do {
1370 if (*p1!=c)
1371 continue;
1372 if (advance(p1, p2)) {
1373 loc1 = p1;
1374 return(1);
1375 }
1376 } while (*p1++);
1377 return(0);
1378 }
1379 /* regular algorithm */
1380 do {
1381 if (advance(p1, p2)) {
1382 loc1 = p1;
1383 return(1);
1384 }
1385 } while (*p1++);
1386 return(0);
1387}
1388
1389advance(lp, ep)
1390register char *ep, *lp;
1391{
1392 register char *curlp;
1393 int i;
1394
1395 for (;;) switch (*ep++) {
1396
1397 case CCHR:
1398 if (*ep++ == *lp++)
1399 continue;
1400 return(0);
1401
1402 case CDOT:
1403 if (*lp++)
1404 continue;
1405 return(0);
1406
1407 case CDOL:
1408 if (*lp==0)
1409 continue;
1410 return(0);
1411
1412 case CEOF:
1413 loc2 = lp;
1414 return(1);
1415
1416 case CCL:
1417 if (cclass(ep, *lp++, 1)) {
1418 ep += *ep;
1419 continue;
1420 }
1421 return(0);
1422
1423 case NCCL:
1424 if (cclass(ep, *lp++, 0)) {
1425 ep += *ep;
1426 continue;
1427 }
1428 return(0);
1429
1430 case CBRA:
1431 braslist[*ep++] = lp;
1432 continue;
1433
1434 case CKET:
1435 braelist[*ep++] = lp;
1436 continue;
1437
1438 case CBACK:
1439 if (braelist[i = *ep++]==0)
1440 error(Q);
1441 if (backref(i, lp)) {
1442 lp += braelist[i] - braslist[i];
1443 continue;
1444 }
1445 return(0);
1446
1447 case CBACK|STAR:
1448 if (braelist[i = *ep++] == 0)
1449 error(Q);
1450 curlp = lp;
1451 while (backref(i, lp))
1452 lp += braelist[i] - braslist[i];
1453 while (lp >= curlp) {
1454 if (advance(lp, ep))
1455 return(1);
1456 lp -= braelist[i] - braslist[i];
1457 }
1458 continue;
1459
1460 case CDOT|STAR:
1461 curlp = lp;
1462 while (*lp++)
1463 ;
1464 goto star;
1465
1466 case CCHR|STAR:
1467 curlp = lp;
1468 while (*lp++ == *ep)
1469 ;
1470 ep++;
1471 goto star;
1472
1473 case CCL|STAR:
1474 case NCCL|STAR:
1475 curlp = lp;
1476 while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)))
1477 ;
1478 ep += *ep;
1479 goto star;
1480
1481 star:
1482 do {
1483 lp--;
1484 if (lp==locs)
1485 break;
1486 if (advance(lp, ep))
1487 return(1);
1488 } while (lp > curlp);
1489 return(0);
1490
1491 default:
1492 error(Q);
1493 }
1494}
1495
1496backref(i, lp)
1497register i;
1498register char *lp;
1499{
1500 register char *bp;
1501
1502 bp = braslist[i];
1503 while (*bp++ == *lp++)
1504 if (bp >= braelist[i])
1505 return(1);
1506 return(0);
1507}
1508
1509cclass(set, c, af)
1510register char *set, c;
1511{
1512 register n;
1513
1514 if (c==0)
1515 return(0);
1516 n = *set++;
1517 while (--n)
1518 if (*set++ == c)
1519 return(af);
1520 return(!af);
1521}
1522
1523putd()
1524{
1525 register r;
1526
1527 r = count%10;
1528 count /= 10;
1529 if (count)
1530 putd();
1531 putchr(r + '0');
1532}
1533
1534puts(sp)
1535register char *sp;
1536{
1537 col = 0;
1538 while (*sp)
1539 putchr(*sp++);
1540 putchr('\n');
1541}
1542
1543char line[70];
1544char *linp = line;
1545
1546putchr(ac)
1547{
1548 register char *lp;
1549 register c;
1550
1551 lp = linp;
1552 c = ac;
1553 if (listf) {
1554 col++;
1555 if (col >= 72) {
1556 col = 0;
1557 *lp++ = '\\';
1558 *lp++ = '\n';
1559 }
1560 if (c=='\t') {
1561 c = '>';
1562 goto esc;
1563 }
1564 if (c=='\b') {
1565 c = '<';
1566 esc:
1567 *lp++ = '-';
1568 *lp++ = '\b';
1569 *lp++ = c;
1570 goto out;
1571 }
1572 if (c<' ' && c!= '\n') {
1573 *lp++ = '\\';
1574 *lp++ = (c>>3)+'0';
1575 *lp++ = (c&07)+'0';
1576 col += 2;
1577 goto out;
1578 }
1579 }
1580 *lp++ = c;
1581out:
1582 if(c == '\n' || lp >= &line[64]) {
1583 linp = line;
1584 write(1, line, lp-line);
1585 return;
1586 }
1587 linp = lp;
1588}
62793f1c 1589