Blob


1 /*
2 * Editor
3 */
4 #include <u.h>
5 #include <libc.h>
6 #include <bio.h>
7 #include <regexp.h>
9 enum
10 {
11 FNSIZE = 128, /* file name */
12 LBSIZE = 4096, /* max line size */
13 BLKSIZE = 4096, /* block size in temp file */
14 NBLK = 8191, /* max size of temp file */
15 ESIZE = 256, /* max size of reg exp */
16 GBSIZE = 256, /* max size of global command */
17 MAXSUB = 9, /* max number of sub reg exp */
18 ESCFLG = 0xFFFF, /* escape Rune - user defined code */
19 EOF = -1,
20 };
22 void (*oldhup)(int);
23 void (*oldquit)(int);
24 int* addr1;
25 int* addr2;
26 int anymarks;
27 int col;
28 long count;
29 int* dol;
30 int* dot;
31 int fchange;
32 char file[FNSIZE];
33 Rune genbuf[LBSIZE];
34 int given;
35 Rune* globp;
36 int iblock;
37 int ichanged;
38 int io;
39 Biobuf iobuf;
40 int lastc;
41 char line[70];
42 Rune* linebp;
43 Rune linebuf[LBSIZE];
44 int listf;
45 int listn;
46 Rune* loc1;
47 Rune* loc2;
48 int names[26];
49 int nleft;
50 int oblock;
51 int oflag;
52 Reprog *pattern;
53 int peekc;
54 int pflag;
55 int rescuing;
56 Rune rhsbuf[LBSIZE/2];
57 char savedfile[FNSIZE];
58 jmp_buf savej;
59 int subnewa;
60 int subolda;
61 Resub subexp[MAXSUB];
62 char* tfname;
63 int tline;
64 int waiting;
65 int wrapp;
66 int* zero;
68 char Q[] = "";
69 char T[] = "TMP";
70 char WRERR[] = "WRITE ERROR";
71 int bpagesize = 20;
72 char hex[] = "0123456789abcdef";
73 char* linp = line;
74 ulong nlall = 128;
75 int tfile = -1;
76 int vflag = 1;
78 void add(int);
79 int* address(void);
80 int append(int(*)(void), int*);
81 void browse(void);
82 void callunix(void);
83 void commands(void);
84 void compile(int);
85 int compsub(void);
86 void dosub(void);
87 void error(char*);
88 int match(int*);
89 void exfile(int);
90 void filename(int);
91 Rune* getblock(int, int);
92 int getchr(void);
93 int getcopy(void);
94 int getfile(void);
95 Rune* getline(int);
96 int getnum(void);
97 int getsub(void);
98 int gettty(void);
99 void global(int);
100 void init(void);
101 void join(void);
102 void move(int);
103 void newline(void);
104 void nonzero(void);
105 void notifyf(void*, char*);
106 Rune* place(Rune*, Rune*, Rune*);
107 void printcom(void);
108 void putchr(int);
109 void putd(void);
110 void putfile(void);
111 int putline(void);
112 void putshst(Rune*);
113 void putst(char*);
114 void quit(void);
115 void rdelete(int*, int*);
116 void regerror(char *);
117 void reverse(int*, int*);
118 void setnoaddr(void);
119 void setwide(void);
120 void squeeze(int);
121 void substitute(int);
123 Rune La[] = { 'a', 0 };
124 Rune Lr[] = { 'r', 0 };
126 char tmp[] = "/tmp/eXXXXX";
128 void
129 main(int argc, char *argv[])
131 char *p1, *p2;
133 notify(notifyf);
134 ARGBEGIN {
135 case 'o':
136 oflag = 1;
137 vflag = 0;
138 break;
139 } ARGEND
141 USED(argc);
142 if(*argv && (strcmp(*argv, "-") == 0)) {
143 argv++;
144 vflag = 0;
146 if(oflag) {
147 p1 = "/fd/1";
148 p2 = savedfile;
149 while(*p2++ = *p1++)
151 globp = La;
152 } else
153 if(*argv) {
154 p1 = *argv;
155 p2 = savedfile;
156 while(*p2++ = *p1++)
157 if(p2 >= &savedfile[sizeof(savedfile)])
158 p2--;
159 globp = Lr;
161 zero = malloc((nlall+5)*sizeof(int*));
162 tfname = mktemp(tmp);
163 init();
164 setjmp(savej);
165 commands();
166 quit();
169 void
170 commands(void)
172 int *a1, c, temp;
173 char lastsep;
174 Dir *d;
176 for(;;) {
177 if(pflag) {
178 pflag = 0;
179 addr1 = addr2 = dot;
180 printcom();
182 c = '\n';
183 for(addr1 = 0;;) {
184 lastsep = c;
185 a1 = address();
186 c = getchr();
187 if(c != ',' && c != ';')
188 break;
189 if(lastsep == ',')
190 error(Q);
191 if(a1 == 0) {
192 a1 = zero+1;
193 if(a1 > dol)
194 a1--;
196 addr1 = a1;
197 if(c == ';')
198 dot = a1;
200 if(lastsep != '\n' && a1 == 0)
201 a1 = dol;
202 if((addr2=a1) == 0) {
203 given = 0;
204 addr2 = dot;
205 } else
206 given = 1;
207 if(addr1 == 0)
208 addr1 = addr2;
209 switch(c) {
211 case 'a':
212 add(0);
213 continue;
215 case 'b':
216 nonzero();
217 browse();
218 continue;
220 case 'c':
221 nonzero();
222 newline();
223 rdelete(addr1, addr2);
224 append(gettty, addr1-1);
225 continue;
227 case 'd':
228 nonzero();
229 newline();
230 rdelete(addr1, addr2);
231 continue;
233 case 'E':
234 fchange = 0;
235 c = 'e';
236 case 'e':
237 setnoaddr();
238 if(vflag && fchange) {
239 fchange = 0;
240 error(Q);
242 filename(c);
243 init();
244 addr2 = zero;
245 goto caseread;
247 case 'f':
248 setnoaddr();
249 filename(c);
250 putst(savedfile);
251 continue;
253 case 'g':
254 global(1);
255 continue;
257 case 'i':
258 add(-1);
259 continue;
262 case 'j':
263 if(!given)
264 addr2++;
265 newline();
266 join();
267 continue;
269 case 'k':
270 nonzero();
271 c = getchr();
272 if(c < 'a' || c > 'z')
273 error(Q);
274 newline();
275 names[c-'a'] = *addr2 & ~01;
276 anymarks |= 01;
277 continue;
279 case 'm':
280 move(0);
281 continue;
283 case 'n':
284 listn++;
285 newline();
286 printcom();
287 continue;
289 case '\n':
290 if(a1==0) {
291 a1 = dot+1;
292 addr2 = a1;
293 addr1 = a1;
295 if(lastsep==';')
296 addr1 = a1;
297 printcom();
298 continue;
300 case 'l':
301 listf++;
302 case 'p':
303 case 'P':
304 newline();
305 printcom();
306 continue;
308 case 'Q':
309 fchange = 0;
310 case 'q':
311 setnoaddr();
312 newline();
313 quit();
315 case 'r':
316 filename(c);
317 caseread:
318 if((io=open(file, OREAD)) < 0) {
319 lastc = '\n';
320 error(file);
322 if((d = dirfstat(io)) != nil){
323 if(d->mode & DMAPPEND)
324 print("warning: %s is append only\n", file);
325 free(d);
327 Binit(&iobuf, io, OREAD);
328 setwide();
329 squeeze(0);
330 c = zero != dol;
331 append(getfile, addr2);
332 exfile(OREAD);
334 fchange = c;
335 continue;
337 case 's':
338 nonzero();
339 substitute(globp != 0);
340 continue;
342 case 't':
343 move(1);
344 continue;
346 case 'u':
347 nonzero();
348 newline();
349 if((*addr2&~01) != subnewa)
350 error(Q);
351 *addr2 = subolda;
352 dot = addr2;
353 continue;
355 case 'v':
356 global(0);
357 continue;
359 case 'W':
360 wrapp++;
361 case 'w':
362 setwide();
363 squeeze(dol>zero);
364 temp = getchr();
365 if(temp != 'q' && temp != 'Q') {
366 peekc = temp;
367 temp = 0;
369 filename(c);
370 if(!wrapp ||
371 ((io = open(file, OWRITE)) == -1) ||
372 ((seek(io, 0L, 2)) == -1))
373 if((io = create(file, OWRITE, 0666)) < 0)
374 error(file);
375 Binit(&iobuf, io, OWRITE);
376 wrapp = 0;
377 if(dol > zero)
378 putfile();
379 exfile(OWRITE);
380 if(addr1<=zero+1 && addr2==dol)
381 fchange = 0;
382 if(temp == 'Q')
383 fchange = 0;
384 if(temp)
385 quit();
386 continue;
388 case '=':
389 setwide();
390 squeeze(0);
391 newline();
392 count = addr2 - zero;
393 putd();
394 putchr(L'\n');
395 continue;
397 case '!':
398 callunix();
399 continue;
401 case EOF:
402 return;
405 error(Q);
409 void
410 printcom(void)
412 int *a1;
414 nonzero();
415 a1 = addr1;
416 do {
417 if(listn) {
418 count = a1-zero;
419 putd();
420 putchr(L'\t');
422 putshst(getline(*a1++));
423 } while(a1 <= addr2);
424 dot = addr2;
425 listf = 0;
426 listn = 0;
427 pflag = 0;
430 int*
431 address(void)
433 int sign, *a, opcnt, nextopand, *b, c;
435 nextopand = -1;
436 sign = 1;
437 opcnt = 0;
438 a = dot;
439 do {
440 do {
441 c = getchr();
442 } while(c == ' ' || c == '\t');
443 if(c >= '0' && c <= '9') {
444 peekc = c;
445 if(!opcnt)
446 a = zero;
447 a += sign*getnum();
448 } else
449 switch(c) {
450 case '$':
451 a = dol;
452 case '.':
453 if(opcnt)
454 error(Q);
455 break;
456 case '\'':
457 c = getchr();
458 if(opcnt || c < 'a' || c > 'z')
459 error(Q);
460 a = zero;
461 do {
462 a++;
463 } while(a <= dol && names[c-'a'] != (*a & ~01));
464 break;
465 case '?':
466 sign = -sign;
467 case '/':
468 compile(c);
469 b = a;
470 for(;;) {
471 a += sign;
472 if(a <= zero)
473 a = dol;
474 if(a > dol)
475 a = zero;
476 if(match(a))
477 break;
478 if(a == b)
479 error(Q);
481 break;
482 default:
483 if(nextopand == opcnt) {
484 a += sign;
485 if(a < zero || dol < a)
486 continue; /* error(Q); */
488 if(c != '+' && c != '-' && c != '^') {
489 peekc = c;
490 if(opcnt == 0)
491 a = 0;
492 return a;
494 sign = 1;
495 if(c != '+')
496 sign = -sign;
497 nextopand = ++opcnt;
498 continue;
500 sign = 1;
501 opcnt++;
502 } while(zero <= a && a <= dol);
503 error(Q);
504 return 0;
507 int
508 getnum(void)
510 int r, c;
512 r = 0;
513 for(;;) {
514 c = getchr();
515 if(c < '0' || c > '9')
516 break;
517 r = r*10 + (c-'0');
519 peekc = c;
520 return r;
523 void
524 setwide(void)
526 if(!given) {
527 addr1 = zero + (dol>zero);
528 addr2 = dol;
532 void
533 setnoaddr(void)
535 if(given)
536 error(Q);
539 void
540 nonzero(void)
542 squeeze(1);
545 void
546 squeeze(int i)
548 if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
549 error(Q);
552 void
553 newline(void)
555 int c;
557 c = getchr();
558 if(c == '\n' || c == EOF)
559 return;
560 if(c == 'p' || c == 'l' || c == 'n') {
561 pflag++;
562 if(c == 'l')
563 listf++;
564 else
565 if(c == 'n')
566 listn++;
567 c = getchr();
568 if(c == '\n')
569 return;
571 error(Q);
574 void
575 filename(int comm)
577 char *p1, *p2;
578 Rune rune;
579 int c;
581 count = 0;
582 c = getchr();
583 if(c == '\n' || c == EOF) {
584 p1 = savedfile;
585 if(*p1 == 0 && comm != 'f')
586 error(Q);
587 p2 = file;
588 while(*p2++ = *p1++)
590 return;
592 if(c != ' ')
593 error(Q);
594 while((c=getchr()) == ' ')
596 if(c == '\n')
597 error(Q);
598 p1 = file;
599 do {
600 if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)
601 error(Q);
602 rune = c;
603 p1 += runetochar(p1, &rune);
604 } while((c=getchr()) != '\n');
605 *p1 = 0;
606 if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {
607 p1 = savedfile;
608 p2 = file;
609 while(*p1++ = *p2++)
614 void
615 exfile(int om)
618 if(om == OWRITE)
619 if(Bflush(&iobuf) < 0)
620 error(Q);
621 close(io);
622 io = -1;
623 if(vflag) {
624 putd();
625 putchr(L'\n');
629 void
630 error1(char *s)
632 int c;
634 wrapp = 0;
635 listf = 0;
636 listn = 0;
637 count = 0;
638 seek(0, 0, 2);
639 pflag = 0;
640 if(globp)
641 lastc = '\n';
642 globp = 0;
643 peekc = lastc;
644 if(lastc)
645 for(;;) {
646 c = getchr();
647 if(c == '\n' || c == EOF)
648 break;
650 if(io > 0) {
651 close(io);
652 io = -1;
654 putchr(L'?');
655 putst(s);
658 void
659 error(char *s)
661 error1(s);
662 longjmp(savej, 1);
665 void
666 rescue(void)
668 rescuing = 1;
669 if(dol > zero) {
670 addr1 = zero+1;
671 addr2 = dol;
672 io = create("ed.hup", OWRITE, 0666);
673 if(io > 0){
674 Binit(&iobuf, io, OWRITE);
675 putfile();
678 fchange = 0;
679 quit();
682 void
683 notifyf(void *a, char *s)
685 if(strcmp(s, "interrupt") == 0){
686 if(rescuing || waiting)
687 noted(NCONT);
688 putchr(L'\n');
689 lastc = '\n';
690 error1(Q);
691 notejmp(a, savej, 0);
693 if(strcmp(s, "hangup") == 0){
694 if(rescuing)
695 noted(NDFLT);
696 rescue();
698 fprint(2, "ed: note: %s\n", s);
699 abort();
702 int
703 getchr(void)
705 char s[UTFmax];
706 int i;
707 Rune r;
709 if(lastc = peekc) {
710 peekc = 0;
711 return lastc;
713 if(globp) {
714 if((lastc=*globp++) != 0)
715 return lastc;
716 globp = 0;
717 return EOF;
719 for(i=0;;) {
720 if(read(0, s+i, 1) <= 0)
721 return lastc = EOF;
722 i++;
723 if(fullrune(s, i))
724 break;
727 chartorune(&r, s);
728 lastc = r;
729 return lastc;
732 int
733 gety(void)
735 int c;
736 Rune *gf, *p;
738 p = linebuf;
739 gf = globp;
740 for(;;) {
741 c = getchr();
742 if(c == '\n') {
743 *p = 0;
744 return 0;
746 if(c == EOF) {
747 if(gf)
748 peekc = c;
749 return c;
751 if(c == 0)
752 continue;
753 *p++ = c;
754 if(p >= &linebuf[LBSIZE-2])
755 error(Q);
757 return 0;
760 int
761 gettty(void)
763 int rc;
765 rc = gety();
766 if(rc)
767 return rc;
768 if(linebuf[0] == '.' && linebuf[1] == 0)
769 return EOF;
770 return 0;
773 int
774 getfile(void)
776 int c;
777 Rune *lp;
779 lp = linebuf;
780 do {
781 c = Bgetrune(&iobuf);
782 if(c < 0) {
783 if(lp > linebuf) {
784 putst("'\\n' appended");
785 c = '\n';
786 } else
787 return EOF;
789 if(lp >= &linebuf[LBSIZE]) {
790 lastc = '\n';
791 error(Q);
793 *lp++ = c;
794 count++;
795 } while(c != '\n');
796 lp[-1] = 0;
797 return 0;
800 void
801 putfile(void)
803 int *a1;
804 Rune *lp;
805 long c;
807 a1 = addr1;
808 do {
809 lp = getline(*a1++);
810 for(;;) {
811 count++;
812 c = *lp++;
813 if(c == 0) {
814 if(Bputrune(&iobuf, '\n') < 0)
815 error(Q);
816 break;
818 if(Bputrune(&iobuf, c) < 0)
819 error(Q);
821 } while(a1 <= addr2);
822 if(Bflush(&iobuf) < 0)
823 error(Q);
826 int
827 append(int (*f)(void), int *a)
829 int *a1, *a2, *rdot, nline, tl;
831 nline = 0;
832 dot = a;
833 while((*f)() == 0) {
834 if((dol-zero) >= nlall) {
835 nlall += 512;
836 a1 = realloc(zero, (nlall+5)*sizeof(int*));
837 if(a1 == 0) {
838 error("MEM?");
839 rescue();
841 tl = a1 - zero; /* relocate pointers */
842 zero += tl;
843 addr1 += tl;
844 addr2 += tl;
845 dol += tl;
846 dot += tl;
848 tl = putline();
849 nline++;
850 a1 = ++dol;
851 a2 = a1+1;
852 rdot = ++dot;
853 while(a1 > rdot)
854 *--a2 = *--a1;
855 *rdot = tl;
857 return nline;
860 void
861 add(int i)
863 if(i && (given || dol > zero)) {
864 addr1--;
865 addr2--;
867 squeeze(0);
868 newline();
869 append(gettty, addr2);
872 void
873 browse(void)
875 int forward, n;
876 static int bformat, bnum; /* 0 */
878 forward = 1;
879 peekc = getchr();
880 if(peekc != '\n'){
881 if(peekc == '-' || peekc == '+') {
882 if(peekc == '-')
883 forward = 0;
884 getchr();
886 n = getnum();
887 if(n > 0)
888 bpagesize = n;
890 newline();
891 if(pflag) {
892 bformat = listf;
893 bnum = listn;
894 } else {
895 listf = bformat;
896 listn = bnum;
898 if(forward) {
899 addr1 = addr2;
900 addr2 += bpagesize;
901 if(addr2 > dol)
902 addr2 = dol;
903 } else {
904 addr1 = addr2-bpagesize;
905 if(addr1 <= zero)
906 addr1 = zero+1;
908 printcom();
911 void
912 callunix(void)
914 int c, pid;
915 Rune rune;
916 char buf[512];
917 char *p;
919 setnoaddr();
920 p = buf;
921 while((c=getchr()) != EOF && c != '\n')
922 if(p < &buf[sizeof(buf) - 6]) {
923 rune = c;
924 p += runetochar(p, &rune);
926 *p = 0;
927 pid = fork();
928 if(pid == 0) {
929 execl("/bin/rc", "rc", "-c", buf, 0);
930 exits("execl failed");
932 waiting = 1;
933 while(waitpid() != pid)
935 waiting = 0;
936 if(vflag)
937 putst("!");
940 void
941 quit(void)
943 if(vflag && fchange && dol!=zero) {
944 fchange = 0;
945 error(Q);
947 remove(tfname);
948 exits(0);
951 void
952 onquit(int sig)
954 USED(sig);
955 quit();
958 void
959 rdelete(int *ad1, int *ad2)
961 int *a1, *a2, *a3;
963 a1 = ad1;
964 a2 = ad2+1;
965 a3 = dol;
966 dol -= a2 - a1;
967 do {
968 *a1++ = *a2++;
969 } while(a2 <= a3);
970 a1 = ad1;
971 if(a1 > dol)
972 a1 = dol;
973 dot = a1;
974 fchange = 1;
977 void
978 gdelete(void)
980 int *a1, *a2, *a3;
982 a3 = dol;
983 for(a1=zero; (*a1&01)==0; a1++)
984 if(a1>=a3)
985 return;
986 for(a2=a1+1; a2<=a3;) {
987 if(*a2 & 01) {
988 a2++;
989 dot = a1;
990 } else
991 *a1++ = *a2++;
993 dol = a1-1;
994 if(dot > dol)
995 dot = dol;
996 fchange = 1;
999 Rune*
1000 getline(int tl)
1002 Rune *lp, *bp;
1003 int nl;
1005 lp = linebuf;
1006 bp = getblock(tl, OREAD);
1007 nl = nleft;
1008 tl &= ~((BLKSIZE/2) - 1);
1009 while(*lp++ = *bp++) {
1010 nl -= sizeof(Rune);
1011 if(nl == 0) {
1012 bp = getblock(tl += BLKSIZE/2, OREAD);
1013 nl = nleft;
1016 return linebuf;
1019 int
1020 putline(void)
1022 Rune *lp, *bp;
1023 int nl, tl;
1025 fchange = 1;
1026 lp = linebuf;
1027 tl = tline;
1028 bp = getblock(tl, OWRITE);
1029 nl = nleft;
1030 tl &= ~((BLKSIZE/2)-1);
1031 while(*bp = *lp++) {
1032 if(*bp++ == '\n') {
1033 bp[-1] = 0;
1034 linebp = lp;
1035 break;
1037 nl -= sizeof(Rune);
1038 if(nl == 0) {
1039 tl += BLKSIZE/2;
1040 bp = getblock(tl, OWRITE);
1041 nl = nleft;
1044 nl = tline;
1045 tline += ((lp-linebuf) + 03) & 077776;
1046 return nl;
1049 void
1050 blkio(int b, uchar *buf, int isread)
1052 int n;
1054 seek(tfile, b*BLKSIZE, 0);
1055 if(isread)
1056 n = read(tfile, buf, BLKSIZE);
1057 else
1058 n = write(tfile, buf, BLKSIZE);
1059 if(n != BLKSIZE)
1060 error(T);
1063 Rune*
1064 getblock(int atl, int iof)
1066 int bno, off;
1068 static uchar ibuff[BLKSIZE];
1069 static uchar obuff[BLKSIZE];
1071 bno = atl / (BLKSIZE/2);
1072 off = (atl<<1) & (BLKSIZE-1) & ~03;
1073 if(bno >= NBLK) {
1074 lastc = '\n';
1075 error(T);
1077 nleft = BLKSIZE - off;
1078 if(bno == iblock) {
1079 ichanged |= iof;
1080 return (Rune*)(ibuff+off);
1082 if(bno == oblock)
1083 return (Rune*)(obuff+off);
1084 if(iof == OREAD) {
1085 if(ichanged)
1086 blkio(iblock, ibuff, 0);
1087 ichanged = 0;
1088 iblock = bno;
1089 blkio(bno, ibuff, 1);
1090 return (Rune*)(ibuff+off);
1092 if(oblock >= 0)
1093 blkio(oblock, obuff, 0);
1094 oblock = bno;
1095 return (Rune*)(obuff+off);
1098 void
1099 init(void)
1101 int *markp;
1103 close(tfile);
1104 tline = 2;
1105 for(markp = names; markp < &names[26]; )
1106 *markp++ = 0;
1107 subnewa = 0;
1108 anymarks = 0;
1109 iblock = -1;
1110 oblock = -1;
1111 ichanged = 0;
1112 if((tfile = create(tfname, ORDWR, 0600)) < 0){
1113 error1(T);
1114 exits(0);
1116 dot = dol = zero;
1119 void
1120 global(int k)
1122 Rune *gp, globuf[GBSIZE];
1123 int c, *a1;
1125 if(globp)
1126 error(Q);
1127 setwide();
1128 squeeze(dol > zero);
1129 c = getchr();
1130 if(c == '\n')
1131 error(Q);
1132 compile(c);
1133 gp = globuf;
1134 while((c=getchr()) != '\n') {
1135 if(c == EOF)
1136 error(Q);
1137 if(c == '\\') {
1138 c = getchr();
1139 if(c != '\n')
1140 *gp++ = '\\';
1142 *gp++ = c;
1143 if(gp >= &globuf[GBSIZE-2])
1144 error(Q);
1146 if(gp == globuf)
1147 *gp++ = 'p';
1148 *gp++ = '\n';
1149 *gp = 0;
1150 for(a1=zero; a1<=dol; a1++) {
1151 *a1 &= ~01;
1152 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1153 *a1 |= 01;
1157 * Special case: g/.../d (avoid n^2 algorithm)
1159 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1160 gdelete();
1161 return;
1163 for(a1=zero; a1<=dol; a1++) {
1164 if(*a1 & 01) {
1165 *a1 &= ~01;
1166 dot = a1;
1167 globp = globuf;
1168 commands();
1169 a1 = zero;
1174 void
1175 join(void)
1177 Rune *gp, *lp;
1178 int *a1;
1180 nonzero();
1181 gp = genbuf;
1182 for(a1=addr1; a1<=addr2; a1++) {
1183 lp = getline(*a1);
1184 while(*gp = *lp++)
1185 if(gp++ >= &genbuf[LBSIZE-2])
1186 error(Q);
1188 lp = linebuf;
1189 gp = genbuf;
1190 while(*lp++ = *gp++)
1192 *addr1 = putline();
1193 if(addr1 < addr2)
1194 rdelete(addr1+1, addr2);
1195 dot = addr1;
1198 void
1199 substitute(int inglob)
1201 int *mp, *a1, nl, gsubf, n;
1203 n = getnum(); /* OK even if n==0 */
1204 gsubf = compsub();
1205 for(a1 = addr1; a1 <= addr2; a1++) {
1206 if(match(a1)){
1207 int *ozero;
1208 int m = n;
1210 do {
1211 int span = loc2-loc1;
1213 if(--m <= 0) {
1214 dosub();
1215 if(!gsubf)
1216 break;
1217 if(span == 0) { /* null RE match */
1218 if(*loc2 == 0)
1219 break;
1220 loc2++;
1223 } while(match(0));
1224 if(m <= 0) {
1225 inglob |= 01;
1226 subnewa = putline();
1227 *a1 &= ~01;
1228 if(anymarks) {
1229 for(mp=names; mp<&names[26]; mp++)
1230 if(*mp == *a1)
1231 *mp = subnewa;
1233 subolda = *a1;
1234 *a1 = subnewa;
1235 ozero = zero;
1236 nl = append(getsub, a1);
1237 addr2 += nl;
1238 nl += zero-ozero;
1239 a1 += nl;
1243 if(inglob == 0)
1244 error(Q);
1247 int
1248 compsub(void)
1250 int seof, c;
1251 Rune *p;
1253 seof = getchr();
1254 if(seof == '\n' || seof == ' ')
1255 error(Q);
1256 compile(seof);
1257 p = rhsbuf;
1258 for(;;) {
1259 c = getchr();
1260 if(c == '\\') {
1261 c = getchr();
1262 *p++ = ESCFLG;
1263 if(p >= &rhsbuf[LBSIZE/2])
1264 error(Q);
1265 } else
1266 if(c == '\n' && (!globp || !globp[0])) {
1267 peekc = c;
1268 pflag++;
1269 break;
1270 } else
1271 if(c == seof)
1272 break;
1273 *p++ = c;
1274 if(p >= &rhsbuf[LBSIZE/2])
1275 error(Q);
1277 *p = 0;
1278 peekc = getchr();
1279 if(peekc == 'g') {
1280 peekc = 0;
1281 newline();
1282 return 1;
1284 newline();
1285 return 0;
1288 int
1289 getsub(void)
1291 Rune *p1, *p2;
1293 p1 = linebuf;
1294 if((p2 = linebp) == 0)
1295 return EOF;
1296 while(*p1++ = *p2++)
1298 linebp = 0;
1299 return 0;
1302 void
1303 dosub(void)
1305 Rune *lp, *sp, *rp;
1306 int c, n;
1308 lp = linebuf;
1309 sp = genbuf;
1310 rp = rhsbuf;
1311 while(lp < loc1)
1312 *sp++ = *lp++;
1313 while(c = *rp++) {
1314 if(c == '&'){
1315 sp = place(sp, loc1, loc2);
1316 continue;
1318 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1319 n = c-'0';
1320 if(subexp[n].s.rsp && subexp[n].e.rep) {
1321 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
1322 continue;
1324 error(Q);
1326 *sp++ = c;
1327 if(sp >= &genbuf[LBSIZE])
1328 error(Q);
1330 lp = loc2;
1331 loc2 = sp - genbuf + linebuf;
1332 while(*sp++ = *lp++)
1333 if(sp >= &genbuf[LBSIZE])
1334 error(Q);
1335 lp = linebuf;
1336 sp = genbuf;
1337 while(*lp++ = *sp++)
1341 Rune*
1342 place(Rune *sp, Rune *l1, Rune *l2)
1345 while(l1 < l2) {
1346 *sp++ = *l1++;
1347 if(sp >= &genbuf[LBSIZE])
1348 error(Q);
1350 return sp;
1353 void
1354 move(int cflag)
1356 int *adt, *ad1, *ad2;
1358 nonzero();
1359 if((adt = address())==0) /* address() guarantees addr is in range */
1360 error(Q);
1361 newline();
1362 if(cflag) {
1363 int *ozero, delta;
1364 ad1 = dol;
1365 ozero = zero;
1366 append(getcopy, ad1++);
1367 ad2 = dol;
1368 delta = zero - ozero;
1369 ad1 += delta;
1370 adt += delta;
1371 } else {
1372 ad2 = addr2;
1373 for(ad1 = addr1; ad1 <= ad2;)
1374 *ad1++ &= ~01;
1375 ad1 = addr1;
1377 ad2++;
1378 if(adt<ad1) {
1379 dot = adt + (ad2-ad1);
1380 if((++adt)==ad1)
1381 return;
1382 reverse(adt, ad1);
1383 reverse(ad1, ad2);
1384 reverse(adt, ad2);
1385 } else
1386 if(adt >= ad2) {
1387 dot = adt++;
1388 reverse(ad1, ad2);
1389 reverse(ad2, adt);
1390 reverse(ad1, adt);
1391 } else
1392 error(Q);
1393 fchange = 1;
1396 void
1397 reverse(int *a1, int *a2)
1399 int t;
1401 for(;;) {
1402 t = *--a2;
1403 if(a2 <= a1)
1404 return;
1405 *a2 = *a1;
1406 *a1++ = t;
1410 int
1411 getcopy(void)
1413 if(addr1 > addr2)
1414 return EOF;
1415 getline(*addr1++);
1416 return 0;
1419 void
1420 compile(int eof)
1422 Rune c;
1423 char *ep;
1424 char expbuf[ESIZE];
1426 if((c = getchr()) == '\n') {
1427 peekc = c;
1428 c = eof;
1430 if(c == eof) {
1431 if(!pattern)
1432 error(Q);
1433 return;
1435 if(pattern) {
1436 free(pattern);
1437 pattern = 0;
1439 ep = expbuf;
1440 do {
1441 if(c == '\\') {
1442 if(ep >= expbuf+sizeof(expbuf)) {
1443 error(Q);
1444 return;
1446 ep += runetochar(ep, &c);
1447 if((c = getchr()) == '\n') {
1448 error(Q);
1449 return;
1452 if(ep >= expbuf+sizeof(expbuf)) {
1453 error(Q);
1454 return;
1456 ep += runetochar(ep, &c);
1457 } while((c = getchr()) != eof && c != '\n');
1458 if(c == '\n')
1459 peekc = c;
1460 *ep = 0;
1461 pattern = regcomp(expbuf);
1464 int
1465 match(int *addr)
1467 if(!pattern)
1468 return 0;
1469 if(addr){
1470 if(addr == zero)
1471 return 0;
1472 subexp[0].s.rsp = getline(*addr);
1473 } else
1474 subexp[0].s.rsp = loc2;
1475 subexp[0].e.rep = 0;
1476 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1477 loc1 = subexp[0].s.rsp;
1478 loc2 = subexp[0].e.rep;
1479 return 1;
1481 loc1 = loc2 = 0;
1482 return 0;
1486 void
1487 putd(void)
1489 int r;
1491 r = count%10;
1492 count /= 10;
1493 if(count)
1494 putd();
1495 putchr(r + L'0');
1498 void
1499 putst(char *sp)
1501 Rune r;
1503 col = 0;
1504 for(;;) {
1505 sp += chartorune(&r, sp);
1506 if(r == 0)
1507 break;
1508 putchr(r);
1510 putchr(L'\n');
1513 void
1514 putshst(Rune *sp)
1516 col = 0;
1517 while(*sp)
1518 putchr(*sp++);
1519 putchr(L'\n');
1522 void
1523 putchr(int ac)
1525 char *lp;
1526 int c;
1527 Rune rune;
1529 lp = linp;
1530 c = ac;
1531 if(listf) {
1532 if(c == '\n') {
1533 if(linp != line && linp[-1] == ' ') {
1534 *lp++ = '\\';
1535 *lp++ = 'n';
1537 } else {
1538 if(col > (72-6-2)) {
1539 col = 8;
1540 *lp++ = '\\';
1541 *lp++ = '\n';
1542 *lp++ = '\t';
1544 col++;
1545 if(c=='\b' || c=='\t' || c=='\\') {
1546 *lp++ = '\\';
1547 if(c == '\b')
1548 c = 'b';
1549 else
1550 if(c == '\t')
1551 c = 't';
1552 col++;
1553 } else
1554 if(c<' ' || c>='\177') {
1555 *lp++ = '\\';
1556 *lp++ = 'x';
1557 *lp++ = hex[c>>12];
1558 *lp++ = hex[c>>8&0xF];
1559 *lp++ = hex[c>>4&0xF];
1560 c = hex[c&0xF];
1561 col += 5;
1566 rune = c;
1567 lp += runetochar(lp, &rune);
1569 if(c == '\n' || lp >= &line[sizeof(line)-5]) {
1570 linp = line;
1571 write(oflag? 2: 1, line, lp-line);
1572 return;
1574 linp = lp;
1577 char*
1578 mktemp(char *as)
1580 char *s;
1581 unsigned pid;
1582 int i;
1584 pid = getpid();
1585 s = as;
1586 while(*s++)
1588 s--;
1589 while(*--s == 'X') {
1590 *s = pid % 10 + '0';
1591 pid /= 10;
1593 s++;
1594 i = 'a';
1595 while(access(as, 0) != -1) {
1596 if(i == 'z')
1597 return "/";
1598 *s = i++;
1600 return as;
1603 void
1604 regerror(char *s)
1606 USED(s);
1607 error(Q);