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