Blob


1 /*
2 * Editor
3 */
4 #include <u.h>
5 #include <libc.h>
6 #include <bio.h>
7 #include <regexp.h>
9 #undef EOF /* stdio? */
11 enum
12 {
13 FNSIZE = 128, /* file name */
14 LBSIZE = 4096, /* max line size */
15 BLKSIZE = 4096, /* block size in temp file */
16 NBLK = 32767, /* max size of temp file */
17 ESIZE = 256, /* max size of reg exp */
18 GBSIZE = 256, /* max size of global command */
19 MAXSUB = 9, /* max number of sub reg exp */
20 ESCFLG = 0xFFFF, /* escape Rune - user defined code */
21 EOF = -1
22 };
24 void (*oldhup)(int);
25 void (*oldquit)(int);
26 int* addr1;
27 int* addr2;
28 int anymarks;
29 int col;
30 long count;
31 int* dol;
32 int* dot;
33 int fchange;
34 char file[FNSIZE];
35 Rune genbuf[LBSIZE];
36 int given;
37 Rune* globp;
38 int iblock;
39 int ichanged;
40 int io;
41 Biobuf iobuf;
42 int lastc;
43 char line[70];
44 Rune* linebp;
45 Rune linebuf[LBSIZE];
46 int listf;
47 int listn;
48 Rune* loc1;
49 Rune* loc2;
50 int names[26];
51 int nleft;
52 int oblock;
53 int oflag;
54 Reprog *pattern;
55 int peekc;
56 int pflag;
57 int rescuing;
58 Rune rhsbuf[LBSIZE/sizeof(Rune)];
59 char savedfile[FNSIZE];
60 jmp_buf savej;
61 int subnewa;
62 int subolda;
63 Resub subexp[MAXSUB];
64 char* tfname;
65 int tline;
66 int waiting;
67 int wrapp;
68 int* zero;
70 char Q[] = "";
71 char T[] = "TMP";
72 char WRERR[] = "WRITE ERROR";
73 int bpagesize = 20;
74 char hex[] = "0123456789abcdef";
75 char* linp = line;
76 ulong nlall = 128;
77 int tfile = -1;
78 int vflag = 1;
80 void add(int);
81 int* address(void);
82 int append(int(*)(void), int*);
83 void browse(void);
84 void callunix(void);
85 void commands(void);
86 void compile(int);
87 int compsub(void);
88 void dosub(void);
89 void error(char*);
90 int match(int*);
91 void exfile(int);
92 void filename(int);
93 Rune* getblock(int, int);
94 int getchr(void);
95 int getcopy(void);
96 int getfile(void);
97 Rune* getline(int);
98 int getnum(void);
99 int getsub(void);
100 int gettty(void);
101 void global(int);
102 void init(void);
103 void join(void);
104 void move(int);
105 void newline(void);
106 void nonzero(void);
107 void notifyf(void*, char*);
108 Rune* place(Rune*, Rune*, Rune*);
109 void printcom(void);
110 void putchr(int);
111 void putd(void);
112 void putfile(void);
113 int putline(void);
114 void putshst(Rune*);
115 void putst(char*);
116 void quit(void);
117 void rdelete(int*, int*);
118 void regerror(char *);
119 void reverse(int*, int*);
120 void setnoaddr(void);
121 void setwide(void);
122 void squeeze(int);
123 void substitute(int);
125 Rune La[] = { 'a', 0 };
126 Rune Lr[] = { 'r', 0 };
128 char tmp[] = "/var/tmp/eXXXXX";
130 void
131 main(int argc, char *argv[])
133 char *p1, *p2;
135 notify(notifyf);
136 ARGBEGIN {
137 case 'o':
138 oflag = 1;
139 vflag = 0;
140 break;
141 } ARGEND
143 USED(argc);
144 if(*argv && (strcmp(*argv, "-") == 0)) {
145 argv++;
146 vflag = 0;
148 if(oflag) {
149 p1 = "/dev/stdout";
150 p2 = savedfile;
151 while(*p2++ = *p1++)
153 globp = La;
154 } else
155 if(*argv) {
156 p1 = *argv;
157 p2 = savedfile;
158 while(*p2++ = *p1++)
159 if(p2 >= &savedfile[sizeof(savedfile)])
160 p2--;
161 globp = Lr;
163 zero = malloc((nlall+5)*sizeof(int*));
164 tfname = mktemp(tmp);
165 init();
166 setjmp(savej);
167 commands();
168 quit();
171 void
172 commands(void)
174 int *a1, c, temp;
175 char lastsep;
176 Dir *d;
178 for(;;) {
179 if(pflag) {
180 pflag = 0;
181 addr1 = addr2 = dot;
182 printcom();
184 c = '\n';
185 for(addr1 = 0;;) {
186 lastsep = c;
187 a1 = address();
188 c = getchr();
189 if(c != ',' && c != ';')
190 break;
191 if(lastsep == ',')
192 error(Q);
193 if(a1 == 0) {
194 a1 = zero+1;
195 if(a1 > dol)
196 a1--;
198 addr1 = a1;
199 if(c == ';')
200 dot = a1;
202 if(lastsep != '\n' && a1 == 0)
203 a1 = dol;
204 if((addr2=a1) == 0) {
205 given = 0;
206 addr2 = dot;
207 } else
208 given = 1;
209 if(addr1 == 0)
210 addr1 = addr2;
211 switch(c) {
213 case 'a':
214 add(0);
215 continue;
217 case 'b':
218 nonzero();
219 browse();
220 continue;
222 case 'c':
223 nonzero();
224 newline();
225 rdelete(addr1, addr2);
226 append(gettty, addr1-1);
227 continue;
229 case 'd':
230 nonzero();
231 newline();
232 rdelete(addr1, addr2);
233 continue;
235 case 'E':
236 fchange = 0;
237 c = 'e';
238 case 'e':
239 setnoaddr();
240 if(vflag && fchange) {
241 fchange = 0;
242 error(Q);
244 filename(c);
245 init();
246 addr2 = zero;
247 goto caseread;
249 case 'f':
250 setnoaddr();
251 filename(c);
252 putst(savedfile);
253 continue;
255 case 'g':
256 global(1);
257 continue;
259 case 'i':
260 add(-1);
261 continue;
264 case 'j':
265 if(!given)
266 addr2++;
267 newline();
268 join();
269 continue;
271 case 'k':
272 nonzero();
273 c = getchr();
274 if(c < 'a' || c > 'z')
275 error(Q);
276 newline();
277 names[c-'a'] = *addr2 & ~01;
278 anymarks |= 01;
279 continue;
281 case 'm':
282 move(0);
283 continue;
285 case 'n':
286 listn++;
287 newline();
288 printcom();
289 continue;
291 case '\n':
292 if(a1==0) {
293 a1 = dot+1;
294 addr2 = a1;
295 addr1 = a1;
297 if(lastsep==';')
298 addr1 = a1;
299 printcom();
300 continue;
302 case 'l':
303 listf++;
304 case 'p':
305 case 'P':
306 newline();
307 printcom();
308 continue;
310 case 'Q':
311 fchange = 0;
312 case 'q':
313 setnoaddr();
314 newline();
315 quit();
317 case 'r':
318 filename(c);
319 caseread:
320 if((io=open(file, OREAD)) < 0) {
321 lastc = '\n';
322 error(file);
324 if((d = dirfstat(io)) != nil){
325 if(d->mode & DMAPPEND)
326 print("warning: %s is append only\n", file);
327 free(d);
329 Binit(&iobuf, io, OREAD);
330 setwide();
331 squeeze(0);
332 c = zero != dol;
333 append(getfile, addr2);
334 exfile(OREAD);
336 fchange = c;
337 continue;
339 case 's':
340 nonzero();
341 substitute(globp != 0);
342 continue;
344 case 't':
345 move(1);
346 continue;
348 case 'u':
349 nonzero();
350 newline();
351 if((*addr2&~01) != subnewa)
352 error(Q);
353 *addr2 = subolda;
354 dot = addr2;
355 continue;
357 case 'v':
358 global(0);
359 continue;
361 case 'W':
362 wrapp++;
363 case 'w':
364 setwide();
365 squeeze(dol>zero);
366 temp = getchr();
367 if(temp != 'q' && temp != 'Q') {
368 peekc = temp;
369 temp = 0;
371 filename(c);
372 if(!wrapp ||
373 ((io = open(file, OWRITE)) == -1) ||
374 ((seek(io, 0L, 2)) == -1))
375 if((io = create(file, OWRITE, 0666)) < 0)
376 error(file);
377 Binit(&iobuf, io, OWRITE);
378 wrapp = 0;
379 if(dol > zero)
380 putfile();
381 exfile(OWRITE);
382 if(addr1<=zero+1 && addr2==dol)
383 fchange = 0;
384 if(temp == 'Q')
385 fchange = 0;
386 if(temp)
387 quit();
388 continue;
390 case '=':
391 setwide();
392 squeeze(0);
393 newline();
394 count = addr2 - zero;
395 putd();
396 putchr('\n');
397 continue;
399 case '!':
400 callunix();
401 continue;
403 case EOF:
404 return;
407 error(Q);
411 void
412 printcom(void)
414 int *a1;
416 nonzero();
417 a1 = addr1;
418 do {
419 if(listn) {
420 count = a1-zero;
421 putd();
422 putchr('\t');
424 putshst(getline(*a1++));
425 } while(a1 <= addr2);
426 dot = addr2;
427 listf = 0;
428 listn = 0;
429 pflag = 0;
432 int*
433 address(void)
435 int sign, *a, opcnt, nextopand, *b, c;
437 nextopand = -1;
438 sign = 1;
439 opcnt = 0;
440 a = dot;
441 do {
442 do {
443 c = getchr();
444 } while(c == ' ' || c == '\t');
445 if(c >= '0' && c <= '9') {
446 peekc = c;
447 if(!opcnt)
448 a = zero;
449 a += sign*getnum();
450 } else
451 switch(c) {
452 case '$':
453 a = dol;
454 case '.':
455 if(opcnt)
456 error(Q);
457 break;
458 case '\'':
459 c = getchr();
460 if(opcnt || c < 'a' || c > 'z')
461 error(Q);
462 a = zero;
463 do {
464 a++;
465 } while(a <= dol && names[c-'a'] != (*a & ~01));
466 break;
467 case '?':
468 sign = -sign;
469 case '/':
470 compile(c);
471 b = a;
472 for(;;) {
473 a += sign;
474 if(a <= zero)
475 a = dol;
476 if(a > dol)
477 a = zero;
478 if(match(a))
479 break;
480 if(a == b)
481 error(Q);
483 break;
484 default:
485 if(nextopand == opcnt) {
486 a += sign;
487 if(a < zero || dol < a)
488 continue; /* error(Q); */
490 if(c != '+' && c != '-' && c != '^') {
491 peekc = c;
492 if(opcnt == 0)
493 a = 0;
494 return a;
496 sign = 1;
497 if(c != '+')
498 sign = -sign;
499 nextopand = ++opcnt;
500 continue;
502 sign = 1;
503 opcnt++;
504 } while(zero <= a && a <= dol);
505 error(Q);
506 return 0;
509 int
510 getnum(void)
512 int r, c;
514 r = 0;
515 for(;;) {
516 c = getchr();
517 if(c < '0' || c > '9')
518 break;
519 r = r*10 + (c-'0');
521 peekc = c;
522 return r;
525 void
526 setwide(void)
528 if(!given) {
529 addr1 = zero + (dol>zero);
530 addr2 = dol;
534 void
535 setnoaddr(void)
537 if(given)
538 error(Q);
541 void
542 nonzero(void)
544 squeeze(1);
547 void
548 squeeze(int i)
550 if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
551 error(Q);
554 void
555 newline(void)
557 int c;
559 c = getchr();
560 if(c == '\n' || c == EOF)
561 return;
562 if(c == 'p' || c == 'l' || c == 'n') {
563 pflag++;
564 if(c == 'l')
565 listf++;
566 else
567 if(c == 'n')
568 listn++;
569 c = getchr();
570 if(c == '\n')
571 return;
573 error(Q);
576 void
577 filename(int comm)
579 char *p1, *p2;
580 Rune rune;
581 int c;
583 count = 0;
584 c = getchr();
585 if(c == '\n' || c == EOF) {
586 p1 = savedfile;
587 if(*p1 == 0 && comm != 'f')
588 error(Q);
589 p2 = file;
590 while(*p2++ = *p1++)
592 return;
594 if(c != ' ')
595 error(Q);
596 while((c=getchr()) == ' ')
598 if(c == '\n')
599 error(Q);
600 p1 = file;
601 do {
602 if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)
603 error(Q);
604 rune = c;
605 p1 += runetochar(p1, &rune);
606 } while((c=getchr()) != '\n');
607 *p1 = 0;
608 if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {
609 p1 = savedfile;
610 p2 = file;
611 while(*p1++ = *p2++)
616 void
617 exfile(int om)
620 if(om == OWRITE)
621 if(Bflush(&iobuf) < 0)
622 error(Q);
623 close(io);
624 io = -1;
625 if(vflag) {
626 putd();
627 putchr('\n');
631 void
632 error1(char *s)
634 int c;
636 wrapp = 0;
637 listf = 0;
638 listn = 0;
639 count = 0;
640 seek(0, 0, 2);
641 pflag = 0;
642 if(globp)
643 lastc = '\n';
644 globp = 0;
645 peekc = lastc;
646 if(lastc)
647 for(;;) {
648 c = getchr();
649 if(c == '\n' || c == EOF)
650 break;
652 if(io > 0) {
653 close(io);
654 io = -1;
656 putchr('?');
657 putst(s);
660 void
661 error(char *s)
663 error1(s);
664 longjmp(savej, 1);
667 void
668 rescue(void)
670 rescuing = 1;
671 if(dol > zero) {
672 addr1 = zero+1;
673 addr2 = dol;
674 io = create("ed.hup", OWRITE, 0666);
675 if(io > 0){
676 Binit(&iobuf, io, OWRITE);
677 putfile();
680 fchange = 0;
681 quit();
684 void
685 notifyf(void *a, char *s)
687 if(strcmp(s, "interrupt") == 0){
688 if(rescuing || waiting)
689 noted(NCONT);
690 putchr('\n');
691 lastc = '\n';
692 error1(Q);
693 notejmp(a, savej, 0);
695 if(strcmp(s, "hangup") == 0 || strcmp(s, "kill") == 0){
696 if(rescuing)
697 noted(NDFLT);
698 rescue();
700 if(strstr(s, "child"))
701 noted(NCONT);
702 fprint(2, "ed: note: %s\n", s);
703 abort();
706 int
707 getchr(void)
709 char s[UTFmax];
710 int i;
711 Rune r;
713 if(lastc = peekc) {
714 peekc = 0;
715 return lastc;
717 if(globp) {
718 if((lastc=*globp++) != 0)
719 return lastc;
720 globp = 0;
721 return EOF;
723 for(i=0;;) {
724 if(read(0, s+i, 1) <= 0)
725 return lastc = EOF;
726 i++;
727 if(fullrune(s, i))
728 break;
731 chartorune(&r, s);
732 lastc = r;
733 return lastc;
736 int
737 gety(void)
739 int c;
740 Rune *gf, *p;
742 p = linebuf;
743 gf = globp;
744 for(;;) {
745 c = getchr();
746 if(c == '\n') {
747 *p = 0;
748 return 0;
750 if(c == EOF) {
751 if(gf)
752 peekc = c;
753 return c;
755 if(c == 0)
756 continue;
757 *p++ = c;
758 if(p >= &linebuf[LBSIZE-2])
759 error(Q);
763 int
764 gettty(void)
766 int rc;
768 rc = gety();
769 if(rc)
770 return rc;
771 if(linebuf[0] == '.' && linebuf[1] == 0)
772 return EOF;
773 return 0;
776 int
777 getfile(void)
779 int c;
780 Rune *lp;
782 lp = linebuf;
783 do {
784 c = Bgetrune(&iobuf);
785 if(c < 0) {
786 if(lp > linebuf) {
787 putst("'\\n' appended");
788 c = '\n';
789 } else
790 return EOF;
792 if(lp >= &linebuf[LBSIZE]) {
793 lastc = '\n';
794 error(Q);
796 *lp++ = c;
797 count++;
798 } while(c != '\n');
799 lp[-1] = 0;
800 return 0;
803 void
804 putfile(void)
806 int *a1;
807 Rune *lp;
808 long c;
810 a1 = addr1;
811 do {
812 lp = getline(*a1++);
813 for(;;) {
814 count++;
815 c = *lp++;
816 if(c == 0) {
817 if(Bputrune(&iobuf, '\n') < 0)
818 error(Q);
819 break;
821 if(Bputrune(&iobuf, c) < 0)
822 error(Q);
824 } while(a1 <= addr2);
825 if(Bflush(&iobuf) < 0)
826 error(Q);
829 int
830 append(int (*f)(void), int *a)
832 int *a1, *a2, *rdot, nline, d;
834 nline = 0;
835 dot = a;
836 while((*f)() == 0) {
837 if((dol-zero) >= nlall) {
838 nlall += 512;
839 a1 = realloc(zero, (nlall+50)*sizeof(int*));
840 if(a1 == 0) {
841 error("MEM?");
842 rescue();
844 /* relocate pointers; avoid wraparound if sizeof(int) < sizeof(int*) */
845 d = addr1 - zero;
846 addr1 = a1 + d;
847 d = addr2 - zero;
848 addr2 = a1 + d;
849 d = dol - zero;
850 dol = a1 + d;
851 d = dot - zero;
852 dot = a1 + d;
853 zero = a1;
855 d = putline();
856 nline++;
857 a1 = ++dol;
858 a2 = a1+1;
859 rdot = ++dot;
860 while(a1 > rdot)
861 *--a2 = *--a1;
862 *rdot = d;
864 return nline;
867 void
868 add(int i)
870 if(i && (given || dol > zero)) {
871 addr1--;
872 addr2--;
874 squeeze(0);
875 newline();
876 append(gettty, addr2);
879 void
880 browse(void)
882 int forward, n;
883 static int bformat, bnum; /* 0 */
885 forward = 1;
886 peekc = getchr();
887 if(peekc != '\n'){
888 if(peekc == '-' || peekc == '+') {
889 if(peekc == '-')
890 forward = 0;
891 getchr();
893 n = getnum();
894 if(n > 0)
895 bpagesize = n;
897 newline();
898 if(pflag) {
899 bformat = listf;
900 bnum = listn;
901 } else {
902 listf = bformat;
903 listn = bnum;
905 if(forward) {
906 addr1 = addr2;
907 addr2 += bpagesize;
908 if(addr2 > dol)
909 addr2 = dol;
910 } else {
911 addr1 = addr2-bpagesize;
912 if(addr1 <= zero)
913 addr1 = zero+1;
915 printcom();
918 void
919 callunix(void)
921 int c, pid;
922 Rune rune;
923 char buf[512];
924 char *p;
926 setnoaddr();
927 p = buf;
928 while((c=getchr()) != EOF && c != '\n')
929 if(p < &buf[sizeof(buf) - 6]) {
930 rune = c;
931 p += runetochar(p, &rune);
933 *p = 0;
934 pid = fork();
935 if(pid == 0) {
936 execlp("rc", "rc", "-c", buf, (char*)0);
937 sysfatal("exec failed: %r");
938 exits("execl failed");
940 waiting = 1;
941 while(waitpid() != pid)
943 waiting = 0;
944 if(vflag)
945 putst("!");
948 void
949 quit(void)
951 if(vflag && fchange && dol!=zero) {
952 fchange = 0;
953 error(Q);
955 remove(tfname);
956 exits(0);
959 void
960 onquit(int sig)
962 USED(sig);
963 quit();
966 void
967 rdelete(int *ad1, int *ad2)
969 int *a1, *a2, *a3;
971 a1 = ad1;
972 a2 = ad2+1;
973 a3 = dol;
974 dol -= a2 - a1;
975 do {
976 *a1++ = *a2++;
977 } while(a2 <= a3);
978 a1 = ad1;
979 if(a1 > dol)
980 a1 = dol;
981 dot = a1;
982 fchange = 1;
985 void
986 gdelete(void)
988 int *a1, *a2, *a3;
990 a3 = dol;
991 for(a1=zero; (*a1&01)==0; a1++)
992 if(a1>=a3)
993 return;
994 for(a2=a1+1; a2<=a3;) {
995 if(*a2 & 01) {
996 a2++;
997 dot = a1;
998 } else
999 *a1++ = *a2++;
1001 dol = a1-1;
1002 if(dot > dol)
1003 dot = dol;
1004 fchange = 1;
1007 Rune*
1008 getline(int tl)
1010 Rune *lp, *bp;
1011 int nl;
1013 lp = linebuf;
1014 bp = getblock(tl, OREAD);
1015 nl = nleft;
1016 tl &= ~((BLKSIZE/sizeof(Rune)) - 1);
1017 while(*lp++ = *bp++) {
1018 nl -= sizeof(Rune);
1019 if(nl == 0) {
1020 bp = getblock(tl += BLKSIZE/sizeof(Rune), OREAD);
1021 nl = nleft;
1024 return linebuf;
1027 int
1028 putline(void)
1030 Rune *lp, *bp;
1031 int nl, tl;
1033 fchange = 1;
1034 lp = linebuf;
1035 tl = tline;
1036 bp = getblock(tl, OWRITE);
1037 nl = nleft;
1038 tl &= ~((BLKSIZE/sizeof(Rune))-1);
1039 while(*bp = *lp++) {
1040 if(*bp++ == '\n') {
1041 bp[-1] = 0;
1042 linebp = lp;
1043 break;
1045 nl -= sizeof(Rune);
1046 if(nl == 0) {
1047 tl += BLKSIZE/sizeof(Rune);
1048 bp = getblock(tl, OWRITE);
1049 nl = nleft;
1052 nl = tline;
1053 tline += ((lp-linebuf) + 03) & (NBLK-1);
1054 return nl;
1057 void
1058 blkio(int b, uchar *buf, int isread)
1060 int n;
1062 seek(tfile, b*BLKSIZE, 0);
1063 if(isread)
1064 n = read(tfile, buf, BLKSIZE);
1065 else
1066 n = write(tfile, buf, BLKSIZE);
1067 if(n != BLKSIZE)
1068 error(T);
1071 Rune*
1072 getblock(int atl, int iof)
1074 int bno, off;
1076 static uchar ibuff[BLKSIZE];
1077 static uchar obuff[BLKSIZE];
1079 bno = atl / (BLKSIZE/sizeof(Rune));
1080 off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~03;
1081 if(bno >= NBLK) {
1082 lastc = '\n';
1083 error(T);
1085 nleft = BLKSIZE - off;
1086 if(bno == iblock) {
1087 ichanged |= iof;
1088 return (Rune*)(ibuff+off);
1090 if(bno == oblock)
1091 return (Rune*)(obuff+off);
1092 if(iof == OREAD) {
1093 if(ichanged)
1094 blkio(iblock, ibuff, 0);
1095 ichanged = 0;
1096 iblock = bno;
1097 blkio(bno, ibuff, 1);
1098 return (Rune*)(ibuff+off);
1100 if(oblock >= 0)
1101 blkio(oblock, obuff, 0);
1102 oblock = bno;
1103 return (Rune*)(obuff+off);
1106 void
1107 init(void)
1109 int *markp;
1111 close(tfile);
1112 tline = 2;
1113 for(markp = names; markp < &names[26]; )
1114 *markp++ = 0;
1115 subnewa = 0;
1116 anymarks = 0;
1117 iblock = -1;
1118 oblock = -1;
1119 ichanged = 0;
1120 if((tfile = create(tfname, ORDWR, 0600)) < 0){
1121 error1(T);
1122 exits(0);
1124 dot = dol = zero;
1127 void
1128 global(int k)
1130 Rune *gp, globuf[GBSIZE];
1131 int c, *a1;
1133 if(globp)
1134 error(Q);
1135 setwide();
1136 squeeze(dol > zero);
1137 c = getchr();
1138 if(c == '\n')
1139 error(Q);
1140 compile(c);
1141 gp = globuf;
1142 while((c=getchr()) != '\n') {
1143 if(c == EOF)
1144 error(Q);
1145 if(c == '\\') {
1146 c = getchr();
1147 if(c != '\n')
1148 *gp++ = '\\';
1150 *gp++ = c;
1151 if(gp >= &globuf[GBSIZE-2])
1152 error(Q);
1154 if(gp == globuf)
1155 *gp++ = 'p';
1156 *gp++ = '\n';
1157 *gp = 0;
1158 for(a1=zero; a1<=dol; a1++) {
1159 *a1 &= ~01;
1160 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1161 *a1 |= 01;
1165 * Special case: g/.../d (avoid n^2 algorithm)
1167 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1168 gdelete();
1169 return;
1171 for(a1=zero; a1<=dol; a1++) {
1172 if(*a1 & 01) {
1173 *a1 &= ~01;
1174 dot = a1;
1175 globp = globuf;
1176 commands();
1177 a1 = zero;
1182 void
1183 join(void)
1185 Rune *gp, *lp;
1186 int *a1;
1188 nonzero();
1189 gp = genbuf;
1190 for(a1=addr1; a1<=addr2; a1++) {
1191 lp = getline(*a1);
1192 while(*gp = *lp++)
1193 if(gp++ >= &genbuf[LBSIZE-2])
1194 error(Q);
1196 lp = linebuf;
1197 gp = genbuf;
1198 while(*lp++ = *gp++)
1200 *addr1 = putline();
1201 if(addr1 < addr2)
1202 rdelete(addr1+1, addr2);
1203 dot = addr1;
1206 void
1207 substitute(int inglob)
1209 int *mp, *a1, nl, gsubf, n;
1211 n = getnum(); /* OK even if n==0 */
1212 gsubf = compsub();
1213 for(a1 = addr1; a1 <= addr2; a1++) {
1214 if(match(a1)){
1215 int *ozero;
1216 int m = n;
1218 do {
1219 int span = loc2-loc1;
1221 if(--m <= 0) {
1222 dosub();
1223 if(!gsubf)
1224 break;
1225 if(span == 0) { /* null RE match */
1226 if(*loc2 == 0)
1227 break;
1228 loc2++;
1231 } while(match(0));
1232 if(m <= 0) {
1233 inglob |= 01;
1234 subnewa = putline();
1235 *a1 &= ~01;
1236 if(anymarks) {
1237 for(mp=names; mp<&names[26]; mp++)
1238 if(*mp == *a1)
1239 *mp = subnewa;
1241 subolda = *a1;
1242 *a1 = subnewa;
1243 ozero = zero;
1244 nl = append(getsub, a1);
1245 addr2 += nl;
1246 nl += zero-ozero;
1247 a1 += nl;
1251 if(inglob == 0)
1252 error(Q);
1255 int
1256 compsub(void)
1258 int seof, c;
1259 Rune *p;
1261 seof = getchr();
1262 if(seof == '\n' || seof == ' ')
1263 error(Q);
1264 compile(seof);
1265 p = rhsbuf;
1266 for(;;) {
1267 c = getchr();
1268 if(c == '\\') {
1269 c = getchr();
1270 *p++ = ESCFLG;
1271 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
1272 error(Q);
1273 } else
1274 if(c == '\n' && (!globp || !globp[0])) {
1275 peekc = c;
1276 pflag++;
1277 break;
1278 } else
1279 if(c == seof)
1280 break;
1281 *p++ = c;
1282 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
1283 error(Q);
1285 *p = 0;
1286 peekc = getchr();
1287 if(peekc == 'g') {
1288 peekc = 0;
1289 newline();
1290 return 1;
1292 newline();
1293 return 0;
1296 int
1297 getsub(void)
1299 Rune *p1, *p2;
1301 p1 = linebuf;
1302 if((p2 = linebp) == 0)
1303 return EOF;
1304 while(*p1++ = *p2++)
1306 linebp = 0;
1307 return 0;
1310 void
1311 dosub(void)
1313 Rune *lp, *sp, *rp;
1314 int c, n;
1316 lp = linebuf;
1317 sp = genbuf;
1318 rp = rhsbuf;
1319 while(lp < loc1)
1320 *sp++ = *lp++;
1321 while(c = *rp++) {
1322 if(c == '&'){
1323 sp = place(sp, loc1, loc2);
1324 continue;
1326 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1327 n = c-'0';
1328 if(subexp[n].s.rsp && subexp[n].e.rep) {
1329 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
1330 continue;
1332 error(Q);
1334 *sp++ = c;
1335 if(sp >= &genbuf[LBSIZE])
1336 error(Q);
1338 lp = loc2;
1339 loc2 = sp - genbuf + linebuf;
1340 while(*sp++ = *lp++)
1341 if(sp >= &genbuf[LBSIZE])
1342 error(Q);
1343 lp = linebuf;
1344 sp = genbuf;
1345 while(*lp++ = *sp++)
1349 Rune*
1350 place(Rune *sp, Rune *l1, Rune *l2)
1353 while(l1 < l2) {
1354 *sp++ = *l1++;
1355 if(sp >= &genbuf[LBSIZE])
1356 error(Q);
1358 return sp;
1361 void
1362 move(int cflag)
1364 int *adt, *ad1, *ad2;
1366 nonzero();
1367 if((adt = address())==0) /* address() guarantees addr is in range */
1368 error(Q);
1369 newline();
1370 if(cflag) {
1371 int *ozero, delta;
1372 ad1 = dol;
1373 ozero = zero;
1374 append(getcopy, ad1++);
1375 ad2 = dol;
1376 delta = zero - ozero;
1377 ad1 += delta;
1378 adt += delta;
1379 } else {
1380 ad2 = addr2;
1381 for(ad1 = addr1; ad1 <= ad2;)
1382 *ad1++ &= ~01;
1383 ad1 = addr1;
1385 ad2++;
1386 if(adt<ad1) {
1387 dot = adt + (ad2-ad1);
1388 if((++adt)==ad1)
1389 return;
1390 reverse(adt, ad1);
1391 reverse(ad1, ad2);
1392 reverse(adt, ad2);
1393 } else
1394 if(adt >= ad2) {
1395 dot = adt++;
1396 reverse(ad1, ad2);
1397 reverse(ad2, adt);
1398 reverse(ad1, adt);
1399 } else
1400 error(Q);
1401 fchange = 1;
1404 void
1405 reverse(int *a1, int *a2)
1407 int t;
1409 for(;;) {
1410 t = *--a2;
1411 if(a2 <= a1)
1412 return;
1413 *a2 = *a1;
1414 *a1++ = t;
1418 int
1419 getcopy(void)
1421 if(addr1 > addr2)
1422 return EOF;
1423 getline(*addr1++);
1424 return 0;
1427 void
1428 compile(int eof)
1430 Rune c;
1431 char *ep;
1432 char expbuf[ESIZE];
1434 if((c = getchr()) == '\n') {
1435 peekc = c;
1436 c = eof;
1438 if(c == eof) {
1439 if(!pattern)
1440 error(Q);
1441 return;
1443 if(pattern) {
1444 free(pattern);
1445 pattern = 0;
1447 ep = expbuf;
1448 do {
1449 if(c == '\\') {
1450 if(ep >= expbuf+sizeof(expbuf)) {
1451 error(Q);
1452 return;
1454 ep += runetochar(ep, &c);
1455 if((c = getchr()) == '\n') {
1456 error(Q);
1457 return;
1460 if(ep >= expbuf+sizeof(expbuf)) {
1461 error(Q);
1462 return;
1464 ep += runetochar(ep, &c);
1465 } while((c = getchr()) != eof && c != '\n');
1466 if(c == '\n')
1467 peekc = c;
1468 *ep = 0;
1469 pattern = regcomp(expbuf);
1472 int
1473 match(int *addr)
1475 if(!pattern)
1476 return 0;
1477 if(addr){
1478 if(addr == zero)
1479 return 0;
1480 subexp[0].s.rsp = getline(*addr);
1481 } else
1482 subexp[0].s.rsp = loc2;
1483 subexp[0].e.rep = 0;
1484 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1485 loc1 = subexp[0].s.rsp;
1486 loc2 = subexp[0].e.rep;
1487 return 1;
1489 loc1 = loc2 = 0;
1490 return 0;
1494 void
1495 putd(void)
1497 int r;
1499 r = count%10;
1500 count /= 10;
1501 if(count)
1502 putd();
1503 putchr(r + '0');
1506 void
1507 putst(char *sp)
1509 Rune r;
1511 col = 0;
1512 for(;;) {
1513 sp += chartorune(&r, sp);
1514 if(r == 0)
1515 break;
1516 putchr(r);
1518 putchr('\n');
1521 void
1522 putshst(Rune *sp)
1524 col = 0;
1525 while(*sp)
1526 putchr(*sp++);
1527 putchr('\n');
1530 void
1531 putchr(int ac)
1533 char *lp;
1534 int c;
1535 Rune rune;
1537 lp = linp;
1538 c = ac;
1539 if(listf) {
1540 if(c == '\n') {
1541 if(linp != line && linp[-1] == ' ') {
1542 *lp++ = '\\';
1543 *lp++ = 'n';
1545 } else {
1546 if(col > (72-6-2)) {
1547 col = 8;
1548 *lp++ = '\\';
1549 *lp++ = '\n';
1550 *lp++ = '\t';
1552 col++;
1553 if(c=='\b' || c=='\t' || c=='\\') {
1554 *lp++ = '\\';
1555 if(c == '\b')
1556 c = 'b';
1557 else
1558 if(c == '\t')
1559 c = 't';
1560 col++;
1561 } else
1562 if(c<' ' || c>='\177') {
1563 *lp++ = '\\';
1564 *lp++ = 'x';
1565 *lp++ = hex[c>>12];
1566 *lp++ = hex[c>>8&0xF];
1567 *lp++ = hex[c>>4&0xF];
1568 c = hex[c&0xF];
1569 col += 5;
1574 rune = c;
1575 lp += runetochar(lp, &rune);
1577 if(c == '\n' || lp >= &line[sizeof(line)-5]) {
1578 linp = line;
1579 write(oflag? 2: 1, line, lp-line);
1580 return;
1582 linp = lp;
1585 char*
1586 mktemp(char *as)
1588 char *s;
1589 unsigned pid;
1590 int i;
1592 pid = getpid();
1593 s = as;
1594 while(*s++)
1596 s--;
1597 while(*--s == 'X') {
1598 *s = pid % 10 + '0';
1599 pid /= 10;
1601 s++;
1602 i = 'a';
1603 while(access(as, 0) != -1) {
1604 if(i == 'z')
1605 return "/";
1606 *s = i++;
1608 return as;
1611 void
1612 regerror(char *s)
1614 USED(s);
1615 error(Q);