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 enum
25 {
26 LINELEN = 70, /* max number of glyphs in a display line */
27 BELL = 6 /* A char could require up to BELL glyphs to display */
28 };
30 void (*oldhup)(int);
31 void (*oldquit)(int);
32 int* addr1;
33 int* addr2;
34 int anymarks;
35 int col;
36 long count;
37 int* dol;
38 int* dot;
39 int fchange;
40 char file[FNSIZE];
41 Rune genbuf[LBSIZE];
42 int given;
43 Rune* globp;
44 int iblock;
45 int ichanged;
46 int io;
47 Biobuf iobuf;
48 int lastc;
49 char line[LINELEN];
50 Rune* linebp;
51 Rune linebuf[LBSIZE];
52 int listf;
53 int listn;
54 Rune* loc1;
55 Rune* loc2;
56 int names[26];
57 int nleft;
58 int oblock;
59 int oflag;
60 Reprog *pattern;
61 int peekc;
62 int pflag;
63 int rescuing;
64 Rune rhsbuf[LBSIZE/sizeof(Rune)];
65 char savedfile[FNSIZE];
66 jmp_buf savej;
67 int subnewa;
68 int subolda;
69 Resub subexp[MAXSUB];
70 char* tfname;
71 int tline;
72 int waiting;
73 int wrapp;
74 int* zero;
76 char Q[] = "";
77 char T[] = "TMP";
78 char WRERR[] = "WRITE ERROR";
79 int bpagesize = 20;
80 char hex[] = "0123456789abcdef";
81 char* linp = line;
82 ulong nlall = 128;
83 int tfile = -1;
84 int vflag = 1;
86 void add(int);
87 int* address(void);
88 int append(int(*)(void), int*);
89 void browse(void);
90 void callunix(void);
91 void commands(void);
92 void compile(int);
93 int compsub(void);
94 void dosub(void);
95 void error(char*);
96 int match(int*);
97 void exfile(int);
98 void filename(int);
99 Rune* getblock(int, int);
100 int getchr(void);
101 int getcopy(void);
102 int getfile(void);
103 Rune* getline(int);
104 int getnum(void);
105 int getsub(void);
106 int gettty(void);
107 void global(int);
108 void init(void);
109 void join(void);
110 void move(int);
111 void newline(void);
112 void nonzero(void);
113 void notifyf(void*, char*);
114 Rune* place(Rune*, Rune*, Rune*);
115 void printcom(void);
116 void putchr(int);
117 void putd(void);
118 void putfile(void);
119 int putline(void);
120 void putshst(Rune*);
121 void putst(char*);
122 void quit(void);
123 void rdelete(int*, int*);
124 void regerror(char *);
125 void reverse(int*, int*);
126 void setnoaddr(void);
127 void setwide(void);
128 void squeeze(int);
129 void substitute(int);
131 Rune La[] = { 'a', 0 };
132 Rune Lr[] = { 'r', 0 };
134 char tmp[] = "/var/tmp/eXXXXX";
136 void
137 main(int argc, char *argv[])
139 char *p1, *p2;
141 notify(notifyf);
142 ARGBEGIN {
143 case 'o':
144 oflag = 1;
145 vflag = 0;
146 break;
147 } ARGEND
149 USED(argc);
150 if(*argv && (strcmp(*argv, "-") == 0)) {
151 argv++;
152 vflag = 0;
154 if(oflag) {
155 p1 = "/dev/stdout";
156 p2 = savedfile;
157 while(*p2++ = *p1++)
159 globp = La;
160 } else
161 if(*argv) {
162 p1 = *argv;
163 p2 = savedfile;
164 while(*p2++ = *p1++)
165 if(p2 >= &savedfile[sizeof(savedfile)])
166 p2--;
167 globp = Lr;
169 zero = malloc((nlall+5)*sizeof(int*));
170 tfname = mktemp(tmp);
171 init();
172 setjmp(savej);
173 commands();
174 quit();
177 void
178 commands(void)
180 int *a1, c, temp;
181 char lastsep;
182 Dir *d;
184 for(;;) {
185 if(pflag) {
186 pflag = 0;
187 addr1 = addr2 = dot;
188 printcom();
190 c = '\n';
191 for(addr1 = 0;;) {
192 lastsep = c;
193 a1 = address();
194 c = getchr();
195 if(c != ',' && c != ';')
196 break;
197 if(lastsep == ',')
198 error(Q);
199 if(a1 == 0) {
200 a1 = zero+1;
201 if(a1 > dol)
202 a1--;
204 addr1 = a1;
205 if(c == ';')
206 dot = a1;
208 if(lastsep != '\n' && a1 == 0)
209 a1 = dol;
210 if((addr2=a1) == 0) {
211 given = 0;
212 addr2 = dot;
213 } else
214 given = 1;
215 if(addr1 == 0)
216 addr1 = addr2;
217 switch(c) {
219 case 'a':
220 add(0);
221 continue;
223 case 'b':
224 nonzero();
225 browse();
226 continue;
228 case 'c':
229 nonzero();
230 newline();
231 rdelete(addr1, addr2);
232 append(gettty, addr1-1);
233 continue;
235 case 'd':
236 nonzero();
237 newline();
238 rdelete(addr1, addr2);
239 continue;
241 case 'E':
242 fchange = 0;
243 c = 'e';
244 case 'e':
245 setnoaddr();
246 if(vflag && fchange) {
247 fchange = 0;
248 error(Q);
250 filename(c);
251 init();
252 addr2 = zero;
253 goto caseread;
255 case 'f':
256 setnoaddr();
257 filename(c);
258 putst(savedfile);
259 continue;
261 case 'g':
262 global(1);
263 continue;
265 case 'i':
266 add(-1);
267 continue;
270 case 'j':
271 if(!given)
272 addr2++;
273 newline();
274 join();
275 continue;
277 case 'k':
278 nonzero();
279 c = getchr();
280 if(c < 'a' || c > 'z')
281 error(Q);
282 newline();
283 names[c-'a'] = *addr2 & ~01;
284 anymarks |= 01;
285 continue;
287 case 'm':
288 move(0);
289 continue;
291 case 'n':
292 listn++;
293 newline();
294 printcom();
295 continue;
297 case '\n':
298 if(a1==0) {
299 a1 = dot+1;
300 addr2 = a1;
301 addr1 = a1;
303 if(lastsep==';')
304 addr1 = a1;
305 printcom();
306 continue;
308 case 'l':
309 listf++;
310 case 'p':
311 case 'P':
312 newline();
313 printcom();
314 continue;
316 case 'Q':
317 fchange = 0;
318 case 'q':
319 setnoaddr();
320 newline();
321 quit();
323 case 'r':
324 filename(c);
325 caseread:
326 if((io=open(file, OREAD)) < 0) {
327 lastc = '\n';
328 error(file);
330 if((d = dirfstat(io)) != nil){
331 if(d->mode & DMAPPEND)
332 print("warning: %s is append only\n", file);
333 free(d);
335 Binit(&iobuf, io, OREAD);
336 setwide();
337 squeeze(0);
338 c = zero != dol;
339 append(getfile, addr2);
340 exfile(OREAD);
342 fchange = c;
343 continue;
345 case 's':
346 nonzero();
347 substitute(globp != 0);
348 continue;
350 case 't':
351 move(1);
352 continue;
354 case 'u':
355 nonzero();
356 newline();
357 if((*addr2&~01) != subnewa)
358 error(Q);
359 *addr2 = subolda;
360 dot = addr2;
361 continue;
363 case 'v':
364 global(0);
365 continue;
367 case 'W':
368 wrapp++;
369 case 'w':
370 setwide();
371 squeeze(dol>zero);
372 temp = getchr();
373 if(temp != 'q' && temp != 'Q') {
374 peekc = temp;
375 temp = 0;
377 filename(c);
378 if(!wrapp ||
379 ((io = open(file, OWRITE)) == -1) ||
380 ((seek(io, 0L, 2)) == -1))
381 if((io = create(file, OWRITE, 0666)) < 0)
382 error(file);
383 Binit(&iobuf, io, OWRITE);
384 wrapp = 0;
385 if(dol > zero)
386 putfile();
387 exfile(OWRITE);
388 if(addr1<=zero+1 && addr2==dol)
389 fchange = 0;
390 if(temp == 'Q')
391 fchange = 0;
392 if(temp)
393 quit();
394 continue;
396 case '=':
397 setwide();
398 squeeze(0);
399 newline();
400 count = addr2 - zero;
401 putd();
402 putchr('\n');
403 continue;
405 case '!':
406 callunix();
407 continue;
409 case EOF:
410 return;
413 error(Q);
417 void
418 printcom(void)
420 int *a1;
422 nonzero();
423 a1 = addr1;
424 do {
425 if(listn) {
426 count = a1-zero;
427 putd();
428 putchr('\t');
430 putshst(getline(*a1++));
431 } while(a1 <= addr2);
432 dot = addr2;
433 listf = 0;
434 listn = 0;
435 pflag = 0;
438 int*
439 address(void)
441 int sign, *a, opcnt, nextopand, *b, c;
443 nextopand = -1;
444 sign = 1;
445 opcnt = 0;
446 a = dot;
447 do {
448 do {
449 c = getchr();
450 } while(c == ' ' || c == '\t');
451 if(c >= '0' && c <= '9') {
452 peekc = c;
453 if(!opcnt)
454 a = zero;
455 a += sign*getnum();
456 } else
457 switch(c) {
458 case '$':
459 a = dol;
460 case '.':
461 if(opcnt)
462 error(Q);
463 break;
464 case '\'':
465 c = getchr();
466 if(opcnt || c < 'a' || c > 'z')
467 error(Q);
468 a = zero;
469 do {
470 a++;
471 } while(a <= dol && names[c-'a'] != (*a & ~01));
472 break;
473 case '?':
474 sign = -sign;
475 case '/':
476 compile(c);
477 b = a;
478 for(;;) {
479 a += sign;
480 if(a <= zero)
481 a = dol;
482 if(a > dol)
483 a = zero;
484 if(match(a))
485 break;
486 if(a == b)
487 error(Q);
489 break;
490 default:
491 if(nextopand == opcnt) {
492 a += sign;
493 if(a < zero || dol < a)
494 continue; /* error(Q); */
496 if(c != '+' && c != '-' && c != '^') {
497 peekc = c;
498 if(opcnt == 0)
499 a = 0;
500 return a;
502 sign = 1;
503 if(c != '+')
504 sign = -sign;
505 nextopand = ++opcnt;
506 continue;
508 sign = 1;
509 opcnt++;
510 } while(zero <= a && a <= dol);
511 error(Q);
512 return 0;
515 int
516 getnum(void)
518 int r, c;
520 r = 0;
521 for(;;) {
522 c = getchr();
523 if(c < '0' || c > '9')
524 break;
525 r = r*10 + (c-'0');
527 peekc = c;
528 return r;
531 void
532 setwide(void)
534 if(!given) {
535 addr1 = zero + (dol>zero);
536 addr2 = dol;
540 void
541 setnoaddr(void)
543 if(given)
544 error(Q);
547 void
548 nonzero(void)
550 squeeze(1);
553 void
554 squeeze(int i)
556 if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
557 error(Q);
560 void
561 newline(void)
563 int c;
565 c = getchr();
566 if(c == '\n' || c == EOF)
567 return;
568 if(c == 'p' || c == 'l' || c == 'n') {
569 pflag++;
570 if(c == 'l')
571 listf++;
572 else
573 if(c == 'n')
574 listn++;
575 c = getchr();
576 if(c == '\n')
577 return;
579 error(Q);
582 void
583 filename(int comm)
585 char *p1, *p2;
586 Rune rune;
587 int c;
589 count = 0;
590 c = getchr();
591 if(c == '\n' || c == EOF) {
592 p1 = savedfile;
593 if(*p1 == 0 && comm != 'f')
594 error(Q);
595 p2 = file;
596 while(*p2++ = *p1++)
598 return;
600 if(c != ' ')
601 error(Q);
602 while((c=getchr()) == ' ')
604 if(c == '\n')
605 error(Q);
606 p1 = file;
607 do {
608 if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)
609 error(Q);
610 rune = c;
611 p1 += runetochar(p1, &rune);
612 } while((c=getchr()) != '\n');
613 *p1 = 0;
614 if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {
615 p1 = savedfile;
616 p2 = file;
617 while(*p1++ = *p2++)
622 void
623 exfile(int om)
626 if(om == OWRITE)
627 if(Bflush(&iobuf) < 0)
628 error(Q);
629 close(io);
630 io = -1;
631 if(vflag) {
632 putd();
633 putchr('\n');
637 void
638 error1(char *s)
640 int c;
642 wrapp = 0;
643 listf = 0;
644 listn = 0;
645 count = 0;
646 seek(0, 0, 2);
647 pflag = 0;
648 if(globp)
649 lastc = '\n';
650 globp = 0;
651 peekc = lastc;
652 if(lastc)
653 for(;;) {
654 c = getchr();
655 if(c == '\n' || c == EOF)
656 break;
658 if(io > 0) {
659 close(io);
660 io = -1;
662 putchr('?');
663 putst(s);
666 void
667 error(char *s)
669 error1(s);
670 longjmp(savej, 1);
673 void
674 rescue(void)
676 rescuing = 1;
677 if(dol > zero) {
678 addr1 = zero+1;
679 addr2 = dol;
680 io = create("ed.hup", OWRITE, 0666);
681 if(io > 0){
682 Binit(&iobuf, io, OWRITE);
683 putfile();
686 fchange = 0;
687 quit();
690 void
691 notifyf(void *a, char *s)
693 if(strcmp(s, "interrupt") == 0){
694 if(rescuing || waiting)
695 noted(NCONT);
696 putchr('\n');
697 lastc = '\n';
698 error1(Q);
699 notejmp(a, savej, 0);
701 if(strcmp(s, "hangup") == 0 || strcmp(s, "kill") == 0){
702 if(rescuing)
703 noted(NDFLT);
704 rescue();
706 if(strstr(s, "child"))
707 noted(NCONT);
708 fprint(2, "ed: note: %s\n", s);
709 abort();
712 int
713 getchr(void)
715 char s[UTFmax];
716 int i;
717 Rune r;
719 if(lastc = peekc) {
720 peekc = 0;
721 return lastc;
723 if(globp) {
724 if((lastc=*globp++) != 0)
725 return lastc;
726 globp = 0;
727 return EOF;
729 for(i=0;;) {
730 if(read(0, s+i, 1) <= 0)
731 return lastc = EOF;
732 i++;
733 if(fullrune(s, i))
734 break;
737 chartorune(&r, s);
738 lastc = r;
739 return lastc;
742 int
743 gety(void)
745 int c;
746 Rune *gf, *p;
748 p = linebuf;
749 gf = globp;
750 for(;;) {
751 c = getchr();
752 if(c == '\n') {
753 *p = 0;
754 return 0;
756 if(c == EOF) {
757 if(gf)
758 peekc = c;
759 return c;
761 if(c == 0)
762 continue;
763 *p++ = c;
764 if(p >= &linebuf[LBSIZE-2])
765 error(Q);
769 int
770 gettty(void)
772 int rc;
774 rc = gety();
775 if(rc)
776 return rc;
777 if(linebuf[0] == '.' && linebuf[1] == 0)
778 return EOF;
779 return 0;
782 int
783 getfile(void)
785 int c;
786 Rune *lp;
788 lp = linebuf;
789 do {
790 c = Bgetrune(&iobuf);
791 if(c < 0) {
792 if(lp > linebuf) {
793 putst("'\\n' appended");
794 c = '\n';
795 } else
796 return EOF;
798 if(lp >= &linebuf[LBSIZE]) {
799 lastc = '\n';
800 error(Q);
802 *lp++ = c;
803 count++;
804 } while(c != '\n');
805 lp[-1] = 0;
806 return 0;
809 void
810 putfile(void)
812 int *a1;
813 Rune *lp;
814 long c;
816 a1 = addr1;
817 do {
818 lp = getline(*a1++);
819 for(;;) {
820 count++;
821 c = *lp++;
822 if(c == 0) {
823 if(Bputrune(&iobuf, '\n') < 0)
824 error(Q);
825 break;
827 if(Bputrune(&iobuf, c) < 0)
828 error(Q);
830 } while(a1 <= addr2);
831 if(Bflush(&iobuf) < 0)
832 error(Q);
835 int
836 append(int (*f)(void), int *a)
838 int *a1, *a2, *rdot, nline, d;
840 nline = 0;
841 dot = a;
842 while((*f)() == 0) {
843 if((dol-zero) >= nlall) {
844 nlall += 512;
845 a1 = realloc(zero, (nlall+50)*sizeof(int*));
846 if(a1 == 0) {
847 error("MEM?");
848 rescue();
850 /* relocate pointers; avoid wraparound if sizeof(int) < sizeof(int*) */
851 d = addr1 - zero;
852 addr1 = a1 + d;
853 d = addr2 - zero;
854 addr2 = a1 + d;
855 d = dol - zero;
856 dol = a1 + d;
857 d = dot - zero;
858 dot = a1 + d;
859 zero = a1;
861 d = putline();
862 nline++;
863 a1 = ++dol;
864 a2 = a1+1;
865 rdot = ++dot;
866 while(a1 > rdot)
867 *--a2 = *--a1;
868 *rdot = d;
870 return nline;
873 void
874 add(int i)
876 if(i && (given || dol > zero)) {
877 addr1--;
878 addr2--;
880 squeeze(0);
881 newline();
882 append(gettty, addr2);
885 void
886 browse(void)
888 int forward, n;
889 static int bformat, bnum; /* 0 */
891 forward = 1;
892 peekc = getchr();
893 if(peekc != '\n'){
894 if(peekc == '-' || peekc == '+') {
895 if(peekc == '-')
896 forward = 0;
897 getchr();
899 n = getnum();
900 if(n > 0)
901 bpagesize = n;
903 newline();
904 if(pflag) {
905 bformat = listf;
906 bnum = listn;
907 } else {
908 listf = bformat;
909 listn = bnum;
911 if(forward) {
912 addr1 = addr2;
913 addr2 += bpagesize;
914 if(addr2 > dol)
915 addr2 = dol;
916 } else {
917 addr1 = addr2-bpagesize;
918 if(addr1 <= zero)
919 addr1 = zero+1;
921 printcom();
924 void
925 callunix(void)
927 int c, pid;
928 Rune rune;
929 char buf[512];
930 char *p;
932 setnoaddr();
933 p = buf;
934 while((c=getchr()) != EOF && c != '\n')
935 if(p < &buf[sizeof(buf) - 6]) {
936 rune = c;
937 p += runetochar(p, &rune);
939 *p = 0;
940 pid = fork();
941 if(pid == 0) {
942 execlp("rc", "rc", "-c", buf, (char*)0);
943 sysfatal("exec failed: %r");
944 exits("execl failed");
946 waiting = 1;
947 while(waitpid() != pid)
949 waiting = 0;
950 if(vflag)
951 putst("!");
954 void
955 quit(void)
957 if(vflag && fchange && dol!=zero) {
958 fchange = 0;
959 error(Q);
961 remove(tfname);
962 exits(0);
965 void
966 onquit(int sig)
968 USED(sig);
969 quit();
972 void
973 rdelete(int *ad1, int *ad2)
975 int *a1, *a2, *a3;
977 a1 = ad1;
978 a2 = ad2+1;
979 a3 = dol;
980 dol -= a2 - a1;
981 do {
982 *a1++ = *a2++;
983 } while(a2 <= a3);
984 a1 = ad1;
985 if(a1 > dol)
986 a1 = dol;
987 dot = a1;
988 fchange = 1;
991 void
992 gdelete(void)
994 int *a1, *a2, *a3;
996 a3 = dol;
997 for(a1=zero; (*a1&01)==0; a1++)
998 if(a1>=a3)
999 return;
1000 for(a2=a1+1; a2<=a3;) {
1001 if(*a2 & 01) {
1002 a2++;
1003 dot = a1;
1004 } else
1005 *a1++ = *a2++;
1007 dol = a1-1;
1008 if(dot > dol)
1009 dot = dol;
1010 fchange = 1;
1013 Rune*
1014 getline(int tl)
1016 Rune *lp, *bp;
1017 int nl;
1019 lp = linebuf;
1020 bp = getblock(tl, OREAD);
1021 nl = nleft;
1022 tl &= ~((BLKSIZE/sizeof(Rune)) - 1);
1023 while(*lp++ = *bp++) {
1024 nl -= sizeof(Rune);
1025 if(nl == 0) {
1026 bp = getblock(tl += BLKSIZE/sizeof(Rune), OREAD);
1027 nl = nleft;
1030 return linebuf;
1033 int
1034 putline(void)
1036 Rune *lp, *bp;
1037 int nl, tl;
1039 fchange = 1;
1040 lp = linebuf;
1041 tl = tline;
1042 bp = getblock(tl, OWRITE);
1043 nl = nleft;
1044 tl &= ~((BLKSIZE/sizeof(Rune))-1);
1045 while(*bp = *lp++) {
1046 if(*bp++ == '\n') {
1047 bp[-1] = 0;
1048 linebp = lp;
1049 break;
1051 nl -= sizeof(Rune);
1052 if(nl == 0) {
1053 tl += BLKSIZE/sizeof(Rune);
1054 bp = getblock(tl, OWRITE);
1055 nl = nleft;
1058 nl = tline;
1059 tline += ((lp-linebuf) + 03) & (NBLK-1);
1060 return nl;
1063 void
1064 blkio(int b, uchar *buf, int isread)
1066 int n;
1068 seek(tfile, b*BLKSIZE, 0);
1069 if(isread)
1070 n = read(tfile, buf, BLKSIZE);
1071 else
1072 n = write(tfile, buf, BLKSIZE);
1073 if(n != BLKSIZE)
1074 error(T);
1077 Rune*
1078 getblock(int atl, int iof)
1080 int bno, off;
1082 static uchar ibuff[BLKSIZE];
1083 static uchar obuff[BLKSIZE];
1085 bno = atl / (BLKSIZE/sizeof(Rune));
1086 off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~03;
1087 if(bno >= NBLK) {
1088 lastc = '\n';
1089 error(T);
1091 nleft = BLKSIZE - off;
1092 if(bno == iblock) {
1093 ichanged |= iof;
1094 return (Rune*)(ibuff+off);
1096 if(bno == oblock)
1097 return (Rune*)(obuff+off);
1098 if(iof == OREAD) {
1099 if(ichanged)
1100 blkio(iblock, ibuff, 0);
1101 ichanged = 0;
1102 iblock = bno;
1103 blkio(bno, ibuff, 1);
1104 return (Rune*)(ibuff+off);
1106 if(oblock >= 0)
1107 blkio(oblock, obuff, 0);
1108 oblock = bno;
1109 return (Rune*)(obuff+off);
1112 void
1113 init(void)
1115 int *markp;
1117 close(tfile);
1118 tline = 2;
1119 for(markp = names; markp < &names[26]; )
1120 *markp++ = 0;
1121 subnewa = 0;
1122 anymarks = 0;
1123 iblock = -1;
1124 oblock = -1;
1125 ichanged = 0;
1126 if((tfile = create(tfname, ORDWR, 0600)) < 0){
1127 error1(T);
1128 exits(0);
1130 dot = dol = zero;
1133 void
1134 global(int k)
1136 Rune *gp, globuf[GBSIZE];
1137 int c, *a1;
1139 if(globp)
1140 error(Q);
1141 setwide();
1142 squeeze(dol > zero);
1143 c = getchr();
1144 if(c == '\n')
1145 error(Q);
1146 compile(c);
1147 gp = globuf;
1148 while((c=getchr()) != '\n') {
1149 if(c == EOF)
1150 error(Q);
1151 if(c == '\\') {
1152 c = getchr();
1153 if(c != '\n')
1154 *gp++ = '\\';
1156 *gp++ = c;
1157 if(gp >= &globuf[GBSIZE-2])
1158 error(Q);
1160 if(gp == globuf)
1161 *gp++ = 'p';
1162 *gp++ = '\n';
1163 *gp = 0;
1164 for(a1=zero; a1<=dol; a1++) {
1165 *a1 &= ~01;
1166 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1167 *a1 |= 01;
1171 * Special case: g/.../d (avoid n^2 algorithm)
1173 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1174 gdelete();
1175 return;
1177 for(a1=zero; a1<=dol; a1++) {
1178 if(*a1 & 01) {
1179 *a1 &= ~01;
1180 dot = a1;
1181 globp = globuf;
1182 commands();
1183 a1 = zero;
1188 void
1189 join(void)
1191 Rune *gp, *lp;
1192 int *a1;
1194 nonzero();
1195 gp = genbuf;
1196 for(a1=addr1; a1<=addr2; a1++) {
1197 lp = getline(*a1);
1198 while(*gp = *lp++)
1199 if(gp++ >= &genbuf[LBSIZE-2])
1200 error(Q);
1202 lp = linebuf;
1203 gp = genbuf;
1204 while(*lp++ = *gp++)
1206 *addr1 = putline();
1207 if(addr1 < addr2)
1208 rdelete(addr1+1, addr2);
1209 dot = addr1;
1212 void
1213 substitute(int inglob)
1215 int *mp, *a1, nl, gsubf, n;
1217 n = getnum(); /* OK even if n==0 */
1218 gsubf = compsub();
1219 for(a1 = addr1; a1 <= addr2; a1++) {
1220 if(match(a1)){
1221 int *ozero;
1222 int m = n;
1224 do {
1225 int span = loc2-loc1;
1227 if(--m <= 0) {
1228 dosub();
1229 if(!gsubf)
1230 break;
1231 if(span == 0) { /* null RE match */
1232 if(*loc2 == 0)
1233 break;
1234 loc2++;
1237 } while(match(0));
1238 if(m <= 0) {
1239 inglob |= 01;
1240 subnewa = putline();
1241 *a1 &= ~01;
1242 if(anymarks) {
1243 for(mp=names; mp<&names[26]; mp++)
1244 if(*mp == *a1)
1245 *mp = subnewa;
1247 subolda = *a1;
1248 *a1 = subnewa;
1249 ozero = zero;
1250 nl = append(getsub, a1);
1251 addr2 += nl;
1252 nl += zero-ozero;
1253 a1 += nl;
1257 if(inglob == 0)
1258 error(Q);
1261 int
1262 compsub(void)
1264 int seof, c;
1265 Rune *p;
1267 seof = getchr();
1268 if(seof == '\n' || seof == ' ')
1269 error(Q);
1270 compile(seof);
1271 p = rhsbuf;
1272 for(;;) {
1273 c = getchr();
1274 if(c == '\\') {
1275 c = getchr();
1276 *p++ = ESCFLG;
1277 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
1278 error(Q);
1279 } else
1280 if(c == '\n' && (!globp || !globp[0])) {
1281 peekc = c;
1282 pflag++;
1283 break;
1284 } else
1285 if(c == seof)
1286 break;
1287 *p++ = c;
1288 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
1289 error(Q);
1291 *p = 0;
1292 peekc = getchr();
1293 if(peekc == 'g') {
1294 peekc = 0;
1295 newline();
1296 return 1;
1298 newline();
1299 return 0;
1302 int
1303 getsub(void)
1305 Rune *p1, *p2;
1307 p1 = linebuf;
1308 if((p2 = linebp) == 0)
1309 return EOF;
1310 while(*p1++ = *p2++)
1312 linebp = 0;
1313 return 0;
1316 void
1317 dosub(void)
1319 Rune *lp, *sp, *rp;
1320 int c, n;
1322 lp = linebuf;
1323 sp = genbuf;
1324 rp = rhsbuf;
1325 while(lp < loc1)
1326 *sp++ = *lp++;
1327 while(c = *rp++) {
1328 if(c == '&'){
1329 sp = place(sp, loc1, loc2);
1330 continue;
1332 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1333 n = c-'0';
1334 if(subexp[n].s.rsp && subexp[n].e.rep) {
1335 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
1336 continue;
1338 error(Q);
1340 *sp++ = c;
1341 if(sp >= &genbuf[LBSIZE])
1342 error(Q);
1344 lp = loc2;
1345 loc2 = sp - genbuf + linebuf;
1346 while(*sp++ = *lp++)
1347 if(sp >= &genbuf[LBSIZE])
1348 error(Q);
1349 lp = linebuf;
1350 sp = genbuf;
1351 while(*lp++ = *sp++)
1355 Rune*
1356 place(Rune *sp, Rune *l1, Rune *l2)
1359 while(l1 < l2) {
1360 *sp++ = *l1++;
1361 if(sp >= &genbuf[LBSIZE])
1362 error(Q);
1364 return sp;
1367 void
1368 move(int cflag)
1370 int *adt, *ad1, *ad2;
1372 nonzero();
1373 if((adt = address())==0) /* address() guarantees addr is in range */
1374 error(Q);
1375 newline();
1376 if(cflag) {
1377 int *ozero, delta;
1378 ad1 = dol;
1379 ozero = zero;
1380 append(getcopy, ad1++);
1381 ad2 = dol;
1382 delta = zero - ozero;
1383 ad1 += delta;
1384 adt += delta;
1385 } else {
1386 ad2 = addr2;
1387 for(ad1 = addr1; ad1 <= ad2;)
1388 *ad1++ &= ~01;
1389 ad1 = addr1;
1391 ad2++;
1392 if(adt<ad1) {
1393 dot = adt + (ad2-ad1);
1394 if((++adt)==ad1)
1395 return;
1396 reverse(adt, ad1);
1397 reverse(ad1, ad2);
1398 reverse(adt, ad2);
1399 } else
1400 if(adt >= ad2) {
1401 dot = adt++;
1402 reverse(ad1, ad2);
1403 reverse(ad2, adt);
1404 reverse(ad1, adt);
1405 } else
1406 error(Q);
1407 fchange = 1;
1410 void
1411 reverse(int *a1, int *a2)
1413 int t;
1415 for(;;) {
1416 t = *--a2;
1417 if(a2 <= a1)
1418 return;
1419 *a2 = *a1;
1420 *a1++ = t;
1424 int
1425 getcopy(void)
1427 if(addr1 > addr2)
1428 return EOF;
1429 getline(*addr1++);
1430 return 0;
1433 void
1434 compile(int eof)
1436 Rune c;
1437 char *ep;
1438 char expbuf[ESIZE];
1440 if((c = getchr()) == '\n') {
1441 peekc = c;
1442 c = eof;
1444 if(c == eof) {
1445 if(!pattern)
1446 error(Q);
1447 return;
1449 if(pattern) {
1450 free(pattern);
1451 pattern = 0;
1453 ep = expbuf;
1454 do {
1455 if(c == '\\') {
1456 if(ep >= expbuf+sizeof(expbuf)) {
1457 error(Q);
1458 return;
1460 ep += runetochar(ep, &c);
1461 if((c = getchr()) == '\n') {
1462 error(Q);
1463 return;
1466 if(ep >= expbuf+sizeof(expbuf)) {
1467 error(Q);
1468 return;
1470 ep += runetochar(ep, &c);
1471 } while((c = getchr()) != eof && c != '\n');
1472 if(c == '\n')
1473 peekc = c;
1474 *ep = 0;
1475 pattern = regcomp(expbuf);
1478 int
1479 match(int *addr)
1481 if(!pattern)
1482 return 0;
1483 if(addr){
1484 if(addr == zero)
1485 return 0;
1486 subexp[0].s.rsp = getline(*addr);
1487 } else
1488 subexp[0].s.rsp = loc2;
1489 subexp[0].e.rep = 0;
1490 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1491 loc1 = subexp[0].s.rsp;
1492 loc2 = subexp[0].e.rep;
1493 return 1;
1495 loc1 = loc2 = 0;
1496 return 0;
1500 void
1501 putd(void)
1503 int r;
1505 r = count%10;
1506 count /= 10;
1507 if(count)
1508 putd();
1509 putchr(r + '0');
1512 void
1513 putst(char *sp)
1515 Rune r;
1517 col = 0;
1518 for(;;) {
1519 sp += chartorune(&r, sp);
1520 if(r == 0)
1521 break;
1522 putchr(r);
1524 putchr('\n');
1527 void
1528 putshst(Rune *sp)
1530 col = 0;
1531 while(*sp)
1532 putchr(*sp++);
1533 putchr('\n');
1536 void
1537 putchr(int ac)
1539 char *lp;
1540 int c;
1541 Rune rune;
1543 lp = linp;
1544 c = ac;
1545 if(listf) {
1546 if(c == '\n') {
1547 if(linp != line && linp[-1] == ' ') {
1548 *lp++ = '\\';
1549 *lp++ = 'n';
1551 } else {
1552 if(col > (LINELEN-BELL)) {
1553 col = 8;
1554 *lp++ = '\\';
1555 *lp++ = '\n';
1556 *lp++ = '\t';
1558 col++;
1559 if(c=='\b' || c=='\t' || c=='\\') {
1560 *lp++ = '\\';
1561 if(c == '\b')
1562 c = 'b';
1563 else
1564 if(c == '\t')
1565 c = 't';
1566 col++;
1567 } else if (c<' ' || c=='\177') {
1568 *lp++ = '\\';
1569 *lp++ = 'x';
1570 *lp++ = hex[(c>>4)&0xF];
1571 c = hex[c&0xF];
1572 col += 3;
1573 } else if (c>'\177' && c<=0xFFFF) {
1574 *lp++ = '\\';
1575 *lp++ = 'u';
1576 *lp++ = hex[(c>>12)&0xF];
1577 *lp++ = hex[(c>>8)&0xF];
1578 *lp++ = hex[(c>>4)&0xF];
1579 c = hex[c&0xF];
1580 col += 5;
1581 } else if (c>0xFFFF) {
1582 *lp++ = '\\';
1583 *lp++ = 'U';
1584 *lp++ = hex[(c>>28)&0xF];
1585 *lp++ = hex[(c>>24)&0xF];
1586 *lp++ = hex[(c>>20)&0xF];
1587 *lp++ = hex[(c>>16)&0xF];
1588 *lp++ = hex[(c>>12)&0xF];
1589 *lp++ = hex[(c>>8)&0xF];
1590 *lp++ = hex[(c>>4)&0xF];
1591 c = hex[c&0xF];
1592 col += 9;
1597 rune = c;
1598 lp += runetochar(lp, &rune);
1600 if(c == '\n' || lp >= &line[LINELEN-BELL]) {
1601 linp = line;
1602 write(oflag? 2: 1, line, lp-line);
1603 return;
1605 linp = lp;
1608 char*
1609 mktemp(char *as)
1611 char *s;
1612 unsigned pid;
1613 int i;
1615 pid = getpid();
1616 s = as;
1617 while(*s++)
1619 s--;
1620 while(*--s == 'X') {
1621 *s = pid % 10 + '0';
1622 pid /= 10;
1624 s++;
1625 i = 'a';
1626 while(access(as, 0) != -1) {
1627 if(i == 'z')
1628 return "/";
1629 *s = i++;
1631 return as;
1634 void
1635 regerror(char *s)
1637 USED(s);
1638 error(Q);