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