]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ed.c
9bootfat: rename open() to fileinit and make it static as its really a internal funct...
[plan9front.git] / sys / src / cmd / ed.c
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  = 0xFFFF,       /* 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/2];
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
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
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
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*
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
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
521 setwide(void)
522 {
523         if(!given) {
524                 addr1 = zero + (dol>zero);
525                 addr2 = dol;
526         }
527 }
528
529 void
530 setnoaddr(void)
531 {
532         if(given)
533                 error(Q);
534 }
535
536 void
537 nonzero(void)
538 {
539         squeeze(1);
540 }
541
542 void
543 squeeze(int i)
544 {
545         if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
546                 error(Q);
547 }
548
549 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
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
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
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
656 error(char *s)
657 {
658         error1(s);
659         longjmp(savej, 1);
660 }
661
662 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
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
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
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-2])
739                         error(Q);
740         }
741 }
742
743 int
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
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
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
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
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
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
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
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
935 onquit(int sig)
936 {
937         USED(sig);
938         quit();
939 }
940
941 void
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
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*
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/2) - 1);
992         while(*lp++ = *bp++) {
993                 nl -= sizeof(Rune);
994                 if(nl == 0) {
995                         bp = getblock(tl += BLKSIZE/2, OREAD);
996                         nl = nleft;
997                 }
998         }
999         return linebuf;
1000 }
1001
1002 int
1003 putline(void)
1004 {
1005         Rune *lp, *bp;
1006         int nl, tl;
1007
1008         fchange = 1;
1009         lp = linebuf;
1010         tl = tline;
1011         bp = getblock(tl, OWRITE);
1012         nl = nleft;
1013         tl &= ~((BLKSIZE/2)-1);
1014         while(*bp = *lp++) {
1015                 if(*bp++ == '\n') {
1016                         bp[-1] = 0;
1017                         linebp = lp;
1018                         break;
1019                 }
1020                 nl -= sizeof(Rune);
1021                 if(nl == 0) {
1022                         tl += BLKSIZE/2;
1023                         bp = getblock(tl, OWRITE);
1024                         nl = nleft;
1025                 }
1026         }
1027         nl = tline;
1028         tline += ((lp-linebuf) + 03) & 077776;
1029         return nl;
1030 }
1031
1032 void
1033 blkio(int b, uchar *buf, long (*iofcn)(int, void *, long))
1034 {
1035         seek(tfile, b*BLKSIZE, 0);
1036         if((*iofcn)(tfile, buf, BLKSIZE) != BLKSIZE) {
1037                 error(T);
1038         }
1039 }
1040
1041 Rune*
1042 getblock(int atl, int iof)
1043 {
1044         int bno, off;
1045         
1046         static uchar ibuff[BLKSIZE];
1047         static uchar obuff[BLKSIZE];
1048
1049         bno = atl / (BLKSIZE/2);
1050         off = (atl<<1) & (BLKSIZE-1) & ~03;
1051         if(bno >= NBLK) {
1052                 lastc = '\n';
1053                 error(T);
1054         }
1055         nleft = BLKSIZE - off;
1056         if(bno == iblock) {
1057                 ichanged |= iof;
1058                 return (Rune*)(ibuff+off);
1059         }
1060         if(bno == oblock)
1061                 return (Rune*)(obuff+off);
1062         if(iof == OREAD) {
1063                 if(ichanged)
1064                         blkio(iblock, ibuff, write);
1065                 ichanged = 0;
1066                 iblock = bno;
1067                 blkio(bno, ibuff, read);
1068                 return (Rune*)(ibuff+off);
1069         }
1070         if(oblock >= 0)
1071                 blkio(oblock, obuff, write);
1072         oblock = bno;
1073         return (Rune*)(obuff+off);
1074 }
1075
1076 void
1077 init(void)
1078 {
1079         int *markp;
1080
1081         close(tfile);
1082         tline = 2;
1083         for(markp = names; markp < &names[26]; )
1084                 *markp++ = 0;
1085         subnewa = 0;
1086         anymarks = 0;
1087         iblock = -1;
1088         oblock = -1;
1089         ichanged = 0;
1090         if((tfile = create(tfname, ORDWR, 0600)) < 0){
1091                 error1(T);
1092                 exits(0);
1093         }
1094         dot = dol = zero;
1095 }
1096
1097 void
1098 global(int k)
1099 {
1100         Rune *gp, globuf[GBSIZE];
1101         int c, *a1;
1102
1103         if(globp)
1104                 error(Q);
1105         setwide();
1106         squeeze(dol > zero);
1107         c = getchr();
1108         if(c == '\n')
1109                 error(Q);
1110         compile(c);
1111         gp = globuf;
1112         while((c=getchr()) != '\n') {
1113                 if(c == EOF)
1114                         error(Q);
1115                 if(c == '\\') {
1116                         c = getchr();
1117                         if(c != '\n')
1118                                 *gp++ = '\\';
1119                 }
1120                 *gp++ = c;
1121                 if(gp >= &globuf[GBSIZE-2])
1122                         error(Q);
1123         }
1124         if(gp == globuf)
1125                 *gp++ = 'p';
1126         *gp++ = '\n';
1127         *gp = 0;
1128         for(a1=zero; a1<=dol; a1++) {
1129                 *a1 &= ~01;
1130                 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1131                         *a1 |= 01;
1132         }
1133
1134         /*
1135          * Special case: g/.../d (avoid n^2 algorithm)
1136          */
1137         if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1138                 gdelete();
1139                 return;
1140         }
1141         for(a1=zero; a1<=dol; a1++) {
1142                 if(*a1 & 01) {
1143                         *a1 &= ~01;
1144                         dot = a1;
1145                         globp = globuf;
1146                         commands();
1147                         a1 = zero;
1148                 }
1149         }
1150 }
1151
1152 void
1153 join(void)
1154 {
1155         Rune *gp, *lp;
1156         int *a1;
1157
1158         nonzero();
1159         gp = genbuf;
1160         for(a1=addr1; a1<=addr2; a1++) {
1161                 lp = getline(*a1);
1162                 while(*gp = *lp++)
1163                         if(gp++ >= &genbuf[LBSIZE-2])
1164                                 error(Q);
1165         }
1166         lp = linebuf;
1167         gp = genbuf;
1168         while(*lp++ = *gp++)
1169                 ;
1170         *addr1 = putline();
1171         if(addr1 < addr2)
1172                 rdelete(addr1+1, addr2);
1173         dot = addr1;
1174 }
1175
1176 void
1177 substitute(int inglob)
1178 {
1179         int *mp, *a1, nl, gsubf, n;
1180
1181         n = getnum();   /* OK even if n==0 */
1182         gsubf = compsub();
1183         for(a1 = addr1; a1 <= addr2; a1++) {
1184                 if(match(a1)){
1185                         int *ozero;
1186                         int m = n;
1187
1188                         do {
1189                                 int span = loc2-loc1;
1190
1191                                 if(--m <= 0) {
1192                                         dosub();
1193                                         if(!gsubf)
1194                                                 break;
1195                                         if(span == 0) { /* null RE match */
1196                                                 if(*loc2 == 0)
1197                                                         break;
1198                                                 loc2++;
1199                                         }
1200                                 }
1201                         } while(match(0));
1202                         if(m <= 0) {
1203                                 inglob |= 01;
1204                                 subnewa = putline();
1205                                 *a1 &= ~01;
1206                                 if(anymarks) {
1207                                         for(mp=names; mp<&names[26]; mp++)
1208                                                 if(*mp == *a1)
1209                                                         *mp = subnewa;
1210                                 }
1211                                 subolda = *a1;
1212                                 *a1 = subnewa;
1213                                 ozero = zero;
1214                                 nl = append(getsub, a1);
1215                                 addr2 += nl;
1216                                 nl += zero-ozero;
1217                                 a1 += nl;
1218                         }
1219                 }
1220         }
1221         if(inglob == 0)
1222                 error(Q);
1223 }
1224
1225 int
1226 compsub(void)
1227 {
1228         int seof, c;
1229         Rune *p;
1230
1231         seof = getchr();
1232         if(seof == '\n' || seof == ' ')
1233                 error(Q);
1234         compile(seof);
1235         p = rhsbuf;
1236         for(;;) {
1237                 c = getchr();
1238                 if(c == '\\') {
1239                         c = getchr();
1240                         *p++ = ESCFLG;
1241                         if(p >= &rhsbuf[LBSIZE/2])
1242                                 error(Q);
1243                 } else
1244                 if(c == '\n' && (!globp || !globp[0])) {
1245                         peekc = c;
1246                         pflag++;
1247                         break;
1248                 } else
1249                 if(c == seof)
1250                         break;
1251                 *p++ = c;
1252                 if(p >= &rhsbuf[LBSIZE/2])
1253                         error(Q);
1254         }
1255         *p = 0;
1256         peekc = getchr();
1257         if(peekc == 'g') {
1258                 peekc = 0;
1259                 newline();
1260                 return 1;
1261         }
1262         newline();
1263         return 0;
1264 }
1265
1266 int
1267 getsub(void)
1268 {
1269         Rune *p1, *p2;
1270
1271         p1 = linebuf;
1272         if((p2 = linebp) == 0)
1273                 return EOF;
1274         while(*p1++ = *p2++)
1275                 ;
1276         linebp = 0;
1277         return 0;
1278 }
1279
1280 void
1281 dosub(void)
1282 {
1283         Rune *lp, *sp, *rp;
1284         int c, n;
1285
1286         lp = linebuf;
1287         sp = genbuf;
1288         rp = rhsbuf;
1289         while(lp < loc1)
1290                 *sp++ = *lp++;
1291         while(c = *rp++) {
1292                 if(c == '&'){
1293                         sp = place(sp, loc1, loc2);
1294                         continue;
1295                 }
1296                 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1297                         n = c-'0';
1298                         if(subexp[n].rsp && subexp[n].rep) {
1299                                 sp = place(sp, subexp[n].rsp, subexp[n].rep);
1300                                 continue;
1301                         }
1302                         error(Q);
1303                 }
1304                 *sp++ = c;
1305                 if(sp >= &genbuf[LBSIZE])
1306                         error(Q);
1307         }
1308         lp = loc2;
1309         loc2 = sp - genbuf + linebuf;
1310         while(*sp++ = *lp++)
1311                 if(sp >= &genbuf[LBSIZE])
1312                         error(Q);
1313         lp = linebuf;
1314         sp = genbuf;
1315         while(*lp++ = *sp++)
1316                 ;
1317 }
1318
1319 Rune*
1320 place(Rune *sp, Rune *l1, Rune *l2)
1321 {
1322
1323         while(l1 < l2) {
1324                 *sp++ = *l1++;
1325                 if(sp >= &genbuf[LBSIZE])
1326                         error(Q);
1327         }
1328         return sp;
1329 }
1330
1331 void
1332 move(int cflag)
1333 {
1334         int *adt, *ad1, *ad2;
1335
1336         nonzero();
1337         if((adt = address())==0)        /* address() guarantees addr is in range */
1338                 error(Q);
1339         newline();
1340         if(cflag) {
1341                 int *ozero, delta;
1342                 ad1 = dol;
1343                 ozero = zero;
1344                 append(getcopy, ad1++);
1345                 ad2 = dol;
1346                 delta = zero - ozero;
1347                 ad1 += delta;
1348                 adt += delta;
1349         } else {
1350                 ad2 = addr2;
1351                 for(ad1 = addr1; ad1 <= ad2;)
1352                         *ad1++ &= ~01;
1353                 ad1 = addr1;
1354         }
1355         ad2++;
1356         if(adt<ad1) {
1357                 dot = adt + (ad2-ad1);
1358                 if((++adt)==ad1)
1359                         return;
1360                 reverse(adt, ad1);
1361                 reverse(ad1, ad2);
1362                 reverse(adt, ad2);
1363         } else
1364         if(adt >= ad2) {
1365                 dot = adt++;
1366                 reverse(ad1, ad2);
1367                 reverse(ad2, adt);
1368                 reverse(ad1, adt);
1369         } else
1370                 error(Q);
1371         fchange = 1;
1372 }
1373
1374 void
1375 reverse(int *a1, int *a2)
1376 {
1377         int t;
1378
1379         for(;;) {
1380                 t = *--a2;
1381                 if(a2 <= a1)
1382                         return;
1383                 *a2 = *a1;
1384                 *a1++ = t;
1385         }
1386 }
1387
1388 int
1389 getcopy(void)
1390 {
1391         if(addr1 > addr2)
1392                 return EOF;
1393         getline(*addr1++);
1394         return 0;
1395 }
1396
1397 void
1398 compile(int eof)
1399 {
1400         Rune c;
1401         char *ep;
1402         char expbuf[ESIZE];
1403
1404         if((c = getchr()) == '\n') {
1405                 peekc = c;
1406                 c = eof;
1407         }
1408         if(c == eof) {
1409                 if(!pattern)
1410                         error(Q);
1411                 return;
1412         }
1413         if(pattern) {
1414                 free(pattern);
1415                 pattern = 0;
1416         }
1417         ep = expbuf;
1418         do {
1419                 if(c == '\\') {
1420                         if(ep >= expbuf+sizeof(expbuf)) {
1421                                 error(Q);
1422                                 return;
1423                         }
1424                         ep += runetochar(ep, &c);
1425                         if((c = getchr()) == '\n') {
1426                                 error(Q);
1427                                 return;
1428                         }
1429                 }
1430                 if(ep >= expbuf+sizeof(expbuf)) {
1431                         error(Q);
1432                         return;
1433                 }
1434                 ep += runetochar(ep, &c);
1435         } while((c = getchr()) != eof && c != '\n');
1436         if(c == '\n')
1437                 peekc = c;
1438         *ep = 0;
1439         pattern = regcomp(expbuf);
1440 }
1441
1442 int
1443 match(int *addr)
1444 {
1445         if(!pattern)
1446                 return 0;
1447         if(addr){
1448                 if(addr == zero)
1449                         return 0;
1450                 subexp[0].rsp = getline(*addr);
1451         } else
1452                 subexp[0].rsp = loc2;
1453         subexp[0].rep = 0;
1454         if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1455                 loc1 = subexp[0].rsp;
1456                 loc2 = subexp[0].rep;
1457                 return 1;
1458         }
1459         loc1 = loc2 = 0;
1460         return 0;
1461         
1462 }
1463
1464 void
1465 putd(void)
1466 {
1467         int r;
1468
1469         r = count%10;
1470         count /= 10;
1471         if(count)
1472                 putd();
1473         putchr(r + L'0');
1474 }
1475
1476 void
1477 putst(char *sp)
1478 {
1479         Rune r;
1480
1481         col = 0;
1482         for(;;) {
1483                 sp += chartorune(&r, sp);
1484                 if(r == 0)
1485                         break;
1486                 putchr(r);
1487         }
1488         putchr(L'\n');
1489 }
1490
1491 void
1492 putshst(Rune *sp)
1493 {
1494         col = 0;
1495         while(*sp)
1496                 putchr(*sp++);
1497         putchr(L'\n');
1498 }
1499
1500 void
1501 putchr(int ac)
1502 {
1503         char *lp;
1504         int c;
1505         Rune rune;
1506
1507         lp = linp;
1508         c = ac;
1509         if(listf) {
1510                 if(c == '\n') {
1511                         if(linp != line && linp[-1] == ' ') {
1512                                 *lp++ = '\\';
1513                                 *lp++ = 'n';
1514                         }
1515                 } else {
1516                         if(col > (72-6-2)) {
1517                                 col = 8;
1518                                 *lp++ = '\\';
1519                                 *lp++ = '\n';
1520                                 *lp++ = '\t';
1521                         }
1522                         col++;
1523                         if(c=='\b' || c=='\t' || c=='\\') {
1524                                 *lp++ = '\\';
1525                                 if(c == '\b')
1526                                         c = 'b';
1527                                 else
1528                                 if(c == '\t')
1529                                         c = 't';
1530                                 col++;
1531                         } else
1532                         if(c<' ' || c>='\177') {
1533                                 *lp++ = '\\';
1534                                 *lp++ = 'x';
1535                                 *lp++ =  hex[c>>12];
1536                                 *lp++ =  hex[c>>8&0xF];
1537                                 *lp++ =  hex[c>>4&0xF];
1538                                 c     =  hex[c&0xF];
1539                                 col += 5;
1540                         }
1541                 }
1542         }
1543
1544         rune = c;
1545         lp += runetochar(lp, &rune);
1546
1547         if(c == '\n' || lp >= &line[sizeof(line)-5]) {
1548                 linp = line;
1549                 write(oflag? 2: 1, line, lp-line);
1550                 return;
1551         }
1552         linp = lp;
1553 }
1554
1555 char*
1556 mktemp(char *as)
1557 {
1558         char *s;
1559         unsigned pid;
1560         int i;
1561
1562         pid = getpid();
1563         s = as;
1564         while(*s++)
1565                 ;
1566         s--;
1567         while(*--s == 'X') {
1568                 *s = pid % 10 + '0';
1569                 pid /= 10;
1570         }
1571         s++;
1572         i = 'a';
1573         while(access(as, 0) != -1) {
1574                 if(i == 'z')
1575                         return "/";
1576                 *s = i++;
1577         }
1578         return as;
1579 }
1580
1581 void
1582 regerror(char *s)
1583 {
1584         USED(s);
1585         error(Q);
1586 }