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 = "/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){
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, tl;
834 nline = 0;
835 dot = a;
836 while((*f)() == 0) {
837 if((dol-zero) >= nlall) {
838 nlall += 512;
839 a1 = realloc(zero, (nlall+5)*sizeof(int*));
840 if(a1 == 0) {
841 error("MEM?");
842 rescue();
844 tl = a1 - zero; /* relocate pointers */
845 zero += tl;
846 addr1 += tl;
847 addr2 += tl;
848 dol += tl;
849 dot += tl;
851 tl = putline();
852 nline++;
853 a1 = ++dol;
854 a2 = a1+1;
855 rdot = ++dot;
856 while(a1 > rdot)
857 *--a2 = *--a1;
858 *rdot = tl;
860 return nline;
863 void
864 add(int i)
866 if(i && (given || dol > zero)) {
867 addr1--;
868 addr2--;
870 squeeze(0);
871 newline();
872 append(gettty, addr2);
875 void
876 browse(void)
878 int forward, n;
879 static int bformat, bnum; /* 0 */
881 forward = 1;
882 peekc = getchr();
883 if(peekc != '\n'){
884 if(peekc == '-' || peekc == '+') {
885 if(peekc == '-')
886 forward = 0;
887 getchr();
889 n = getnum();
890 if(n > 0)
891 bpagesize = n;
893 newline();
894 if(pflag) {
895 bformat = listf;
896 bnum = listn;
897 } else {
898 listf = bformat;
899 listn = bnum;
901 if(forward) {
902 addr1 = addr2;
903 addr2 += bpagesize;
904 if(addr2 > dol)
905 addr2 = dol;
906 } else {
907 addr1 = addr2-bpagesize;
908 if(addr1 <= zero)
909 addr1 = zero+1;
911 printcom();
914 void
915 callunix(void)
917 int c, pid;
918 Rune rune;
919 char buf[512];
920 char *p;
922 setnoaddr();
923 p = buf;
924 while((c=getchr()) != EOF && c != '\n')
925 if(p < &buf[sizeof(buf) - 6]) {
926 rune = c;
927 p += runetochar(p, &rune);
929 *p = 0;
930 pid = fork();
931 if(pid == 0) {
932 execlp("rc", "rc", "-c", buf, (char*)0);
933 sysfatal("exec failed: %r");
934 exits("execl failed");
936 waiting = 1;
937 while(waitpid() != pid)
939 waiting = 0;
940 if(vflag)
941 putst("!");
944 void
945 quit(void)
947 if(vflag && fchange && dol!=zero) {
948 fchange = 0;
949 error(Q);
951 remove(tfname);
952 exits(0);
955 void
956 onquit(int sig)
958 USED(sig);
959 quit();
962 void
963 rdelete(int *ad1, int *ad2)
965 int *a1, *a2, *a3;
967 a1 = ad1;
968 a2 = ad2+1;
969 a3 = dol;
970 dol -= a2 - a1;
971 do {
972 *a1++ = *a2++;
973 } while(a2 <= a3);
974 a1 = ad1;
975 if(a1 > dol)
976 a1 = dol;
977 dot = a1;
978 fchange = 1;
981 void
982 gdelete(void)
984 int *a1, *a2, *a3;
986 a3 = dol;
987 for(a1=zero; (*a1&01)==0; a1++)
988 if(a1>=a3)
989 return;
990 for(a2=a1+1; a2<=a3;) {
991 if(*a2 & 01) {
992 a2++;
993 dot = a1;
994 } else
995 *a1++ = *a2++;
997 dol = a1-1;
998 if(dot > dol)
999 dot = dol;
1000 fchange = 1;
1003 Rune*
1004 getline(int tl)
1006 Rune *lp, *bp;
1007 int nl;
1009 lp = linebuf;
1010 bp = getblock(tl, OREAD);
1011 nl = nleft;
1012 tl &= ~((BLKSIZE/2) - 1);
1013 while(*lp++ = *bp++) {
1014 nl -= sizeof(Rune);
1015 if(nl == 0) {
1016 bp = getblock(tl += BLKSIZE/2, OREAD);
1017 nl = nleft;
1020 return linebuf;
1023 int
1024 putline(void)
1026 Rune *lp, *bp;
1027 int nl, tl;
1029 fchange = 1;
1030 lp = linebuf;
1031 tl = tline;
1032 bp = getblock(tl, OWRITE);
1033 nl = nleft;
1034 tl &= ~((BLKSIZE/2)-1);
1035 while(*bp = *lp++) {
1036 if(*bp++ == '\n') {
1037 bp[-1] = 0;
1038 linebp = lp;
1039 break;
1041 nl -= sizeof(Rune);
1042 if(nl == 0) {
1043 tl += BLKSIZE/2;
1044 bp = getblock(tl, OWRITE);
1045 nl = nleft;
1048 nl = tline;
1049 tline += ((lp-linebuf) + 03) & 077776;
1050 return nl;
1053 void
1054 blkio(int b, uchar *buf, int isread)
1056 int n;
1058 seek(tfile, b*BLKSIZE, 0);
1059 if(isread)
1060 n = read(tfile, buf, BLKSIZE);
1061 else
1062 n = write(tfile, buf, BLKSIZE);
1063 if(n != BLKSIZE)
1064 error(T);
1067 Rune*
1068 getblock(int atl, int iof)
1070 int bno, off;
1072 static uchar ibuff[BLKSIZE];
1073 static uchar obuff[BLKSIZE];
1075 bno = atl / (BLKSIZE/2);
1076 off = (atl<<1) & (BLKSIZE-1) & ~03;
1077 if(bno >= NBLK) {
1078 lastc = '\n';
1079 error(T);
1081 nleft = BLKSIZE - off;
1082 if(bno == iblock) {
1083 ichanged |= iof;
1084 return (Rune*)(ibuff+off);
1086 if(bno == oblock)
1087 return (Rune*)(obuff+off);
1088 if(iof == OREAD) {
1089 if(ichanged)
1090 blkio(iblock, ibuff, 0);
1091 ichanged = 0;
1092 iblock = bno;
1093 blkio(bno, ibuff, 1);
1094 return (Rune*)(ibuff+off);
1096 if(oblock >= 0)
1097 blkio(oblock, obuff, 0);
1098 oblock = bno;
1099 return (Rune*)(obuff+off);
1102 void
1103 init(void)
1105 int *markp;
1107 close(tfile);
1108 tline = 2;
1109 for(markp = names; markp < &names[26]; )
1110 *markp++ = 0;
1111 subnewa = 0;
1112 anymarks = 0;
1113 iblock = -1;
1114 oblock = -1;
1115 ichanged = 0;
1116 if((tfile = create(tfname, ORDWR, 0600)) < 0){
1117 error1(T);
1118 exits(0);
1120 dot = dol = zero;
1123 void
1124 global(int k)
1126 Rune *gp, globuf[GBSIZE];
1127 int c, *a1;
1129 if(globp)
1130 error(Q);
1131 setwide();
1132 squeeze(dol > zero);
1133 c = getchr();
1134 if(c == '\n')
1135 error(Q);
1136 compile(c);
1137 gp = globuf;
1138 while((c=getchr()) != '\n') {
1139 if(c == EOF)
1140 error(Q);
1141 if(c == '\\') {
1142 c = getchr();
1143 if(c != '\n')
1144 *gp++ = '\\';
1146 *gp++ = c;
1147 if(gp >= &globuf[GBSIZE-2])
1148 error(Q);
1150 if(gp == globuf)
1151 *gp++ = 'p';
1152 *gp++ = '\n';
1153 *gp = 0;
1154 for(a1=zero; a1<=dol; a1++) {
1155 *a1 &= ~01;
1156 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1157 *a1 |= 01;
1161 * Special case: g/.../d (avoid n^2 algorithm)
1163 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1164 gdelete();
1165 return;
1167 for(a1=zero; a1<=dol; a1++) {
1168 if(*a1 & 01) {
1169 *a1 &= ~01;
1170 dot = a1;
1171 globp = globuf;
1172 commands();
1173 a1 = zero;
1178 void
1179 join(void)
1181 Rune *gp, *lp;
1182 int *a1;
1184 nonzero();
1185 gp = genbuf;
1186 for(a1=addr1; a1<=addr2; a1++) {
1187 lp = getline(*a1);
1188 while(*gp = *lp++)
1189 if(gp++ >= &genbuf[LBSIZE-2])
1190 error(Q);
1192 lp = linebuf;
1193 gp = genbuf;
1194 while(*lp++ = *gp++)
1196 *addr1 = putline();
1197 if(addr1 < addr2)
1198 rdelete(addr1+1, addr2);
1199 dot = addr1;
1202 void
1203 substitute(int inglob)
1205 int *mp, *a1, nl, gsubf, n;
1207 n = getnum(); /* OK even if n==0 */
1208 gsubf = compsub();
1209 for(a1 = addr1; a1 <= addr2; a1++) {
1210 if(match(a1)){
1211 int *ozero;
1212 int m = n;
1214 do {
1215 int span = loc2-loc1;
1217 if(--m <= 0) {
1218 dosub();
1219 if(!gsubf)
1220 break;
1221 if(span == 0) { /* null RE match */
1222 if(*loc2 == 0)
1223 break;
1224 loc2++;
1227 } while(match(0));
1228 if(m <= 0) {
1229 inglob |= 01;
1230 subnewa = putline();
1231 *a1 &= ~01;
1232 if(anymarks) {
1233 for(mp=names; mp<&names[26]; mp++)
1234 if(*mp == *a1)
1235 *mp = subnewa;
1237 subolda = *a1;
1238 *a1 = subnewa;
1239 ozero = zero;
1240 nl = append(getsub, a1);
1241 addr2 += nl;
1242 nl += zero-ozero;
1243 a1 += nl;
1247 if(inglob == 0)
1248 error(Q);
1251 int
1252 compsub(void)
1254 int seof, c;
1255 Rune *p;
1257 seof = getchr();
1258 if(seof == '\n' || seof == ' ')
1259 error(Q);
1260 compile(seof);
1261 p = rhsbuf;
1262 for(;;) {
1263 c = getchr();
1264 if(c == '\\') {
1265 c = getchr();
1266 *p++ = ESCFLG;
1267 if(p >= &rhsbuf[LBSIZE/2])
1268 error(Q);
1269 } else
1270 if(c == '\n' && (!globp || !globp[0])) {
1271 peekc = c;
1272 pflag++;
1273 break;
1274 } else
1275 if(c == seof)
1276 break;
1277 *p++ = c;
1278 if(p >= &rhsbuf[LBSIZE/2])
1279 error(Q);
1281 *p = 0;
1282 peekc = getchr();
1283 if(peekc == 'g') {
1284 peekc = 0;
1285 newline();
1286 return 1;
1288 newline();
1289 return 0;
1292 int
1293 getsub(void)
1295 Rune *p1, *p2;
1297 p1 = linebuf;
1298 if((p2 = linebp) == 0)
1299 return EOF;
1300 while(*p1++ = *p2++)
1302 linebp = 0;
1303 return 0;
1306 void
1307 dosub(void)
1309 Rune *lp, *sp, *rp;
1310 int c, n;
1312 lp = linebuf;
1313 sp = genbuf;
1314 rp = rhsbuf;
1315 while(lp < loc1)
1316 *sp++ = *lp++;
1317 while(c = *rp++) {
1318 if(c == '&'){
1319 sp = place(sp, loc1, loc2);
1320 continue;
1322 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1323 n = c-'0';
1324 if(subexp[n].s.rsp && subexp[n].e.rep) {
1325 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
1326 continue;
1328 error(Q);
1330 *sp++ = c;
1331 if(sp >= &genbuf[LBSIZE])
1332 error(Q);
1334 lp = loc2;
1335 loc2 = sp - genbuf + linebuf;
1336 while(*sp++ = *lp++)
1337 if(sp >= &genbuf[LBSIZE])
1338 error(Q);
1339 lp = linebuf;
1340 sp = genbuf;
1341 while(*lp++ = *sp++)
1345 Rune*
1346 place(Rune *sp, Rune *l1, Rune *l2)
1349 while(l1 < l2) {
1350 *sp++ = *l1++;
1351 if(sp >= &genbuf[LBSIZE])
1352 error(Q);
1354 return sp;
1357 void
1358 move(int cflag)
1360 int *adt, *ad1, *ad2;
1362 nonzero();
1363 if((adt = address())==0) /* address() guarantees addr is in range */
1364 error(Q);
1365 newline();
1366 if(cflag) {
1367 int *ozero, delta;
1368 ad1 = dol;
1369 ozero = zero;
1370 append(getcopy, ad1++);
1371 ad2 = dol;
1372 delta = zero - ozero;
1373 ad1 += delta;
1374 adt += delta;
1375 } else {
1376 ad2 = addr2;
1377 for(ad1 = addr1; ad1 <= ad2;)
1378 *ad1++ &= ~01;
1379 ad1 = addr1;
1381 ad2++;
1382 if(adt<ad1) {
1383 dot = adt + (ad2-ad1);
1384 if((++adt)==ad1)
1385 return;
1386 reverse(adt, ad1);
1387 reverse(ad1, ad2);
1388 reverse(adt, ad2);
1389 } else
1390 if(adt >= ad2) {
1391 dot = adt++;
1392 reverse(ad1, ad2);
1393 reverse(ad2, adt);
1394 reverse(ad1, adt);
1395 } else
1396 error(Q);
1397 fchange = 1;
1400 void
1401 reverse(int *a1, int *a2)
1403 int t;
1405 for(;;) {
1406 t = *--a2;
1407 if(a2 <= a1)
1408 return;
1409 *a2 = *a1;
1410 *a1++ = t;
1414 int
1415 getcopy(void)
1417 if(addr1 > addr2)
1418 return EOF;
1419 getline(*addr1++);
1420 return 0;
1423 void
1424 compile(int eof)
1426 Rune c;
1427 char *ep;
1428 char expbuf[ESIZE];
1430 if((c = getchr()) == '\n') {
1431 peekc = c;
1432 c = eof;
1434 if(c == eof) {
1435 if(!pattern)
1436 error(Q);
1437 return;
1439 if(pattern) {
1440 free(pattern);
1441 pattern = 0;
1443 ep = expbuf;
1444 do {
1445 if(c == '\\') {
1446 if(ep >= expbuf+sizeof(expbuf)) {
1447 error(Q);
1448 return;
1450 ep += runetochar(ep, &c);
1451 if((c = getchr()) == '\n') {
1452 error(Q);
1453 return;
1456 if(ep >= expbuf+sizeof(expbuf)) {
1457 error(Q);
1458 return;
1460 ep += runetochar(ep, &c);
1461 } while((c = getchr()) != eof && c != '\n');
1462 if(c == '\n')
1463 peekc = c;
1464 *ep = 0;
1465 pattern = regcomp(expbuf);
1468 int
1469 match(int *addr)
1471 if(!pattern)
1472 return 0;
1473 if(addr){
1474 if(addr == zero)
1475 return 0;
1476 subexp[0].s.rsp = getline(*addr);
1477 } else
1478 subexp[0].s.rsp = loc2;
1479 subexp[0].e.rep = 0;
1480 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1481 loc1 = subexp[0].s.rsp;
1482 loc2 = subexp[0].e.rep;
1483 return 1;
1485 loc1 = loc2 = 0;
1486 return 0;
1490 void
1491 putd(void)
1493 int r;
1495 r = count%10;
1496 count /= 10;
1497 if(count)
1498 putd();
1499 putchr(r + '0');
1502 void
1503 putst(char *sp)
1505 Rune r;
1507 col = 0;
1508 for(;;) {
1509 sp += chartorune(&r, sp);
1510 if(r == 0)
1511 break;
1512 putchr(r);
1514 putchr('\n');
1517 void
1518 putshst(Rune *sp)
1520 col = 0;
1521 while(*sp)
1522 putchr(*sp++);
1523 putchr('\n');
1526 void
1527 putchr(int ac)
1529 char *lp;
1530 int c;
1531 Rune rune;
1533 lp = linp;
1534 c = ac;
1535 if(listf) {
1536 if(c == '\n') {
1537 if(linp != line && linp[-1] == ' ') {
1538 *lp++ = '\\';
1539 *lp++ = 'n';
1541 } else {
1542 if(col > (72-6-2)) {
1543 col = 8;
1544 *lp++ = '\\';
1545 *lp++ = '\n';
1546 *lp++ = '\t';
1548 col++;
1549 if(c=='\b' || c=='\t' || c=='\\') {
1550 *lp++ = '\\';
1551 if(c == '\b')
1552 c = 'b';
1553 else
1554 if(c == '\t')
1555 c = 't';
1556 col++;
1557 } else
1558 if(c<' ' || c>='\177') {
1559 *lp++ = '\\';
1560 *lp++ = 'x';
1561 *lp++ = hex[c>>12];
1562 *lp++ = hex[c>>8&0xF];
1563 *lp++ = hex[c>>4&0xF];
1564 c = hex[c&0xF];
1565 col += 5;
1570 rune = c;
1571 lp += runetochar(lp, &rune);
1573 if(c == '\n' || lp >= &line[sizeof(line)-5]) {
1574 linp = line;
1575 write(oflag? 2: 1, line, lp-line);
1576 return;
1578 linp = lp;
1581 char*
1582 mktemp(char *as)
1584 char *s;
1585 unsigned pid;
1586 int i;
1588 pid = getpid();
1589 s = as;
1590 while(*s++)
1592 s--;
1593 while(*--s == 'X') {
1594 *s = pid % 10 + '0';
1595 pid /= 10;
1597 s++;
1598 i = 'a';
1599 while(access(as, 0) != -1) {
1600 if(i == 'z')
1601 return "/";
1602 *s = i++;
1604 return as;
1607 void
1608 regerror(char *s)
1610 USED(s);
1611 error(Q);