1 /*
2 * Editor
3 */
4 #include <u.h>
5 #include <libc.h>
6 #include <bio.h>
7 #include <regexp.h>
8
9 #undef EOF /* stdio? */
10
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 };
23
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/sizeof(Rune)];
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;
69
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;
79
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);
124 char* _mktemp(char *as);
125
126 Rune La[] = { 'a', 0 };
127 Rune Lr[] = { 'r', 0 };
128
129 char tmp[] = "/var/tmp/eXXXXX";
130
131 void
main(int argc,char * argv[])132 main(int argc, char *argv[])
133 {
134 char *p1, *p2;
135
136 notify(notifyf);
137 ARGBEGIN {
138 case 'o':
139 oflag = 1;
140 vflag = 0;
141 break;
142 } ARGEND
143
144 USED(argc);
145 if(*argv && (strcmp(*argv, "-") == 0)) {
146 argv++;
147 vflag = 0;
148 }
149 if(oflag) {
150 p1 = "/dev/stdout";
151 p2 = savedfile;
152 while(*p2++ = *p1++)
153 ;
154 globp = La;
155 } else
156 if(*argv) {
157 p1 = *argv;
158 p2 = savedfile;
159 while(*p2++ = *p1++)
160 if(p2 >= &savedfile[sizeof(savedfile)])
161 p2--;
162 globp = Lr;
163 }
164 zero = malloc((nlall+5)*sizeof(int*));
165 tfname = _mktemp(tmp);
166 init();
167 setjmp(savej);
168 commands();
169 quit();
170 }
171
172 void
commands(void)173 commands(void)
174 {
175 int *a1, c, temp;
176 char lastsep;
177 Dir *d;
178
179 for(;;) {
180 if(pflag) {
181 pflag = 0;
182 addr1 = addr2 = dot;
183 printcom();
184 }
185 c = '\n';
186 for(addr1 = 0;;) {
187 lastsep = c;
188 a1 = address();
189 c = getchr();
190 if(c != ',' && c != ';')
191 break;
192 if(lastsep == ',')
193 error(Q);
194 if(a1 == 0) {
195 a1 = zero+1;
196 if(a1 > dol)
197 a1--;
198 }
199 addr1 = a1;
200 if(c == ';')
201 dot = a1;
202 }
203 if(lastsep != '\n' && a1 == 0)
204 a1 = dol;
205 if((addr2=a1) == 0) {
206 given = 0;
207 addr2 = dot;
208 } else
209 given = 1;
210 if(addr1 == 0)
211 addr1 = addr2;
212 switch(c) {
213
214 case 'a':
215 add(0);
216 continue;
217
218 case 'b':
219 nonzero();
220 browse();
221 continue;
222
223 case 'c':
224 nonzero();
225 newline();
226 rdelete(addr1, addr2);
227 append(gettty, addr1-1);
228 continue;
229
230 case 'd':
231 nonzero();
232 newline();
233 rdelete(addr1, addr2);
234 continue;
235
236 case 'E':
237 fchange = 0;
238 c = 'e';
239 case 'e':
240 setnoaddr();
241 if(vflag && fchange) {
242 fchange = 0;
243 error(Q);
244 }
245 filename(c);
246 init();
247 addr2 = zero;
248 goto caseread;
249
250 case 'f':
251 setnoaddr();
252 filename(c);
253 putst(savedfile);
254 continue;
255
256 case 'g':
257 global(1);
258 continue;
259
260 case 'i':
261 add(-1);
262 continue;
263
264
265 case 'j':
266 if(!given)
267 addr2++;
268 newline();
269 join();
270 continue;
271
272 case 'k':
273 nonzero();
274 c = getchr();
275 if(c < 'a' || c > 'z')
276 error(Q);
277 newline();
278 names[c-'a'] = *addr2 & ~01;
279 anymarks |= 01;
280 continue;
281
282 case 'm':
283 move(0);
284 continue;
285
286 case 'n':
287 listn++;
288 newline();
289 printcom();
290 continue;
291
292 case '\n':
293 if(a1==0) {
294 a1 = dot+1;
295 addr2 = a1;
296 addr1 = a1;
297 }
298 if(lastsep==';')
299 addr1 = a1;
300 printcom();
301 continue;
302
303 case 'l':
304 listf++;
305 case 'p':
306 case 'P':
307 newline();
308 printcom();
309 continue;
310
311 case 'Q':
312 fchange = 0;
313 case 'q':
314 setnoaddr();
315 newline();
316 quit();
317
318 case 'r':
319 filename(c);
320 caseread:
321 if((io=open(file, OREAD)) < 0) {
322 lastc = '\n';
323 error(file);
324 }
325 if((d = dirfstat(io)) != nil){
326 if(d->mode & DMAPPEND)
327 print("warning: %s is append only\n", file);
328 free(d);
329 }
330 Binit(&iobuf, io, OREAD);
331 setwide();
332 squeeze(0);
333 c = zero != dol;
334 append(getfile, addr2);
335 exfile(OREAD);
336
337 fchange = c;
338 continue;
339
340 case 's':
341 nonzero();
342 substitute(globp != 0);
343 continue;
344
345 case 't':
346 move(1);
347 continue;
348
349 case 'u':
350 nonzero();
351 newline();
352 if((*addr2&~01) != subnewa)
353 error(Q);
354 *addr2 = subolda;
355 dot = addr2;
356 continue;
357
358 case 'v':
359 global(0);
360 continue;
361
362 case 'W':
363 wrapp++;
364 case 'w':
365 setwide();
366 squeeze(dol>zero);
367 temp = getchr();
368 if(temp != 'q' && temp != 'Q') {
369 peekc = temp;
370 temp = 0;
371 }
372 filename(c);
373 if(!wrapp ||
374 ((io = open(file, OWRITE)) == -1) ||
375 ((seek(io, 0L, 2)) == -1))
376 if((io = create(file, OWRITE, 0666)) < 0)
377 error(file);
378 Binit(&iobuf, io, OWRITE);
379 wrapp = 0;
380 if(dol > zero)
381 putfile();
382 exfile(OWRITE);
383 if(addr1<=zero+1 && addr2==dol)
384 fchange = 0;
385 if(temp == 'Q')
386 fchange = 0;
387 if(temp)
388 quit();
389 continue;
390
391 case '=':
392 setwide();
393 squeeze(0);
394 newline();
395 count = addr2 - zero;
396 putd();
397 putchr('\n');
398 continue;
399
400 case '!':
401 callunix();
402 continue;
403
404 case EOF:
405 return;
406
407 }
408 error(Q);
409 }
410 }
411
412 void
printcom(void)413 printcom(void)
414 {
415 int *a1;
416
417 nonzero();
418 a1 = addr1;
419 do {
420 if(listn) {
421 count = a1-zero;
422 putd();
423 putchr('\t');
424 }
425 putshst(getline(*a1++));
426 } while(a1 <= addr2);
427 dot = addr2;
428 listf = 0;
429 listn = 0;
430 pflag = 0;
431 }
432
433 int*
address(void)434 address(void)
435 {
436 int sign, *a, opcnt, nextopand, *b, c;
437
438 nextopand = -1;
439 sign = 1;
440 opcnt = 0;
441 a = dot;
442 do {
443 do {
444 c = getchr();
445 } while(c == ' ' || c == '\t');
446 if(c >= '0' && c <= '9') {
447 peekc = c;
448 if(!opcnt)
449 a = zero;
450 a += sign*getnum();
451 } else
452 switch(c) {
453 case '$':
454 a = dol;
455 case '.':
456 if(opcnt)
457 error(Q);
458 break;
459 case '\'':
460 c = getchr();
461 if(opcnt || c < 'a' || c > 'z')
462 error(Q);
463 a = zero;
464 do {
465 a++;
466 } while(a <= dol && names[c-'a'] != (*a & ~01));
467 break;
468 case '?':
469 sign = -sign;
470 case '/':
471 compile(c);
472 b = a;
473 for(;;) {
474 a += sign;
475 if(a <= zero)
476 a = dol;
477 if(a > dol)
478 a = zero;
479 if(match(a))
480 break;
481 if(a == b)
482 error(Q);
483 }
484 break;
485 default:
486 if(nextopand == opcnt) {
487 a += sign;
488 if(a < zero || dol < a)
489 continue; /* error(Q); */
490 }
491 if(c != '+' && c != '-' && c != '^') {
492 peekc = c;
493 if(opcnt == 0)
494 a = 0;
495 return a;
496 }
497 sign = 1;
498 if(c != '+')
499 sign = -sign;
500 nextopand = ++opcnt;
501 continue;
502 }
503 sign = 1;
504 opcnt++;
505 } while(zero <= a && a <= dol);
506 error(Q);
507 return 0;
508 }
509
510 int
getnum(void)511 getnum(void)
512 {
513 int r, c;
514
515 r = 0;
516 for(;;) {
517 c = getchr();
518 if(c < '0' || c > '9')
519 break;
520 r = r*10 + (c-'0');
521 }
522 peekc = c;
523 return r;
524 }
525
526 void
setwide(void)527 setwide(void)
528 {
529 if(!given) {
530 addr1 = zero + (dol>zero);
531 addr2 = dol;
532 }
533 }
534
535 void
setnoaddr(void)536 setnoaddr(void)
537 {
538 if(given)
539 error(Q);
540 }
541
542 void
nonzero(void)543 nonzero(void)
544 {
545 squeeze(1);
546 }
547
548 void
squeeze(int i)549 squeeze(int i)
550 {
551 if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
552 error(Q);
553 }
554
555 void
newline(void)556 newline(void)
557 {
558 int c;
559
560 c = getchr();
561 if(c == '\n' || c == EOF)
562 return;
563 if(c == 'p' || c == 'l' || c == 'n') {
564 pflag++;
565 if(c == 'l')
566 listf++;
567 else
568 if(c == 'n')
569 listn++;
570 c = getchr();
571 if(c == '\n')
572 return;
573 }
574 error(Q);
575 }
576
577 void
filename(int comm)578 filename(int comm)
579 {
580 char *p1, *p2;
581 Rune rune;
582 int c;
583
584 count = 0;
585 c = getchr();
586 if(c == '\n' || c == EOF) {
587 p1 = savedfile;
588 if(*p1 == 0 && comm != 'f')
589 error(Q);
590 p2 = file;
591 while(*p2++ = *p1++)
592 ;
593 return;
594 }
595 if(c != ' ')
596 error(Q);
597 while((c=getchr()) == ' ')
598 ;
599 if(c == '\n')
600 error(Q);
601 p1 = file;
602 do {
603 if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)
604 error(Q);
605 rune = c;
606 p1 += runetochar(p1, &rune);
607 } while((c=getchr()) != '\n');
608 *p1 = 0;
609 if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {
610 p1 = savedfile;
611 p2 = file;
612 while(*p1++ = *p2++)
613 ;
614 }
615 }
616
617 void
exfile(int om)618 exfile(int om)
619 {
620
621 if(om == OWRITE)
622 if(Bflush(&iobuf) < 0)
623 error(Q);
624 close(io);
625 io = -1;
626 if(vflag) {
627 putd();
628 putchr('\n');
629 }
630 }
631
632 void
error1(char * s)633 error1(char *s)
634 {
635 int c;
636
637 wrapp = 0;
638 listf = 0;
639 listn = 0;
640 count = 0;
641 seek(0, 0, 2);
642 pflag = 0;
643 if(globp)
644 lastc = '\n';
645 globp = 0;
646 peekc = lastc;
647 if(lastc)
648 for(;;) {
649 c = getchr();
650 if(c == '\n' || c == EOF)
651 break;
652 }
653 if(io > 0) {
654 close(io);
655 io = -1;
656 }
657 putchr('?');
658 putst(s);
659 }
660
661 void
error(char * s)662 error(char *s)
663 {
664 error1(s);
665 longjmp(savej, 1);
666 }
667
668 void
rescue(void)669 rescue(void)
670 {
671 rescuing = 1;
672 if(dol > zero) {
673 addr1 = zero+1;
674 addr2 = dol;
675 io = create("ed.hup", OWRITE, 0666);
676 if(io > 0){
677 Binit(&iobuf, io, OWRITE);
678 putfile();
679 }
680 }
681 fchange = 0;
682 quit();
683 }
684
685 void
notifyf(void * a,char * s)686 notifyf(void *a, char *s)
687 {
688 if(strcmp(s, "interrupt") == 0){
689 if(rescuing || waiting)
690 noted(NCONT);
691 putchr('\n');
692 lastc = '\n';
693 error1(Q);
694 notejmp(a, savej, 0);
695 }
696 if(strcmp(s, "hangup") == 0 || strcmp(s, "kill") == 0){
697 if(rescuing)
698 noted(NDFLT);
699 rescue();
700 }
701 if(strstr(s, "child"))
702 noted(NCONT);
703 fprint(2, "ed: note: %s\n", s);
704 abort();
705 }
706
707 int
getchr(void)708 getchr(void)
709 {
710 char s[UTFmax];
711 int i;
712 Rune r;
713
714 if(lastc = peekc) {
715 peekc = 0;
716 return lastc;
717 }
718 if(globp) {
719 if((lastc=*globp++) != 0)
720 return lastc;
721 globp = 0;
722 return EOF;
723 }
724 for(i=0;;) {
725 if(read(0, s+i, 1) <= 0)
726 return lastc = EOF;
727 i++;
728 if(fullrune(s, i))
729 break;
730
731 }
732 chartorune(&r, s);
733 lastc = r;
734 return lastc;
735 }
736
737 int
gety(void)738 gety(void)
739 {
740 int c;
741 Rune *gf, *p;
742
743 p = linebuf;
744 gf = globp;
745 for(;;) {
746 c = getchr();
747 if(c == '\n') {
748 *p = 0;
749 return 0;
750 }
751 if(c == EOF) {
752 if(gf)
753 peekc = c;
754 return c;
755 }
756 if(c == 0)
757 continue;
758 *p++ = c;
759 if(p >= &linebuf[LBSIZE-2])
760 error(Q);
761 }
762 }
763
764 int
gettty(void)765 gettty(void)
766 {
767 int rc;
768
769 rc = gety();
770 if(rc)
771 return rc;
772 if(linebuf[0] == '.' && linebuf[1] == 0)
773 return EOF;
774 return 0;
775 }
776
777 int
getfile(void)778 getfile(void)
779 {
780 int c;
781 Rune *lp;
782
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;
792 }
793 if(lp >= &linebuf[LBSIZE]) {
794 lastc = '\n';
795 error(Q);
796 }
797 *lp++ = c;
798 count++;
799 } while(c != '\n');
800 lp[-1] = 0;
801 return 0;
802 }
803
804 void
putfile(void)805 putfile(void)
806 {
807 int *a1;
808 Rune *lp;
809 long c;
810
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;
821 }
822 if(Bputrune(&iobuf, c) < 0)
823 error(Q);
824 }
825 } while(a1 <= addr2);
826 if(Bflush(&iobuf) < 0)
827 error(Q);
828 }
829
830 int
append(int (* f)(void),int * a)831 append(int (*f)(void), int *a)
832 {
833 int *a1, *a2, *rdot, nline, d;
834
835 nline = 0;
836 dot = a;
837 while((*f)() == 0) {
838 if((dol-zero) >= nlall) {
839 nlall += 512;
840 a1 = realloc(zero, (nlall+50)*sizeof(int*));
841 if(a1 == 0) {
842 error("MEM?");
843 rescue();
844 }
845 /* relocate pointers; avoid wraparound if sizeof(int) < sizeof(int*) */
846 d = addr1 - zero;
847 addr1 = a1 + d;
848 d = addr2 - zero;
849 addr2 = a1 + d;
850 d = dol - zero;
851 dol = a1 + d;
852 d = dot - zero;
853 dot = a1 + d;
854 zero = a1;
855 }
856 d = putline();
857 nline++;
858 a1 = ++dol;
859 a2 = a1+1;
860 rdot = ++dot;
861 while(a1 > rdot)
862 *--a2 = *--a1;
863 *rdot = d;
864 }
865 return nline;
866 }
867
868 void
add(int i)869 add(int i)
870 {
871 if(i && (given || dol > zero)) {
872 addr1--;
873 addr2--;
874 }
875 squeeze(0);
876 newline();
877 append(gettty, addr2);
878 }
879
880 void
browse(void)881 browse(void)
882 {
883 int forward, n;
884 static int bformat, bnum; /* 0 */
885
886 forward = 1;
887 peekc = getchr();
888 if(peekc != '\n'){
889 if(peekc == '-' || peekc == '+') {
890 if(peekc == '-')
891 forward = 0;
892 getchr();
893 }
894 n = getnum();
895 if(n > 0)
896 bpagesize = n;
897 }
898 newline();
899 if(pflag) {
900 bformat = listf;
901 bnum = listn;
902 } else {
903 listf = bformat;
904 listn = bnum;
905 }
906 if(forward) {
907 addr1 = addr2;
908 addr2 += bpagesize;
909 if(addr2 > dol)
910 addr2 = dol;
911 } else {
912 addr1 = addr2-bpagesize;
913 if(addr1 <= zero)
914 addr1 = zero+1;
915 }
916 printcom();
917 }
918
919 void
callunix(void)920 callunix(void)
921 {
922 int c, pid;
923 Rune rune;
924 char buf[512];
925 char *p;
926
927 setnoaddr();
928 p = buf;
929 while((c=getchr()) != EOF && c != '\n')
930 if(p < &buf[sizeof(buf) - 6]) {
931 rune = c;
932 p += runetochar(p, &rune);
933 }
934 *p = 0;
935 pid = fork();
936 if(pid == 0) {
937 execlp("rc", "rc", "-c", buf, (char*)0);
938 sysfatal("exec failed: %r");
939 exits("execl failed");
940 }
941 waiting = 1;
942 while(waitpid() != pid)
943 ;
944 waiting = 0;
945 if(vflag)
946 putst("!");
947 }
948
949 void
quit(void)950 quit(void)
951 {
952 if(vflag && fchange && dol!=zero) {
953 fchange = 0;
954 error(Q);
955 }
956 remove(tfname);
957 exits(0);
958 }
959
960 void
onquit(int sig)961 onquit(int sig)
962 {
963 USED(sig);
964 quit();
965 }
966
967 void
rdelete(int * ad1,int * ad2)968 rdelete(int *ad1, int *ad2)
969 {
970 int *a1, *a2, *a3;
971
972 a1 = ad1;
973 a2 = ad2+1;
974 a3 = dol;
975 dol -= a2 - a1;
976 do {
977 *a1++ = *a2++;
978 } while(a2 <= a3);
979 a1 = ad1;
980 if(a1 > dol)
981 a1 = dol;
982 dot = a1;
983 fchange = 1;
984 }
985
986 void
gdelete(void)987 gdelete(void)
988 {
989 int *a1, *a2, *a3;
990
991 a3 = dol;
992 for(a1=zero; (*a1&01)==0; a1++)
993 if(a1>=a3)
994 return;
995 for(a2=a1+1; a2<=a3;) {
996 if(*a2 & 01) {
997 a2++;
998 dot = a1;
999 } else
1000 *a1++ = *a2++;
1001 }
1002 dol = a1-1;
1003 if(dot > dol)
1004 dot = dol;
1005 fchange = 1;
1006 }
1007
1008 Rune*
getline(int tl)1009 getline(int tl)
1010 {
1011 Rune *lp, *bp;
1012 int nl;
1013
1014 lp = linebuf;
1015 bp = getblock(tl, OREAD);
1016 nl = nleft;
1017 tl &= ~((BLKSIZE/sizeof(Rune)) - 1);
1018 while(*lp++ = *bp++) {
1019 nl -= sizeof(Rune);
1020 if(nl == 0) {
1021 bp = getblock(tl += BLKSIZE/sizeof(Rune), OREAD);
1022 nl = nleft;
1023 }
1024 }
1025 return linebuf;
1026 }
1027
1028 int
putline(void)1029 putline(void)
1030 {
1031 Rune *lp, *bp;
1032 int nl, tl;
1033
1034 fchange = 1;
1035 lp = linebuf;
1036 tl = tline;
1037 bp = getblock(tl, OWRITE);
1038 nl = nleft;
1039 tl &= ~((BLKSIZE/sizeof(Rune))-1);
1040 while(*bp = *lp++) {
1041 if(*bp++ == '\n') {
1042 bp[-1] = 0;
1043 linebp = lp;
1044 break;
1045 }
1046 nl -= sizeof(Rune);
1047 if(nl == 0) {
1048 tl += BLKSIZE/sizeof(Rune);
1049 bp = getblock(tl, OWRITE);
1050 nl = nleft;
1051 }
1052 }
1053 nl = tline;
1054 tline += ((lp-linebuf) + 03) & 077776;
1055 return nl;
1056 }
1057
1058 void
blkio(int b,uchar * buf,int isread)1059 blkio(int b, uchar *buf, int isread)
1060 {
1061 int n;
1062
1063 seek(tfile, b*BLKSIZE, 0);
1064 if(isread)
1065 n = read(tfile, buf, BLKSIZE);
1066 else
1067 n = write(tfile, buf, BLKSIZE);
1068 if(n != BLKSIZE)
1069 error(T);
1070 }
1071
1072 Rune*
getblock(int atl,int iof)1073 getblock(int atl, int iof)
1074 {
1075 int bno, off;
1076
1077 static uchar ibuff[BLKSIZE];
1078 static uchar obuff[BLKSIZE];
1079
1080 bno = atl / (BLKSIZE/sizeof(Rune));
1081 off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~03;
1082 if(bno >= NBLK) {
1083 lastc = '\n';
1084 error(T);
1085 }
1086 nleft = BLKSIZE - off;
1087 if(bno == iblock) {
1088 ichanged |= iof;
1089 return (Rune*)(ibuff+off);
1090 }
1091 if(bno == oblock)
1092 return (Rune*)(obuff+off);
1093 if(iof == OREAD) {
1094 if(ichanged)
1095 blkio(iblock, ibuff, 0);
1096 ichanged = 0;
1097 iblock = bno;
1098 blkio(bno, ibuff, 1);
1099 return (Rune*)(ibuff+off);
1100 }
1101 if(oblock >= 0)
1102 blkio(oblock, obuff, 0);
1103 oblock = bno;
1104 return (Rune*)(obuff+off);
1105 }
1106
1107 void
init(void)1108 init(void)
1109 {
1110 int *markp;
1111
1112 close(tfile);
1113 tline = 2;
1114 for(markp = names; markp < &names[26]; )
1115 *markp++ = 0;
1116 subnewa = 0;
1117 anymarks = 0;
1118 iblock = -1;
1119 oblock = -1;
1120 ichanged = 0;
1121 if((tfile = create(tfname, ORDWR, 0600)) < 0){
1122 error1(T);
1123 exits(0);
1124 }
1125 dot = dol = zero;
1126 }
1127
1128 void
global(int k)1129 global(int k)
1130 {
1131 Rune *gp, globuf[GBSIZE];
1132 int c, *a1;
1133
1134 if(globp)
1135 error(Q);
1136 setwide();
1137 squeeze(dol > zero);
1138 c = getchr();
1139 if(c == '\n')
1140 error(Q);
1141 compile(c);
1142 gp = globuf;
1143 while((c=getchr()) != '\n') {
1144 if(c == EOF)
1145 error(Q);
1146 if(c == '\\') {
1147 c = getchr();
1148 if(c != '\n')
1149 *gp++ = '\\';
1150 }
1151 *gp++ = c;
1152 if(gp >= &globuf[GBSIZE-2])
1153 error(Q);
1154 }
1155 if(gp == globuf)
1156 *gp++ = 'p';
1157 *gp++ = '\n';
1158 *gp = 0;
1159 for(a1=zero; a1<=dol; a1++) {
1160 *a1 &= ~01;
1161 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1162 *a1 |= 01;
1163 }
1164
1165 /*
1166 * Special case: g/.../d (avoid n^2 algorithm)
1167 */
1168 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1169 gdelete();
1170 return;
1171 }
1172 for(a1=zero; a1<=dol; a1++) {
1173 if(*a1 & 01) {
1174 *a1 &= ~01;
1175 dot = a1;
1176 globp = globuf;
1177 commands();
1178 a1 = zero;
1179 }
1180 }
1181 }
1182
1183 void
join(void)1184 join(void)
1185 {
1186 Rune *gp, *lp;
1187 int *a1;
1188
1189 nonzero();
1190 gp = genbuf;
1191 for(a1=addr1; a1<=addr2; a1++) {
1192 lp = getline(*a1);
1193 while(*gp = *lp++)
1194 if(gp++ >= &genbuf[LBSIZE-2])
1195 error(Q);
1196 }
1197 lp = linebuf;
1198 gp = genbuf;
1199 while(*lp++ = *gp++)
1200 ;
1201 *addr1 = putline();
1202 if(addr1 < addr2)
1203 rdelete(addr1+1, addr2);
1204 dot = addr1;
1205 }
1206
1207 void
substitute(int inglob)1208 substitute(int inglob)
1209 {
1210 int *mp, *a1, nl, gsubf, n;
1211
1212 n = getnum(); /* OK even if n==0 */
1213 gsubf = compsub();
1214 for(a1 = addr1; a1 <= addr2; a1++) {
1215 if(match(a1)){
1216 int *ozero;
1217 int m = n;
1218
1219 do {
1220 int span = loc2-loc1;
1221
1222 if(--m <= 0) {
1223 dosub();
1224 if(!gsubf)
1225 break;
1226 if(span == 0) { /* null RE match */
1227 if(*loc2 == 0)
1228 break;
1229 loc2++;
1230 }
1231 }
1232 } while(match(0));
1233 if(m <= 0) {
1234 inglob |= 01;
1235 subnewa = putline();
1236 *a1 &= ~01;
1237 if(anymarks) {
1238 for(mp=names; mp<&names[26]; mp++)
1239 if(*mp == *a1)
1240 *mp = subnewa;
1241 }
1242 subolda = *a1;
1243 *a1 = subnewa;
1244 ozero = zero;
1245 nl = append(getsub, a1);
1246 addr2 += nl;
1247 nl += zero-ozero;
1248 a1 += nl;
1249 }
1250 }
1251 }
1252 if(inglob == 0)
1253 error(Q);
1254 }
1255
1256 int
compsub(void)1257 compsub(void)
1258 {
1259 int seof, c;
1260 Rune *p;
1261
1262 seof = getchr();
1263 if(seof == '\n' || seof == ' ')
1264 error(Q);
1265 compile(seof);
1266 p = rhsbuf;
1267 for(;;) {
1268 c = getchr();
1269 if(c == '\\') {
1270 c = getchr();
1271 *p++ = ESCFLG;
1272 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
1273 error(Q);
1274 } else
1275 if(c == '\n' && (!globp || !globp[0])) {
1276 peekc = c;
1277 pflag++;
1278 break;
1279 } else
1280 if(c == seof)
1281 break;
1282 *p++ = c;
1283 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
1284 error(Q);
1285 }
1286 *p = 0;
1287 peekc = getchr();
1288 if(peekc == 'g') {
1289 peekc = 0;
1290 newline();
1291 return 1;
1292 }
1293 newline();
1294 return 0;
1295 }
1296
1297 int
getsub(void)1298 getsub(void)
1299 {
1300 Rune *p1, *p2;
1301
1302 p1 = linebuf;
1303 if((p2 = linebp) == 0)
1304 return EOF;
1305 while(*p1++ = *p2++)
1306 ;
1307 linebp = 0;
1308 return 0;
1309 }
1310
1311 void
dosub(void)1312 dosub(void)
1313 {
1314 Rune *lp, *sp, *rp;
1315 int c, n;
1316
1317 lp = linebuf;
1318 sp = genbuf;
1319 rp = rhsbuf;
1320 while(lp < loc1)
1321 *sp++ = *lp++;
1322 while(c = *rp++) {
1323 if(c == '&'){
1324 sp = place(sp, loc1, loc2);
1325 continue;
1326 }
1327 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1328 n = c-'0';
1329 if(subexp[n].s.rsp && subexp[n].e.rep) {
1330 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
1331 continue;
1332 }
1333 error(Q);
1334 }
1335 *sp++ = c;
1336 if(sp >= &genbuf[LBSIZE])
1337 error(Q);
1338 }
1339 lp = loc2;
1340 loc2 = sp - genbuf + linebuf;
1341 while(*sp++ = *lp++)
1342 if(sp >= &genbuf[LBSIZE])
1343 error(Q);
1344 lp = linebuf;
1345 sp = genbuf;
1346 while(*lp++ = *sp++)
1347 ;
1348 }
1349
1350 Rune*
place(Rune * sp,Rune * l1,Rune * l2)1351 place(Rune *sp, Rune *l1, Rune *l2)
1352 {
1353
1354 while(l1 < l2) {
1355 *sp++ = *l1++;
1356 if(sp >= &genbuf[LBSIZE])
1357 error(Q);
1358 }
1359 return sp;
1360 }
1361
1362 void
move(int cflag)1363 move(int cflag)
1364 {
1365 int *adt, *ad1, *ad2;
1366
1367 nonzero();
1368 if((adt = address())==0) /* address() guarantees addr is in range */
1369 error(Q);
1370 newline();
1371 if(cflag) {
1372 int *ozero, delta;
1373 ad1 = dol;
1374 ozero = zero;
1375 append(getcopy, ad1++);
1376 ad2 = dol;
1377 delta = zero - ozero;
1378 ad1 += delta;
1379 adt += delta;
1380 } else {
1381 ad2 = addr2;
1382 for(ad1 = addr1; ad1 <= ad2;)
1383 *ad1++ &= ~01;
1384 ad1 = addr1;
1385 }
1386 ad2++;
1387 if(adt<ad1) {
1388 dot = adt + (ad2-ad1);
1389 if((++adt)==ad1)
1390 return;
1391 reverse(adt, ad1);
1392 reverse(ad1, ad2);
1393 reverse(adt, ad2);
1394 } else
1395 if(adt >= ad2) {
1396 dot = adt++;
1397 reverse(ad1, ad2);
1398 reverse(ad2, adt);
1399 reverse(ad1, adt);
1400 } else
1401 error(Q);
1402 fchange = 1;
1403 }
1404
1405 void
reverse(int * a1,int * a2)1406 reverse(int *a1, int *a2)
1407 {
1408 int t;
1409
1410 for(;;) {
1411 t = *--a2;
1412 if(a2 <= a1)
1413 return;
1414 *a2 = *a1;
1415 *a1++ = t;
1416 }
1417 }
1418
1419 int
getcopy(void)1420 getcopy(void)
1421 {
1422 if(addr1 > addr2)
1423 return EOF;
1424 getline(*addr1++);
1425 return 0;
1426 }
1427
1428 void
compile(int eof)1429 compile(int eof)
1430 {
1431 Rune c;
1432 char *ep;
1433 char expbuf[ESIZE];
1434
1435 if((c = getchr()) == '\n') {
1436 peekc = c;
1437 c = eof;
1438 }
1439 if(c == eof) {
1440 if(!pattern)
1441 error(Q);
1442 return;
1443 }
1444 if(pattern) {
1445 free(pattern);
1446 pattern = 0;
1447 }
1448 ep = expbuf;
1449 do {
1450 if(c == '\\') {
1451 if(ep >= expbuf+sizeof(expbuf)) {
1452 error(Q);
1453 return;
1454 }
1455 ep += runetochar(ep, &c);
1456 if((c = getchr()) == '\n') {
1457 error(Q);
1458 return;
1459 }
1460 }
1461 if(ep >= expbuf+sizeof(expbuf)) {
1462 error(Q);
1463 return;
1464 }
1465 ep += runetochar(ep, &c);
1466 } while((c = getchr()) != eof && c != '\n');
1467 if(c == '\n')
1468 peekc = c;
1469 *ep = 0;
1470 pattern = regcomp(expbuf);
1471 }
1472
1473 int
match(int * addr)1474 match(int *addr)
1475 {
1476 if(!pattern)
1477 return 0;
1478 if(addr){
1479 if(addr == zero)
1480 return 0;
1481 subexp[0].s.rsp = getline(*addr);
1482 } else
1483 subexp[0].s.rsp = loc2;
1484 subexp[0].e.rep = 0;
1485 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1486 loc1 = subexp[0].s.rsp;
1487 loc2 = subexp[0].e.rep;
1488 return 1;
1489 }
1490 loc1 = loc2 = 0;
1491 return 0;
1492
1493 }
1494
1495 void
putd(void)1496 putd(void)
1497 {
1498 int r;
1499
1500 r = count%10;
1501 count /= 10;
1502 if(count)
1503 putd();
1504 putchr(r + '0');
1505 }
1506
1507 void
putst(char * sp)1508 putst(char *sp)
1509 {
1510 Rune r;
1511
1512 col = 0;
1513 for(;;) {
1514 sp += chartorune(&r, sp);
1515 if(r == 0)
1516 break;
1517 putchr(r);
1518 }
1519 putchr('\n');
1520 }
1521
1522 void
putshst(Rune * sp)1523 putshst(Rune *sp)
1524 {
1525 col = 0;
1526 while(*sp)
1527 putchr(*sp++);
1528 putchr('\n');
1529 }
1530
1531 void
putchr(int ac)1532 putchr(int ac)
1533 {
1534 char *lp;
1535 int c;
1536 Rune rune;
1537
1538 lp = linp;
1539 c = ac;
1540 if(listf) {
1541 if(c == '\n') {
1542 if(linp != line && linp[-1] == ' ') {
1543 *lp++ = '\\';
1544 *lp++ = 'n';
1545 }
1546 } else {
1547 if(col > (72-6-2)) {
1548 col = 8;
1549 *lp++ = '\\';
1550 *lp++ = '\n';
1551 *lp++ = '\t';
1552 }
1553 col++;
1554 if(c=='\b' || c=='\t' || c=='\\') {
1555 *lp++ = '\\';
1556 if(c == '\b')
1557 c = 'b';
1558 else
1559 if(c == '\t')
1560 c = 't';
1561 col++;
1562 } else
1563 if(c<' ' || c>='\177') {
1564 *lp++ = '\\';
1565 *lp++ = 'x';
1566 *lp++ = hex[c>>12];
1567 *lp++ = hex[c>>8&0xF];
1568 *lp++ = hex[c>>4&0xF];
1569 c = hex[c&0xF];
1570 col += 5;
1571 }
1572 }
1573 }
1574
1575 rune = c;
1576 lp += runetochar(lp, &rune);
1577
1578 if(c == '\n' || lp >= &line[sizeof(line)-5]) {
1579 linp = line;
1580 write(oflag? 2: 1, line, lp-line);
1581 return;
1582 }
1583 linp = lp;
1584 }
1585
1586 char*
_mktemp(char * as)1587 _mktemp(char *as)
1588 {
1589 char *s;
1590 unsigned pid;
1591 int i;
1592
1593 pid = getpid();
1594 s = as;
1595 while(*s++)
1596 ;
1597 s--;
1598 while(*--s == 'X') {
1599 *s = pid % 10 + '0';
1600 pid /= 10;
1601 }
1602 s++;
1603 i = 'a';
1604 while(access(as, 0) != -1) {
1605 if(i == 'z')
1606 return "/";
1607 *s = i++;
1608 }
1609 return as;
1610 }
1611
1612 void
regerror(char * s)1613 regerror(char *s)
1614 {
1615 USED(s);
1616 error(Q);
1617 }
1618