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