URI:
       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 }