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 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);
761 return 0;
764 int
765 gettty(void)
767 int rc;
769 rc = gety();
770 if(rc)
771 return rc;
772 if(linebuf[0] == '.' && linebuf[1] == 0)
773 return EOF;
774 return 0;
777 int
778 getfile(void)
780 int c;
781 Rune *lp;
783 lp = linebuf;
784 do {
785 c = Bgetrune(&iobuf);
786 if(c < 0) {
787 if(lp > linebuf) {
788 putst("'\\n' appended");
789 c = '\n';
790 } else
791 return EOF;
793 if(lp >= &linebuf[LBSIZE]) {
794 lastc = '\n';
795 error(Q);
797 *lp++ = c;
798 count++;
799 } while(c != '\n');
800 lp[-1] = 0;
801 return 0;
804 void
805 putfile(void)
807 int *a1;
808 Rune *lp;
809 long c;
811 a1 = addr1;
812 do {
813 lp = getline(*a1++);
814 for(;;) {
815 count++;
816 c = *lp++;
817 if(c == 0) {
818 if(Bputrune(&iobuf, '\n') < 0)
819 error(Q);
820 break;
822 if(Bputrune(&iobuf, c) < 0)
823 error(Q);
825 } while(a1 <= addr2);
826 if(Bflush(&iobuf) < 0)
827 error(Q);
830 int
831 append(int (*f)(void), int *a)
833 int *a1, *a2, *rdot, nline, tl;
835 nline = 0;
836 dot = a;
837 while((*f)() == 0) {
838 if((dol-zero) >= nlall) {
839 nlall += 512;
840 a1 = realloc(zero, (nlall+5)*sizeof(int*));
841 if(a1 == 0) {
842 error("MEM?");
843 rescue();
845 tl = a1 - zero; /* relocate pointers */
846 zero += tl;
847 addr1 += tl;
848 addr2 += tl;
849 dol += tl;
850 dot += tl;
852 tl = putline();
853 nline++;
854 a1 = ++dol;
855 a2 = a1+1;
856 rdot = ++dot;
857 while(a1 > rdot)
858 *--a2 = *--a1;
859 *rdot = tl;
861 return nline;
864 void
865 add(int i)
867 if(i && (given || dol > zero)) {
868 addr1--;
869 addr2--;
871 squeeze(0);
872 newline();
873 append(gettty, addr2);
876 void
877 browse(void)
879 int forward, n;
880 static int bformat, bnum; /* 0 */
882 forward = 1;
883 peekc = getchr();
884 if(peekc != '\n'){
885 if(peekc == '-' || peekc == '+') {
886 if(peekc == '-')
887 forward = 0;
888 getchr();
890 n = getnum();
891 if(n > 0)
892 bpagesize = n;
894 newline();
895 if(pflag) {
896 bformat = listf;
897 bnum = listn;
898 } else {
899 listf = bformat;
900 listn = bnum;
902 if(forward) {
903 addr1 = addr2;
904 addr2 += bpagesize;
905 if(addr2 > dol)
906 addr2 = dol;
907 } else {
908 addr1 = addr2-bpagesize;
909 if(addr1 <= zero)
910 addr1 = zero+1;
912 printcom();
915 void
916 callunix(void)
918 int c, pid;
919 Rune rune;
920 char buf[512];
921 char *p;
923 setnoaddr();
924 p = buf;
925 while((c=getchr()) != EOF && c != '\n')
926 if(p < &buf[sizeof(buf) - 6]) {
927 rune = c;
928 p += runetochar(p, &rune);
930 *p = 0;
931 pid = fork();
932 if(pid == 0) {
933 execlp("rc", "rc", "-c", buf, 0);
934 sysfatal("exec failed: %r");
935 exits("execl failed");
937 waiting = 1;
938 while(waitpid() != pid)
940 waiting = 0;
941 if(vflag)
942 putst("!");
945 void
946 quit(void)
948 if(vflag && fchange && dol!=zero) {
949 fchange = 0;
950 error(Q);
952 remove(tfname);
953 exits(0);
956 void
957 onquit(int sig)
959 USED(sig);
960 quit();
963 void
964 rdelete(int *ad1, int *ad2)
966 int *a1, *a2, *a3;
968 a1 = ad1;
969 a2 = ad2+1;
970 a3 = dol;
971 dol -= a2 - a1;
972 do {
973 *a1++ = *a2++;
974 } while(a2 <= a3);
975 a1 = ad1;
976 if(a1 > dol)
977 a1 = dol;
978 dot = a1;
979 fchange = 1;
982 void
983 gdelete(void)
985 int *a1, *a2, *a3;
987 a3 = dol;
988 for(a1=zero; (*a1&01)==0; a1++)
989 if(a1>=a3)
990 return;
991 for(a2=a1+1; a2<=a3;) {
992 if(*a2 & 01) {
993 a2++;
994 dot = a1;
995 } else
996 *a1++ = *a2++;
998 dol = a1-1;
999 if(dot > dol)
1000 dot = dol;
1001 fchange = 1;
1004 Rune*
1005 getline(int tl)
1007 Rune *lp, *bp;
1008 int nl;
1010 lp = linebuf;
1011 bp = getblock(tl, OREAD);
1012 nl = nleft;
1013 tl &= ~((BLKSIZE/2) - 1);
1014 while(*lp++ = *bp++) {
1015 nl -= sizeof(Rune);
1016 if(nl == 0) {
1017 bp = getblock(tl += BLKSIZE/2, OREAD);
1018 nl = nleft;
1021 return linebuf;
1024 int
1025 putline(void)
1027 Rune *lp, *bp;
1028 int nl, tl;
1030 fchange = 1;
1031 lp = linebuf;
1032 tl = tline;
1033 bp = getblock(tl, OWRITE);
1034 nl = nleft;
1035 tl &= ~((BLKSIZE/2)-1);
1036 while(*bp = *lp++) {
1037 if(*bp++ == '\n') {
1038 bp[-1] = 0;
1039 linebp = lp;
1040 break;
1042 nl -= sizeof(Rune);
1043 if(nl == 0) {
1044 tl += BLKSIZE/2;
1045 bp = getblock(tl, OWRITE);
1046 nl = nleft;
1049 nl = tline;
1050 tline += ((lp-linebuf) + 03) & 077776;
1051 return nl;
1054 void
1055 blkio(int b, uchar *buf, int isread)
1057 int n;
1059 seek(tfile, b*BLKSIZE, 0);
1060 if(isread)
1061 n = read(tfile, buf, BLKSIZE);
1062 else
1063 n = write(tfile, buf, BLKSIZE);
1064 if(n != BLKSIZE)
1065 error(T);
1068 Rune*
1069 getblock(int atl, int iof)
1071 int bno, off;
1073 static uchar ibuff[BLKSIZE];
1074 static uchar obuff[BLKSIZE];
1076 bno = atl / (BLKSIZE/2);
1077 off = (atl<<1) & (BLKSIZE-1) & ~03;
1078 if(bno >= NBLK) {
1079 lastc = '\n';
1080 error(T);
1082 nleft = BLKSIZE - off;
1083 if(bno == iblock) {
1084 ichanged |= iof;
1085 return (Rune*)(ibuff+off);
1087 if(bno == oblock)
1088 return (Rune*)(obuff+off);
1089 if(iof == OREAD) {
1090 if(ichanged)
1091 blkio(iblock, ibuff, 0);
1092 ichanged = 0;
1093 iblock = bno;
1094 blkio(bno, ibuff, 1);
1095 return (Rune*)(ibuff+off);
1097 if(oblock >= 0)
1098 blkio(oblock, obuff, 0);
1099 oblock = bno;
1100 return (Rune*)(obuff+off);
1103 void
1104 init(void)
1106 int *markp;
1108 close(tfile);
1109 tline = 2;
1110 for(markp = names; markp < &names[26]; )
1111 *markp++ = 0;
1112 subnewa = 0;
1113 anymarks = 0;
1114 iblock = -1;
1115 oblock = -1;
1116 ichanged = 0;
1117 if((tfile = create(tfname, ORDWR, 0600)) < 0){
1118 error1(T);
1119 exits(0);
1121 dot = dol = zero;
1124 void
1125 global(int k)
1127 Rune *gp, globuf[GBSIZE];
1128 int c, *a1;
1130 if(globp)
1131 error(Q);
1132 setwide();
1133 squeeze(dol > zero);
1134 c = getchr();
1135 if(c == '\n')
1136 error(Q);
1137 compile(c);
1138 gp = globuf;
1139 while((c=getchr()) != '\n') {
1140 if(c == EOF)
1141 error(Q);
1142 if(c == '\\') {
1143 c = getchr();
1144 if(c != '\n')
1145 *gp++ = '\\';
1147 *gp++ = c;
1148 if(gp >= &globuf[GBSIZE-2])
1149 error(Q);
1151 if(gp == globuf)
1152 *gp++ = 'p';
1153 *gp++ = '\n';
1154 *gp = 0;
1155 for(a1=zero; a1<=dol; a1++) {
1156 *a1 &= ~01;
1157 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1158 *a1 |= 01;
1162 * Special case: g/.../d (avoid n^2 algorithm)
1164 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1165 gdelete();
1166 return;
1168 for(a1=zero; a1<=dol; a1++) {
1169 if(*a1 & 01) {
1170 *a1 &= ~01;
1171 dot = a1;
1172 globp = globuf;
1173 commands();
1174 a1 = zero;
1179 void
1180 join(void)
1182 Rune *gp, *lp;
1183 int *a1;
1185 nonzero();
1186 gp = genbuf;
1187 for(a1=addr1; a1<=addr2; a1++) {
1188 lp = getline(*a1);
1189 while(*gp = *lp++)
1190 if(gp++ >= &genbuf[LBSIZE-2])
1191 error(Q);
1193 lp = linebuf;
1194 gp = genbuf;
1195 while(*lp++ = *gp++)
1197 *addr1 = putline();
1198 if(addr1 < addr2)
1199 rdelete(addr1+1, addr2);
1200 dot = addr1;
1203 void
1204 substitute(int inglob)
1206 int *mp, *a1, nl, gsubf, n;
1208 n = getnum(); /* OK even if n==0 */
1209 gsubf = compsub();
1210 for(a1 = addr1; a1 <= addr2; a1++) {
1211 if(match(a1)){
1212 int *ozero;
1213 int m = n;
1215 do {
1216 int span = loc2-loc1;
1218 if(--m <= 0) {
1219 dosub();
1220 if(!gsubf)
1221 break;
1222 if(span == 0) { /* null RE match */
1223 if(*loc2 == 0)
1224 break;
1225 loc2++;
1228 } while(match(0));
1229 if(m <= 0) {
1230 inglob |= 01;
1231 subnewa = putline();
1232 *a1 &= ~01;
1233 if(anymarks) {
1234 for(mp=names; mp<&names[26]; mp++)
1235 if(*mp == *a1)
1236 *mp = subnewa;
1238 subolda = *a1;
1239 *a1 = subnewa;
1240 ozero = zero;
1241 nl = append(getsub, a1);
1242 addr2 += nl;
1243 nl += zero-ozero;
1244 a1 += nl;
1248 if(inglob == 0)
1249 error(Q);
1252 int
1253 compsub(void)
1255 int seof, c;
1256 Rune *p;
1258 seof = getchr();
1259 if(seof == '\n' || seof == ' ')
1260 error(Q);
1261 compile(seof);
1262 p = rhsbuf;
1263 for(;;) {
1264 c = getchr();
1265 if(c == '\\') {
1266 c = getchr();
1267 *p++ = ESCFLG;
1268 if(p >= &rhsbuf[LBSIZE/2])
1269 error(Q);
1270 } else
1271 if(c == '\n' && (!globp || !globp[0])) {
1272 peekc = c;
1273 pflag++;
1274 break;
1275 } else
1276 if(c == seof)
1277 break;
1278 *p++ = c;
1279 if(p >= &rhsbuf[LBSIZE/2])
1280 error(Q);
1282 *p = 0;
1283 peekc = getchr();
1284 if(peekc == 'g') {
1285 peekc = 0;
1286 newline();
1287 return 1;
1289 newline();
1290 return 0;
1293 int
1294 getsub(void)
1296 Rune *p1, *p2;
1298 p1 = linebuf;
1299 if((p2 = linebp) == 0)
1300 return EOF;
1301 while(*p1++ = *p2++)
1303 linebp = 0;
1304 return 0;
1307 void
1308 dosub(void)
1310 Rune *lp, *sp, *rp;
1311 int c, n;
1313 lp = linebuf;
1314 sp = genbuf;
1315 rp = rhsbuf;
1316 while(lp < loc1)
1317 *sp++ = *lp++;
1318 while(c = *rp++) {
1319 if(c == '&'){
1320 sp = place(sp, loc1, loc2);
1321 continue;
1323 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1324 n = c-'0';
1325 if(subexp[n].s.rsp && subexp[n].e.rep) {
1326 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
1327 continue;
1329 error(Q);
1331 *sp++ = c;
1332 if(sp >= &genbuf[LBSIZE])
1333 error(Q);
1335 lp = loc2;
1336 loc2 = sp - genbuf + linebuf;
1337 while(*sp++ = *lp++)
1338 if(sp >= &genbuf[LBSIZE])
1339 error(Q);
1340 lp = linebuf;
1341 sp = genbuf;
1342 while(*lp++ = *sp++)
1346 Rune*
1347 place(Rune *sp, Rune *l1, Rune *l2)
1350 while(l1 < l2) {
1351 *sp++ = *l1++;
1352 if(sp >= &genbuf[LBSIZE])
1353 error(Q);
1355 return sp;
1358 void
1359 move(int cflag)
1361 int *adt, *ad1, *ad2;
1363 nonzero();
1364 if((adt = address())==0) /* address() guarantees addr is in range */
1365 error(Q);
1366 newline();
1367 if(cflag) {
1368 int *ozero, delta;
1369 ad1 = dol;
1370 ozero = zero;
1371 append(getcopy, ad1++);
1372 ad2 = dol;
1373 delta = zero - ozero;
1374 ad1 += delta;
1375 adt += delta;
1376 } else {
1377 ad2 = addr2;
1378 for(ad1 = addr1; ad1 <= ad2;)
1379 *ad1++ &= ~01;
1380 ad1 = addr1;
1382 ad2++;
1383 if(adt<ad1) {
1384 dot = adt + (ad2-ad1);
1385 if((++adt)==ad1)
1386 return;
1387 reverse(adt, ad1);
1388 reverse(ad1, ad2);
1389 reverse(adt, ad2);
1390 } else
1391 if(adt >= ad2) {
1392 dot = adt++;
1393 reverse(ad1, ad2);
1394 reverse(ad2, adt);
1395 reverse(ad1, adt);
1396 } else
1397 error(Q);
1398 fchange = 1;
1401 void
1402 reverse(int *a1, int *a2)
1404 int t;
1406 for(;;) {
1407 t = *--a2;
1408 if(a2 <= a1)
1409 return;
1410 *a2 = *a1;
1411 *a1++ = t;
1415 int
1416 getcopy(void)
1418 if(addr1 > addr2)
1419 return EOF;
1420 getline(*addr1++);
1421 return 0;
1424 void
1425 compile(int eof)
1427 Rune c;
1428 char *ep;
1429 char expbuf[ESIZE];
1431 if((c = getchr()) == '\n') {
1432 peekc = c;
1433 c = eof;
1435 if(c == eof) {
1436 if(!pattern)
1437 error(Q);
1438 return;
1440 if(pattern) {
1441 free(pattern);
1442 pattern = 0;
1444 ep = expbuf;
1445 do {
1446 if(c == '\\') {
1447 if(ep >= expbuf+sizeof(expbuf)) {
1448 error(Q);
1449 return;
1451 ep += runetochar(ep, &c);
1452 if((c = getchr()) == '\n') {
1453 error(Q);
1454 return;
1457 if(ep >= expbuf+sizeof(expbuf)) {
1458 error(Q);
1459 return;
1461 ep += runetochar(ep, &c);
1462 } while((c = getchr()) != eof && c != '\n');
1463 if(c == '\n')
1464 peekc = c;
1465 *ep = 0;
1466 pattern = regcomp(expbuf);
1469 int
1470 match(int *addr)
1472 if(!pattern)
1473 return 0;
1474 if(addr){
1475 if(addr == zero)
1476 return 0;
1477 subexp[0].s.rsp = getline(*addr);
1478 } else
1479 subexp[0].s.rsp = loc2;
1480 subexp[0].e.rep = 0;
1481 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1482 loc1 = subexp[0].s.rsp;
1483 loc2 = subexp[0].e.rep;
1484 return 1;
1486 loc1 = loc2 = 0;
1487 return 0;
1491 void
1492 putd(void)
1494 int r;
1496 r = count%10;
1497 count /= 10;
1498 if(count)
1499 putd();
1500 putchr(r + L'0');
1503 void
1504 putst(char *sp)
1506 Rune r;
1508 col = 0;
1509 for(;;) {
1510 sp += chartorune(&r, sp);
1511 if(r == 0)
1512 break;
1513 putchr(r);
1515 putchr(L'\n');
1518 void
1519 putshst(Rune *sp)
1521 col = 0;
1522 while(*sp)
1523 putchr(*sp++);
1524 putchr(L'\n');
1527 void
1528 putchr(int ac)
1530 char *lp;
1531 int c;
1532 Rune rune;
1534 lp = linp;
1535 c = ac;
1536 if(listf) {
1537 if(c == '\n') {
1538 if(linp != line && linp[-1] == ' ') {
1539 *lp++ = '\\';
1540 *lp++ = 'n';
1542 } else {
1543 if(col > (72-6-2)) {
1544 col = 8;
1545 *lp++ = '\\';
1546 *lp++ = '\n';
1547 *lp++ = '\t';
1549 col++;
1550 if(c=='\b' || c=='\t' || c=='\\') {
1551 *lp++ = '\\';
1552 if(c == '\b')
1553 c = 'b';
1554 else
1555 if(c == '\t')
1556 c = 't';
1557 col++;
1558 } else
1559 if(c<' ' || c>='\177') {
1560 *lp++ = '\\';
1561 *lp++ = 'x';
1562 *lp++ = hex[c>>12];
1563 *lp++ = hex[c>>8&0xF];
1564 *lp++ = hex[c>>4&0xF];
1565 c = hex[c&0xF];
1566 col += 5;
1571 rune = c;
1572 lp += runetochar(lp, &rune);
1574 if(c == '\n' || lp >= &line[sizeof(line)-5]) {
1575 linp = line;
1576 write(oflag? 2: 1, line, lp-line);
1577 return;
1579 linp = lp;
1582 char*
1583 mktemp(char *as)
1585 char *s;
1586 unsigned pid;
1587 int i;
1589 pid = getpid();
1590 s = as;
1591 while(*s++)
1593 s--;
1594 while(*--s == 'X') {
1595 *s = pid % 10 + '0';
1596 pid /= 10;
1598 s++;
1599 i = 'a';
1600 while(access(as, 0) != -1) {
1601 if(i == 'z')
1602 return "/";
1603 *s = i++;
1605 return as;
1608 void
1609 regerror(char *s)
1611 USED(s);
1612 error(Q);