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