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