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 = 8191, /* 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/2];
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[] = "/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 = "/fd/1";
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(L'\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(L'\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(L'\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(L'?');
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(L'\n');
691 lastc = '\n';
692 error1(Q);
693 notejmp(a, savej, 0);
695 if(strcmp(s, "hangup") == 0){
696 if(rescuing)
697 noted(NDFLT);
698 rescue();
700 fprint(2, "ed: note: %s\n", s);
701 abort();
704 int
705 getchr(void)
707 char s[UTFmax];
708 int i;
709 Rune r;
711 if(lastc = peekc) {
712 peekc = 0;
713 return lastc;
715 if(globp) {
716 if((lastc=*globp++) != 0)
717 return lastc;
718 globp = 0;
719 return EOF;
721 for(i=0;;) {
722 if(read(0, s+i, 1) <= 0)
723 return lastc = EOF;
724 i++;
725 if(fullrune(s, i))
726 break;
729 chartorune(&r, s);
730 lastc = r;
731 return lastc;
734 int
735 gety(void)
737 int c;
738 Rune *gf, *p;
740 p = linebuf;
741 gf = globp;
742 for(;;) {
743 c = getchr();
744 if(c == '\n') {
745 *p = 0;
746 return 0;
748 if(c == EOF) {
749 if(gf)
750 peekc = c;
751 return c;
753 if(c == 0)
754 continue;
755 *p++ = c;
756 if(p >= &linebuf[LBSIZE-2])
757 error(Q);
759 return 0;
762 int
763 gettty(void)
765 int rc;
767 rc = gety();
768 if(rc)
769 return rc;
770 if(linebuf[0] == '.' && linebuf[1] == 0)
771 return EOF;
772 return 0;
775 int
776 getfile(void)
778 int c;
779 Rune *lp;
781 lp = linebuf;
782 do {
783 c = Bgetrune(&iobuf);
784 if(c < 0) {
785 if(lp > linebuf) {
786 putst("'\\n' appended");
787 c = '\n';
788 } else
789 return EOF;
791 if(lp >= &linebuf[LBSIZE]) {
792 lastc = '\n';
793 error(Q);
795 *lp++ = c;
796 count++;
797 } while(c != '\n');
798 lp[-1] = 0;
799 return 0;
802 void
803 putfile(void)
805 int *a1;
806 Rune *lp;
807 long c;
809 a1 = addr1;
810 do {
811 lp = getline(*a1++);
812 for(;;) {
813 count++;
814 c = *lp++;
815 if(c == 0) {
816 if(Bputrune(&iobuf, '\n') < 0)
817 error(Q);
818 break;
820 if(Bputrune(&iobuf, c) < 0)
821 error(Q);
823 } while(a1 <= addr2);
824 if(Bflush(&iobuf) < 0)
825 error(Q);
828 int
829 append(int (*f)(void), int *a)
831 int *a1, *a2, *rdot, nline, tl;
833 nline = 0;
834 dot = a;
835 while((*f)() == 0) {
836 if((dol-zero) >= nlall) {
837 nlall += 512;
838 a1 = realloc(zero, (nlall+5)*sizeof(int*));
839 if(a1 == 0) {
840 error("MEM?");
841 rescue();
843 tl = a1 - zero; /* relocate pointers */
844 zero += tl;
845 addr1 += tl;
846 addr2 += tl;
847 dol += tl;
848 dot += tl;
850 tl = putline();
851 nline++;
852 a1 = ++dol;
853 a2 = a1+1;
854 rdot = ++dot;
855 while(a1 > rdot)
856 *--a2 = *--a1;
857 *rdot = tl;
859 return nline;
862 void
863 add(int i)
865 if(i && (given || dol > zero)) {
866 addr1--;
867 addr2--;
869 squeeze(0);
870 newline();
871 append(gettty, addr2);
874 void
875 browse(void)
877 int forward, n;
878 static int bformat, bnum; /* 0 */
880 forward = 1;
881 peekc = getchr();
882 if(peekc != '\n'){
883 if(peekc == '-' || peekc == '+') {
884 if(peekc == '-')
885 forward = 0;
886 getchr();
888 n = getnum();
889 if(n > 0)
890 bpagesize = n;
892 newline();
893 if(pflag) {
894 bformat = listf;
895 bnum = listn;
896 } else {
897 listf = bformat;
898 listn = bnum;
900 if(forward) {
901 addr1 = addr2;
902 addr2 += bpagesize;
903 if(addr2 > dol)
904 addr2 = dol;
905 } else {
906 addr1 = addr2-bpagesize;
907 if(addr1 <= zero)
908 addr1 = zero+1;
910 printcom();
913 void
914 callunix(void)
916 int c, pid;
917 Rune rune;
918 char buf[512];
919 char *p;
921 setnoaddr();
922 p = buf;
923 while((c=getchr()) != EOF && c != '\n')
924 if(p < &buf[sizeof(buf) - 6]) {
925 rune = c;
926 p += runetochar(p, &rune);
928 *p = 0;
929 pid = fork();
930 if(pid == 0) {
931 execl("/bin/rc", "rc", "-c", buf, 0);
932 exits("execl failed");
934 waiting = 1;
935 while(waitpid() != pid)
937 waiting = 0;
938 if(vflag)
939 putst("!");
942 void
943 quit(void)
945 if(vflag && fchange && dol!=zero) {
946 fchange = 0;
947 error(Q);
949 remove(tfname);
950 exits(0);
953 void
954 onquit(int sig)
956 USED(sig);
957 quit();
960 void
961 rdelete(int *ad1, int *ad2)
963 int *a1, *a2, *a3;
965 a1 = ad1;
966 a2 = ad2+1;
967 a3 = dol;
968 dol -= a2 - a1;
969 do {
970 *a1++ = *a2++;
971 } while(a2 <= a3);
972 a1 = ad1;
973 if(a1 > dol)
974 a1 = dol;
975 dot = a1;
976 fchange = 1;
979 void
980 gdelete(void)
982 int *a1, *a2, *a3;
984 a3 = dol;
985 for(a1=zero; (*a1&01)==0; a1++)
986 if(a1>=a3)
987 return;
988 for(a2=a1+1; a2<=a3;) {
989 if(*a2 & 01) {
990 a2++;
991 dot = a1;
992 } else
993 *a1++ = *a2++;
995 dol = a1-1;
996 if(dot > dol)
997 dot = dol;
998 fchange = 1;
1001 Rune*
1002 getline(int tl)
1004 Rune *lp, *bp;
1005 int nl;
1007 lp = linebuf;
1008 bp = getblock(tl, OREAD);
1009 nl = nleft;
1010 tl &= ~((BLKSIZE/2) - 1);
1011 while(*lp++ = *bp++) {
1012 nl -= sizeof(Rune);
1013 if(nl == 0) {
1014 bp = getblock(tl += BLKSIZE/2, OREAD);
1015 nl = nleft;
1018 return linebuf;
1021 int
1022 putline(void)
1024 Rune *lp, *bp;
1025 int nl, tl;
1027 fchange = 1;
1028 lp = linebuf;
1029 tl = tline;
1030 bp = getblock(tl, OWRITE);
1031 nl = nleft;
1032 tl &= ~((BLKSIZE/2)-1);
1033 while(*bp = *lp++) {
1034 if(*bp++ == '\n') {
1035 bp[-1] = 0;
1036 linebp = lp;
1037 break;
1039 nl -= sizeof(Rune);
1040 if(nl == 0) {
1041 tl += BLKSIZE/2;
1042 bp = getblock(tl, OWRITE);
1043 nl = nleft;
1046 nl = tline;
1047 tline += ((lp-linebuf) + 03) & 077776;
1048 return nl;
1051 void
1052 blkio(int b, uchar *buf, int isread)
1054 int n;
1056 seek(tfile, b*BLKSIZE, 0);
1057 if(isread)
1058 n = read(tfile, buf, BLKSIZE);
1059 else
1060 n = write(tfile, buf, BLKSIZE);
1061 if(n != BLKSIZE)
1062 error(T);
1065 Rune*
1066 getblock(int atl, int iof)
1068 int bno, off;
1070 static uchar ibuff[BLKSIZE];
1071 static uchar obuff[BLKSIZE];
1073 bno = atl / (BLKSIZE/2);
1074 off = (atl<<1) & (BLKSIZE-1) & ~03;
1075 if(bno >= NBLK) {
1076 lastc = '\n';
1077 error(T);
1079 nleft = BLKSIZE - off;
1080 if(bno == iblock) {
1081 ichanged |= iof;
1082 return (Rune*)(ibuff+off);
1084 if(bno == oblock)
1085 return (Rune*)(obuff+off);
1086 if(iof == OREAD) {
1087 if(ichanged)
1088 blkio(iblock, ibuff, 0);
1089 ichanged = 0;
1090 iblock = bno;
1091 blkio(bno, ibuff, 1);
1092 return (Rune*)(ibuff+off);
1094 if(oblock >= 0)
1095 blkio(oblock, obuff, 0);
1096 oblock = bno;
1097 return (Rune*)(obuff+off);
1100 void
1101 init(void)
1103 int *markp;
1105 close(tfile);
1106 tline = 2;
1107 for(markp = names; markp < &names[26]; )
1108 *markp++ = 0;
1109 subnewa = 0;
1110 anymarks = 0;
1111 iblock = -1;
1112 oblock = -1;
1113 ichanged = 0;
1114 if((tfile = create(tfname, ORDWR, 0600)) < 0){
1115 error1(T);
1116 exits(0);
1118 dot = dol = zero;
1121 void
1122 global(int k)
1124 Rune *gp, globuf[GBSIZE];
1125 int c, *a1;
1127 if(globp)
1128 error(Q);
1129 setwide();
1130 squeeze(dol > zero);
1131 c = getchr();
1132 if(c == '\n')
1133 error(Q);
1134 compile(c);
1135 gp = globuf;
1136 while((c=getchr()) != '\n') {
1137 if(c == EOF)
1138 error(Q);
1139 if(c == '\\') {
1140 c = getchr();
1141 if(c != '\n')
1142 *gp++ = '\\';
1144 *gp++ = c;
1145 if(gp >= &globuf[GBSIZE-2])
1146 error(Q);
1148 if(gp == globuf)
1149 *gp++ = 'p';
1150 *gp++ = '\n';
1151 *gp = 0;
1152 for(a1=zero; a1<=dol; a1++) {
1153 *a1 &= ~01;
1154 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1155 *a1 |= 01;
1159 * Special case: g/.../d (avoid n^2 algorithm)
1161 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1162 gdelete();
1163 return;
1165 for(a1=zero; a1<=dol; a1++) {
1166 if(*a1 & 01) {
1167 *a1 &= ~01;
1168 dot = a1;
1169 globp = globuf;
1170 commands();
1171 a1 = zero;
1176 void
1177 join(void)
1179 Rune *gp, *lp;
1180 int *a1;
1182 nonzero();
1183 gp = genbuf;
1184 for(a1=addr1; a1<=addr2; a1++) {
1185 lp = getline(*a1);
1186 while(*gp = *lp++)
1187 if(gp++ >= &genbuf[LBSIZE-2])
1188 error(Q);
1190 lp = linebuf;
1191 gp = genbuf;
1192 while(*lp++ = *gp++)
1194 *addr1 = putline();
1195 if(addr1 < addr2)
1196 rdelete(addr1+1, addr2);
1197 dot = addr1;
1200 void
1201 substitute(int inglob)
1203 int *mp, *a1, nl, gsubf, n;
1205 n = getnum(); /* OK even if n==0 */
1206 gsubf = compsub();
1207 for(a1 = addr1; a1 <= addr2; a1++) {
1208 if(match(a1)){
1209 int *ozero;
1210 int m = n;
1212 do {
1213 int span = loc2-loc1;
1215 if(--m <= 0) {
1216 dosub();
1217 if(!gsubf)
1218 break;
1219 if(span == 0) { /* null RE match */
1220 if(*loc2 == 0)
1221 break;
1222 loc2++;
1225 } while(match(0));
1226 if(m <= 0) {
1227 inglob |= 01;
1228 subnewa = putline();
1229 *a1 &= ~01;
1230 if(anymarks) {
1231 for(mp=names; mp<&names[26]; mp++)
1232 if(*mp == *a1)
1233 *mp = subnewa;
1235 subolda = *a1;
1236 *a1 = subnewa;
1237 ozero = zero;
1238 nl = append(getsub, a1);
1239 addr2 += nl;
1240 nl += zero-ozero;
1241 a1 += nl;
1245 if(inglob == 0)
1246 error(Q);
1249 int
1250 compsub(void)
1252 int seof, c;
1253 Rune *p;
1255 seof = getchr();
1256 if(seof == '\n' || seof == ' ')
1257 error(Q);
1258 compile(seof);
1259 p = rhsbuf;
1260 for(;;) {
1261 c = getchr();
1262 if(c == '\\') {
1263 c = getchr();
1264 *p++ = ESCFLG;
1265 if(p >= &rhsbuf[LBSIZE/2])
1266 error(Q);
1267 } else
1268 if(c == '\n' && (!globp || !globp[0])) {
1269 peekc = c;
1270 pflag++;
1271 break;
1272 } else
1273 if(c == seof)
1274 break;
1275 *p++ = c;
1276 if(p >= &rhsbuf[LBSIZE/2])
1277 error(Q);
1279 *p = 0;
1280 peekc = getchr();
1281 if(peekc == 'g') {
1282 peekc = 0;
1283 newline();
1284 return 1;
1286 newline();
1287 return 0;
1290 int
1291 getsub(void)
1293 Rune *p1, *p2;
1295 p1 = linebuf;
1296 if((p2 = linebp) == 0)
1297 return EOF;
1298 while(*p1++ = *p2++)
1300 linebp = 0;
1301 return 0;
1304 void
1305 dosub(void)
1307 Rune *lp, *sp, *rp;
1308 int c, n;
1310 lp = linebuf;
1311 sp = genbuf;
1312 rp = rhsbuf;
1313 while(lp < loc1)
1314 *sp++ = *lp++;
1315 while(c = *rp++) {
1316 if(c == '&'){
1317 sp = place(sp, loc1, loc2);
1318 continue;
1320 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1321 n = c-'0';
1322 if(subexp[n].s.rsp && subexp[n].e.rep) {
1323 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
1324 continue;
1326 error(Q);
1328 *sp++ = c;
1329 if(sp >= &genbuf[LBSIZE])
1330 error(Q);
1332 lp = loc2;
1333 loc2 = sp - genbuf + linebuf;
1334 while(*sp++ = *lp++)
1335 if(sp >= &genbuf[LBSIZE])
1336 error(Q);
1337 lp = linebuf;
1338 sp = genbuf;
1339 while(*lp++ = *sp++)
1343 Rune*
1344 place(Rune *sp, Rune *l1, Rune *l2)
1347 while(l1 < l2) {
1348 *sp++ = *l1++;
1349 if(sp >= &genbuf[LBSIZE])
1350 error(Q);
1352 return sp;
1355 void
1356 move(int cflag)
1358 int *adt, *ad1, *ad2;
1360 nonzero();
1361 if((adt = address())==0) /* address() guarantees addr is in range */
1362 error(Q);
1363 newline();
1364 if(cflag) {
1365 int *ozero, delta;
1366 ad1 = dol;
1367 ozero = zero;
1368 append(getcopy, ad1++);
1369 ad2 = dol;
1370 delta = zero - ozero;
1371 ad1 += delta;
1372 adt += delta;
1373 } else {
1374 ad2 = addr2;
1375 for(ad1 = addr1; ad1 <= ad2;)
1376 *ad1++ &= ~01;
1377 ad1 = addr1;
1379 ad2++;
1380 if(adt<ad1) {
1381 dot = adt + (ad2-ad1);
1382 if((++adt)==ad1)
1383 return;
1384 reverse(adt, ad1);
1385 reverse(ad1, ad2);
1386 reverse(adt, ad2);
1387 } else
1388 if(adt >= ad2) {
1389 dot = adt++;
1390 reverse(ad1, ad2);
1391 reverse(ad2, adt);
1392 reverse(ad1, adt);
1393 } else
1394 error(Q);
1395 fchange = 1;
1398 void
1399 reverse(int *a1, int *a2)
1401 int t;
1403 for(;;) {
1404 t = *--a2;
1405 if(a2 <= a1)
1406 return;
1407 *a2 = *a1;
1408 *a1++ = t;
1412 int
1413 getcopy(void)
1415 if(addr1 > addr2)
1416 return EOF;
1417 getline(*addr1++);
1418 return 0;
1421 void
1422 compile(int eof)
1424 Rune c;
1425 char *ep;
1426 char expbuf[ESIZE];
1428 if((c = getchr()) == '\n') {
1429 peekc = c;
1430 c = eof;
1432 if(c == eof) {
1433 if(!pattern)
1434 error(Q);
1435 return;
1437 if(pattern) {
1438 free(pattern);
1439 pattern = 0;
1441 ep = expbuf;
1442 do {
1443 if(c == '\\') {
1444 if(ep >= expbuf+sizeof(expbuf)) {
1445 error(Q);
1446 return;
1448 ep += runetochar(ep, &c);
1449 if((c = getchr()) == '\n') {
1450 error(Q);
1451 return;
1454 if(ep >= expbuf+sizeof(expbuf)) {
1455 error(Q);
1456 return;
1458 ep += runetochar(ep, &c);
1459 } while((c = getchr()) != eof && c != '\n');
1460 if(c == '\n')
1461 peekc = c;
1462 *ep = 0;
1463 pattern = regcomp(expbuf);
1466 int
1467 match(int *addr)
1469 if(!pattern)
1470 return 0;
1471 if(addr){
1472 if(addr == zero)
1473 return 0;
1474 subexp[0].s.rsp = getline(*addr);
1475 } else
1476 subexp[0].s.rsp = loc2;
1477 subexp[0].e.rep = 0;
1478 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1479 loc1 = subexp[0].s.rsp;
1480 loc2 = subexp[0].e.rep;
1481 return 1;
1483 loc1 = loc2 = 0;
1484 return 0;
1488 void
1489 putd(void)
1491 int r;
1493 r = count%10;
1494 count /= 10;
1495 if(count)
1496 putd();
1497 putchr(r + L'0');
1500 void
1501 putst(char *sp)
1503 Rune r;
1505 col = 0;
1506 for(;;) {
1507 sp += chartorune(&r, sp);
1508 if(r == 0)
1509 break;
1510 putchr(r);
1512 putchr(L'\n');
1515 void
1516 putshst(Rune *sp)
1518 col = 0;
1519 while(*sp)
1520 putchr(*sp++);
1521 putchr(L'\n');
1524 void
1525 putchr(int ac)
1527 char *lp;
1528 int c;
1529 Rune rune;
1531 lp = linp;
1532 c = ac;
1533 if(listf) {
1534 if(c == '\n') {
1535 if(linp != line && linp[-1] == ' ') {
1536 *lp++ = '\\';
1537 *lp++ = 'n';
1539 } else {
1540 if(col > (72-6-2)) {
1541 col = 8;
1542 *lp++ = '\\';
1543 *lp++ = '\n';
1544 *lp++ = '\t';
1546 col++;
1547 if(c=='\b' || c=='\t' || c=='\\') {
1548 *lp++ = '\\';
1549 if(c == '\b')
1550 c = 'b';
1551 else
1552 if(c == '\t')
1553 c = 't';
1554 col++;
1555 } else
1556 if(c<' ' || c>='\177') {
1557 *lp++ = '\\';
1558 *lp++ = 'x';
1559 *lp++ = hex[c>>12];
1560 *lp++ = hex[c>>8&0xF];
1561 *lp++ = hex[c>>4&0xF];
1562 c = hex[c&0xF];
1563 col += 5;
1568 rune = c;
1569 lp += runetochar(lp, &rune);
1571 if(c == '\n' || lp >= &line[sizeof(line)-5]) {
1572 linp = line;
1573 write(oflag? 2: 1, line, lp-line);
1574 return;
1576 linp = lp;
1579 char*
1580 mktemp(char *as)
1582 char *s;
1583 unsigned pid;
1584 int i;
1586 pid = getpid();
1587 s = as;
1588 while(*s++)
1590 s--;
1591 while(*--s == 'X') {
1592 *s = pid % 10 + '0';
1593 pid /= 10;
1595 s++;
1596 i = 'a';
1597 while(access(as, 0) != -1) {
1598 if(i == 'z')
1599 return "/";
1600 *s = i++;
1602 return as;
1605 void
1606 regerror(char *s)
1608 USED(s);
1609 error(Q);