00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <ctype.h>
00022 #include <sys/types.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 #include <stdio.h>
00027
00028
00029
00030
00031
00032
00033 #define MAXBUF 4000
00034 #define MAXAPPENDS 20
00035 #define MAXTAGS 9
00036
00037
00038 #define EQCMD 0x01
00039 #define ACMD 0x02
00040 #define BCMD 0x03
00041 #define CCMD 0x04
00042 #define DCMD 0x05
00043 #define CDCMD 0x06
00044 #define GCMD 0x07
00045 #define CGCMD 0x08
00046 #define HCMD 0x09
00047 #define CHCMD 0x0A
00048 #define ICMD 0x0B
00049 #define LCMD 0x0C
00050 #define NCMD 0x0D
00051 #define CNCMD 0x0E
00052 #define PCMD 0x0F
00053 #define CPCMD 0x10
00054 #define QCMD 0x11
00055 #define RCMD 0x12
00056 #define SCMD 0x13
00057 #define TCMD 0x14
00058 #define CTCMD 0x15
00059 #define WCMD 0x16
00060 #define CWCMD 0x17
00061 #define XCMD 0x18
00062 #define YCMD 0x19
00063
00064 struct cmd_t {
00065 char *addr1;
00066 char *addr2;
00067 union {
00068 char *lhs;
00069 struct cmd_t *link;
00070 } u;
00071 char command;
00072 char *rhs;
00073 FILE *fout;
00074 struct {
00075 char allbut;
00076 char global;
00077 char print;
00078 char inrange;
00079 } flags;
00080 };
00081 typedef struct cmd_t sedcmd;
00082
00083 #define BAD ((char *) -1)
00084
00085
00086
00087
00088 #define STAR 1
00089 #define CCHR 2
00090
00091 #define CDOT 4
00092 #define CCL 6
00093 #define CNL 8
00094 #define CDOL 10
00095 #define CBRA 12
00096 #define CKET 14
00097 #define CBACK 16
00098 #define CLNUM 18
00099 #define CEND 20
00100 #define CEOF 22
00101
00102
00103
00104 #ifndef CMASK
00105 #define CMASK 0xFF
00106
00107 #endif
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 #define MAXCMDS 500
00137 #define MAXLINES 256
00138
00139
00140 char linebuf[MAXBUF + 1];
00141 sedcmd cmds[MAXCMDS + 1];
00142 long linenum[MAXLINES];
00143
00144
00145 int nflag;
00146 int eargc;
00147 char **eargv;
00148 char bits[] = {1, 2, 4, 8, 16, 32, 64, 128};
00149
00150
00151
00152 #define POOLSIZE 20000
00153 #define WFILES 10
00154 #define RELIMIT 256
00155 #define MAXDEPTH 20
00156 #define MAXLABS 50
00157
00158 #define SKIPWS(pc) while ((*pc==' ') || (*pc=='\t')) pc++
00159 #define ABORT(msg) (fprintf(stderr, msg, linebuf), quit(2))
00160 #define IFEQ(x, v) if (*x == v) x++ ,
00161
00162
00163 static char AGMSG[] = "sed: garbled address %s\n";
00164 static char CGMSG[] = "sed: garbled command %s\n";
00165 static char TMTXT[] = "sed: too much text: %s\n";
00166 static char AD1NG[] = "sed: no addresses allowed for %s\n";
00167 static char AD2NG[] = "sed: only one address allowed for %s\n";
00168 static char TMCDS[] = "sed: too many commands, last was %s\n";
00169 static char COCFI[] = "sed: cannot open command-file %s\n";
00170 static char UFLAG[] = "sed: unknown flag %c\n";
00171 static char CCOFI[] = "sed: cannot create %s\n";
00172 static char ULABL[] = "sed: undefined label %s\n";
00173 static char TMLBR[] = "sed: too many {'s\n";
00174 static char FRENL[] = "sed: first RE must be non-null\n";
00175 static char NSCAX[] = "sed: no such command as %s\n";
00176 static char TMRBR[] = "sed: too many }'s\n";
00177 static char DLABL[] = "sed: duplicate label %s\n";
00178 static char TMLAB[] = "sed: too many labels: %s\n";
00179 static char TMWFI[] = "sed: too many w files\n";
00180 static char REITL[] = "sed: RE too long: %s\n";
00181 static char TMLNR[] = "sed: too many line numbers\n";
00182 static char TRAIL[] = "sed: command \"%s\" has trailing garbage\n";
00183
00184 typedef struct {
00185 char *name;
00186 sedcmd *last;
00187 sedcmd *address;
00188 }
00189
00190 label;
00191
00192
00193 static label labels[MAXLABS];
00194 static label *lab = labels + 1;
00195 static label *lablst = labels;
00196
00197
00198 static char pool[POOLSIZE];
00199 static char *fp = pool;
00200 static char *poolend = pool + POOLSIZE;
00201
00202
00203 static FILE *cmdf = NULL;
00204 static char *cp = linebuf;
00205 static sedcmd *cmdp = cmds;
00206 static char *lastre = NULL;
00207 static int bdepth = 0;
00208 static int bcount = 0;
00209
00210
00211 static int eflag;
00212 static int gflag;
00213
00214 _PROTOTYPE(int main, (int argc, char **argv));
00215 _PROTOTYPE(static void compile, (void));
00216 _PROTOTYPE(static int cmdcomp, (int cchar));
00217 _PROTOTYPE(static char *rhscomp, (char *rhsp, int delim));
00218 _PROTOTYPE(static char *recomp, (char *expbuf, int redelim));
00219 _PROTOTYPE(static int cmdline, (char *cbuf));
00220 _PROTOTYPE(static char *address, (char *expbuf));
00221 _PROTOTYPE(static char *gettext, (char *txp));
00222 _PROTOTYPE(static label *search, (label *ptr));
00223 _PROTOTYPE(static void resolve, (void));
00224 _PROTOTYPE(static char *ycomp, (char *ep, int delim));
00225 _PROTOTYPE(void quit, (int n));
00226 _PROTOTYPE(void execute, (void));
00227 _PROTOTYPE(static int selected, (sedcmd *ipc));
00228 _PROTOTYPE(static int match, (char *expbuf, int gf));
00229 _PROTOTYPE(static int advance, (char *lp, char *ep));
00230 _PROTOTYPE(static int substitute, (sedcmd *ipc));
00231 _PROTOTYPE(static void dosub, (char *rhsbuf));
00232 _PROTOTYPE(static char *place, (char *asp, char *al1, char *al2));
00233 _PROTOTYPE(static void listto, (char *p1, FILE *fp));
00234 _PROTOTYPE(static void truncated, (int h));
00235 _PROTOTYPE(static void command, (sedcmd *ipc));
00236 _PROTOTYPE(static void openfile, (char *file));
00237 _PROTOTYPE(static void get, (void));
00238 _PROTOTYPE(static void initget, (void));
00239 _PROTOTYPE(static char *getline, (char *buf));
00240 _PROTOTYPE(static int Memcmp, (char *a, char *b, int count));
00241 _PROTOTYPE(static void readout, (void));
00242
00243 int main(argc, argv)
00244
00245 int argc;
00246 char *argv[];
00247 {
00248 eargc = argc;
00249 eargv = argv;
00250 cmdp->addr1 = pool;
00251 if (eargc == 1) quit(0);
00252
00253 while ((--eargc > 0) && (**++eargv == '-')) switch (eargv[0][1]) {
00254 case 'e':
00255 eflag++;
00256 compile();
00257 eflag = 0;
00258 continue;
00259 case 'f':
00260 if (eargc-- <= 0)
00261 quit(2);
00262 if ((cmdf = fopen(*++eargv, "r")) == NULL) {
00263 fprintf(stderr, COCFI, *eargv);
00264 quit(2);
00265 }
00266 compile();
00267 fclose(cmdf);
00268 continue;
00269 case 'g':
00270 gflag++;
00271 continue;
00272 case 'n':
00273 nflag++;
00274 continue;
00275 default:
00276 fprintf(stdout, UFLAG, eargv[0][1]);
00277 continue;
00278 }
00279
00280
00281 if (cmdp == cmds) {
00282 eargv--;
00283 eargc++;
00284 eflag++;
00285 compile();
00286 eflag = 0;
00287 eargv++;
00288 eargc--;
00289 }
00290 if (bdepth)
00291 ABORT(TMLBR);
00292
00293 lablst->address = cmdp;
00294 resolve();
00295 execute();
00296 quit(0);
00297 return(0);
00298 }
00299
00300
00301 #define H 0x80
00302
00303 #define LOWCMD 56
00304
00305
00306 static char cmdmask[] =
00307 {
00308 0, 0, H, 0, 0, H + EQCMD, 0, 0,
00309 0, 0, 0, 0, H + CDCMD, 0, 0, CGCMD,
00310 CHCMD, 0, 0, 0, 0, 0, CNCMD, 0,
00311 CPCMD, 0, 0, 0, H + CTCMD, 0, 0, H + CWCMD,
00312 0, 0, 0, 0, 0, 0, 0, 0,
00313 0, H + ACMD, H + BCMD, H + CCMD, DCMD, 0, 0, GCMD,
00314 HCMD, H + ICMD, 0, 0, H + LCMD, 0, NCMD, 0,
00315 PCMD, H + QCMD, H + RCMD, H + SCMD, H + TCMD, 0, 0, H + WCMD,
00316 XCMD, H + YCMD, 0, H + BCMD, 0, H, 0, 0,
00317 };
00318
00319 static void compile()
00320
00321 {
00322 char ccode;
00323
00324
00325 for (;;) {
00326 if (*cp == '\0') {
00327 *linebuf = '\0';
00328 if (cmdline(cp = linebuf) < 0) break;
00329 }
00330 SKIPWS(cp);
00331 if (*cp == '\0')
00332 continue;
00333 if (*cp == '#') {
00334 while (*cp) ++cp;
00335 continue;
00336 }
00337 if (*cp == ';') {
00338 cp++;
00339 continue;
00340 }
00341
00342
00343 if (fp > poolend)
00344 ABORT(TMTXT);
00345 else if ((fp = address(cmdp->addr1 = fp)) == BAD)
00346 ABORT(AGMSG);
00347
00348 if (fp == cmdp->addr1) {
00349 if (lastre)
00350 cmdp->addr1 = lastre;
00351 else
00352 ABORT(FRENL);
00353 } else if (fp == NULL) {
00354 fp = cmdp->addr1;
00355 cmdp->addr1 = NULL;
00356 } else {
00357 lastre = cmdp->addr1;
00358 if (*cp == ',' || *cp == ';') {
00359 cp++;
00360 if (fp > poolend) ABORT(TMTXT);
00361 fp = address(cmdp->addr2 = fp);
00362 if (fp == BAD || fp == NULL) ABORT(AGMSG);
00363 if (fp == cmdp->addr2)
00364 cmdp->addr2 = lastre;
00365 else
00366 lastre = cmdp->addr2;
00367 } else
00368 cmdp->addr2 = NULL;
00369 }
00370 if (fp > poolend) ABORT(TMTXT);
00371
00372 SKIPWS(cp);
00373 IFEQ(cp, '!') cmdp->flags.allbut = 1;
00374
00375 SKIPWS(cp);
00376 if ((*cp < LOWCMD) || (*cp > '~')
00377 || ((ccode = cmdmask[*cp - LOWCMD]) == 0))
00378 ABORT(NSCAX);
00379
00380 cmdp->command = ccode & ~H;
00381 if ((ccode & H) == 0)
00382 cp++;
00383 else if (cmdcomp(*cp++))
00384 continue;
00385
00386 if (++cmdp >= cmds + MAXCMDS) ABORT(TMCDS);
00387
00388 SKIPWS(cp);
00389 if (*cp != '\0' && *cp != ';' && *cp != '#') ABORT(TRAIL);
00390 }
00391 }
00392
00393 static int cmdcomp(cchar)
00394
00395 register char cchar;
00396 {
00397 static sedcmd **cmpstk[MAXDEPTH];
00398 static char *fname[WFILES];
00399 static FILE *fout[WFILES];
00400 static int nwfiles = 1;
00401 int i;
00402 sedcmd *sp1, *sp2;
00403 label *lpt;
00404 char redelim;
00405
00406 fout[0] = stdout;
00407 switch (cchar) {
00408 case '{':
00409 cmdp->flags.allbut = !cmdp->flags.allbut;
00410 cmpstk[bdepth++] = &(cmdp->u.link);
00411 if (++cmdp >= cmds + MAXCMDS) ABORT(TMCDS);
00412 return(1);
00413
00414 case '}':
00415 if (cmdp->addr1) ABORT(AD1NG);
00416 if (--bdepth < 0) ABORT(TMRBR);
00417 *cmpstk[bdepth] = cmdp;
00418 return(1);
00419
00420 case '=':
00421 case 'q':
00422 if (cmdp->addr2) ABORT(AD2NG);
00423 break;
00424
00425 case ':':
00426 if (cmdp->addr1) ABORT(AD1NG);
00427 fp = gettext(lab->name = fp);
00428 if (lpt = search(lab)) {
00429 if (lpt->address) ABORT(DLABL);
00430 } else {
00431 lab->last = NULL;
00432 lpt = lab;
00433 if (++lab >= labels + MAXLABS) ABORT(TMLAB);
00434 }
00435 lpt->address = cmdp;
00436 return(1);
00437
00438 case 'b':
00439 case 't':
00440 case 'T':
00441 SKIPWS(cp);
00442 if (*cp == '\0') {
00443
00444 if (sp1 = lablst->last) {
00445 while (sp2 = sp1->u.link) sp1 = sp2;
00446 sp1->u.link = cmdp;
00447 } else
00448 lablst->last = cmdp;
00449 break;
00450 }
00451 fp = gettext(lab->name = fp);
00452 if (lpt = search(lab)) {
00453 if (lpt->address)
00454 cmdp->u.link = lpt->address;
00455 else {
00456 sp1 = lpt->last;
00457 while (sp2 = sp1->u.link) sp1 = sp2;
00458 sp1->u.link = cmdp;
00459 }
00460 } else {
00461 lab->last = cmdp;
00462 lab->address = NULL;
00463 if (++lab >= labels + MAXLABS)
00464 ABORT(TMLAB);
00465 }
00466 break;
00467
00468 case 'a':
00469 case 'i':
00470 case 'r':
00471 if (cmdp->addr2) ABORT(AD2NG);
00472 case 'c':
00473 if ((*cp == '\\') && (*++cp == '\n')) cp++;
00474 fp = gettext(cmdp->u.lhs = fp);
00475 break;
00476
00477 case 'D':
00478 cmdp->u.link = cmds;
00479 break;
00480
00481 case 's':
00482 redelim = *cp++;
00483 if ((fp = recomp(cmdp->u.lhs = fp, redelim)) == BAD) ABORT(CGMSG);
00484 if (fp == cmdp->u.lhs)
00485 cmdp->u.lhs = lastre;
00486 else
00487 lastre = cmdp->u.lhs;
00488 if ((cmdp->rhs = fp) > poolend) ABORT(TMTXT);
00489 if ((fp = rhscomp(cmdp->rhs, redelim)) == BAD) ABORT(CGMSG);
00490 if (gflag) cmdp->flags.global ++;
00491 while (*cp == 'g' || *cp == 'p' || *cp == 'P') {
00492 IFEQ(cp, 'g') cmdp->flags.global ++;
00493 IFEQ(cp, 'p') cmdp->flags.print = 1;
00494 IFEQ(cp, 'P') cmdp->flags.print = 2;
00495 }
00496
00497 case 'l':
00498 if (*cp == 'w')
00499 cp++;
00500 else
00501 break;
00502
00503 case 'w':
00504 case 'W':
00505 if (nwfiles >= WFILES) ABORT(TMWFI);
00506 fp = gettext(fname[nwfiles] = fp);
00507 for (i = nwfiles - 1; i >= 0; i--)
00508 if ((fname[i] != NULL) &&
00509 (strcmp(fname[nwfiles], fname[i]) == 0)) {
00510 cmdp->fout = fout[i];
00511 return(0);
00512 }
00513
00514
00515 if ((cmdp->fout = fopen(fname[nwfiles], "w")) == NULL) {
00516 fprintf(stderr, CCOFI, fname[nwfiles]);
00517 quit(2);
00518 }
00519 fout[nwfiles++] = cmdp->fout;
00520 break;
00521
00522 case 'y':
00523 fp = ycomp(cmdp->u.lhs = fp, *cp++);
00524 if (fp == BAD) ABORT(CGMSG);
00525 if (fp > poolend) ABORT(TMTXT);
00526 break;
00527 }
00528 return(0);
00529 }
00530
00531 static char *rhscomp(rhsp, delim)
00532
00533 register char *rhsp;
00534 register char delim;
00535 {
00536 register char *p = cp;
00537
00538 for (;;)
00539 if ((*rhsp = *p++) == '\\') {
00540 *rhsp = *p++;
00541
00542 if (*rhsp > bcount + '0' && *rhsp <= '9') return(BAD);
00543 *rhsp++ |= 0x80;
00544 continue;
00545 } else if (*rhsp == delim) {
00546 *rhsp++ = '\0';
00547 cp = p;
00548 return(rhsp);
00549 } else if (*rhsp++ == '\0')
00550 return(BAD);
00551 }
00552
00553 static char *recomp(expbuf, redelim)
00554
00555 char *expbuf;
00556 char redelim;
00557 {
00558 register char *ep = expbuf;
00559 register char *sp = cp;
00560 register int c;
00561 char negclass;
00562 char *lastep;
00563 char *svclass;
00564 char brnest[MAXTAGS];
00565 char *brnestp;
00566 int classct;
00567 int tags;
00568
00569 if (*cp == redelim)
00570 return(cp++, expbuf);
00571
00572 lastep = NULL;
00573 brnestp = brnest;
00574 tags = bcount = 0;
00575
00576 if (*ep++ = (*sp == '^'))
00577 sp++;
00578
00579 for (;;) {
00580 if (ep >= expbuf + RELIMIT)
00581 return(cp = sp, BAD);
00582 if ((c = *sp++) == redelim) {
00583 cp = sp;
00584 if (brnestp != brnest)
00585 return(BAD);
00586 *ep++ = CEOF;
00587 return(ep);
00588 }
00589 if (c != '*')
00590 lastep = ep;
00591
00592 switch (c) {
00593 case '\\':
00594 if ((c = *sp++) == '(') {
00595 if (bcount >= MAXTAGS) return(cp = sp, BAD);
00596 *brnestp++ = bcount;
00597 *ep++ = CBRA;
00598 *ep++ = bcount++;
00599 continue;
00600 } else if (c == ')') {
00601 if (brnestp <= brnest)
00602 return(cp = sp, BAD);
00603 *ep++ = CKET;
00604 *ep++ = *--brnestp;
00605 tags++;
00606 continue;
00607 } else if (c >= '1' && c <= '9') {
00608 if ((c -= '1') >= tags)
00609 return(BAD);
00610 *ep++ = CBACK;
00611 *ep++ = c;
00612 continue;
00613 } else if (c == '\n')
00614 return(cp = sp, BAD);
00615 else if (c == 'n')
00616 c = '\n';
00617 else if (c == 't')
00618 c = '\t';
00619 else if (c == 'r')
00620 c = '\r';
00621 goto defchar;
00622
00623 case '\0':
00624 continue;
00625
00626 case '\n':
00627 return(cp = sp, BAD);
00628
00629 case '.':
00630 *ep++ = CDOT;
00631 continue;
00632 case '*':
00633 if (lastep == NULL)
00634 goto defchar;
00635 if (*lastep == CKET)
00636 return(cp = sp, BAD);
00637 *lastep |= STAR;
00638 continue;
00639
00640 case '$':
00641 if (*sp != redelim)
00642 goto defchar;
00643 *ep++ = CDOL;
00644 continue;
00645
00646 case '[':
00647 if (ep + 17 >= expbuf + RELIMIT) ABORT(REITL);
00648 *ep++ = CCL;
00649 if (negclass = ((c = *sp++) == '^')) c = *sp++;
00650 svclass = sp;
00651 do {
00652 if (c == '\0') ABORT(CGMSG);
00653
00654
00655 if (c == '-' && sp > svclass && *sp != ']')
00656 for (c = sp[-2]; c < *sp; c++)
00657 ep[c >> 3] |= bits[c & 7];
00658
00659
00660 if (c == '\\')
00661 if ((c = *sp++) == 'n')
00662 c = '\n';
00663 else if (c == 't')
00664 c = '\t';
00665 else if (c == 'r')
00666 c = '\r';
00667
00668
00669 ep[c >> 3] |= bits[c & 7];
00670 } while
00671 ((c = *sp++) != ']');
00672
00673
00674 if (negclass) for (classct = 0; classct < 16; classct++)
00675 ep[classct] ^= 0xFF;
00676 ep[0] &= 0xFE;
00677 ep += 16;
00678 continue;
00679
00680 defchar:
00681 default:
00682 *ep++ = CCHR;
00683 *ep++ = c;
00684 }
00685 }
00686 }
00687
00688 static int cmdline(cbuf)
00689
00690 register char *cbuf;
00691 {
00692 register int inc;
00693
00694 *cbuf-- = 0;
00695
00696
00697 if (eflag) {
00698 register char *p;
00699 static char *savep;
00700
00701 if (eflag > 0) {
00702 eflag = -1;
00703 if (eargc-- <= 0) quit(2);
00704
00705
00706 p = *++eargv;
00707 while (*++cbuf = *p++)
00708 if (*cbuf == '\\') {
00709 if ((*++cbuf = *p++) == '\0')
00710 return(savep = NULL, -1);
00711 else
00712 continue;
00713 } else if (*cbuf == '\n') {
00714 *cbuf = '\0';
00715 return(savep = p, 1);
00716
00717 }
00718
00719
00720 return(savep = NULL, 1);
00721 }
00722 if ((p = savep) == NULL) return(-1);
00723
00724 while (*++cbuf = *p++)
00725 if (*cbuf == '\\') {
00726 if ((*++cbuf = *p++) == '0')
00727 return(savep = NULL, -1);
00728 else
00729 continue;
00730 } else if (*cbuf == '\n') {
00731 *cbuf = '\0';
00732 return(savep = p, 1);
00733 }
00734 return(savep = NULL, 1);
00735 }
00736
00737
00738 while ((inc = getc(cmdf)) != EOF)
00739 if ((*++cbuf = inc) == '\\')
00740 *++cbuf = inc = getc(cmdf);
00741 else if (*cbuf == '\n')
00742 return(*cbuf = '\0', 1);
00743
00744 return(*++cbuf = '\0', -1);
00745 }
00746
00747 static char *address(expbuf)
00748
00749 register char *expbuf;
00750 {
00751 static int numl = 0;
00752 register char *rcp;
00753 long lno;
00754
00755 if (*cp == '$') {
00756 *expbuf++ = CEND;
00757 *expbuf++ = CEOF;
00758 cp++;
00759 return(expbuf);
00760 }
00761 if (*cp == '/' || *cp == '\\') {
00762 if (*cp == '\\') cp++;
00763 return(recomp(expbuf, *cp++));
00764 }
00765
00766 rcp = cp;
00767 lno = 0;
00768 while (*rcp >= '0' && *rcp <= '9')
00769 lno = lno * 10 + *rcp++ - '0';
00770
00771 if (rcp > cp) {
00772 *expbuf++ = CLNUM;
00773 *expbuf++ = numl;
00774 linenum[numl++] = lno;
00775 if (numl >= MAXLINES)
00776 ABORT(TMLNR);
00777 *expbuf++ = CEOF;
00778 cp = rcp;
00779 return(expbuf);
00780 }
00781 return(NULL);
00782 }
00783
00784 static char *gettext(txp)
00785
00786 register char *txp;
00787 {
00788 register char *p = cp;
00789
00790 SKIPWS(p);
00791 do {
00792 if ((*txp = *p++) == '\\')
00793 *txp = *p++;
00794 if (*txp == '\0')
00795 return(cp = --p, ++txp);
00796 else if (*txp == '\n')
00797 SKIPWS(p);
00798 } while
00799 (txp++);
00800 return(txp);
00801 }
00802
00803 static label *search(ptr)
00804
00805 register label *ptr;
00806 {
00807 register label *rp;
00808 for (rp = lablst; rp < ptr; rp++)
00809 if ((rp->name != NULL) && (strcmp(rp->name, ptr->name) == 0))
00810 return(rp);
00811 return(NULL);
00812 }
00813
00814 static void resolve()
00815 {
00816
00817 register label *lptr;
00818 register sedcmd *rptr, *trptr;
00819
00820
00821 for (lptr = lablst; lptr < lab; lptr++)
00822 if (lptr->address == NULL) {
00823 fprintf(stderr, ULABL, lptr->name);
00824 quit(2);
00825 } else if (lptr->last) {
00826 rptr = lptr->last;
00827 while (trptr = rptr->u.link) {
00828 rptr->u.link = lptr->address;
00829 rptr = trptr;
00830 }
00831 rptr->u.link = lptr->address;
00832 }
00833 }
00834
00835 static char *ycomp(ep, delim)
00836
00837 register char *ep;
00838 char delim;
00839 {
00840 register char *tp, *sp;
00841 register int c;
00842
00843
00844 for (sp = tp = cp; *tp != delim; tp++) {
00845 if (*tp == '\\') tp++;
00846 if ((*tp == '\n') || (*tp == '\0')) return (BAD);
00847 }
00848 tp++;
00849
00850
00851
00852 while ((c = *sp++ & 0x7F) != delim) {
00853 if (c == '\\' && *sp == 'n') {
00854 sp++;
00855 c = '\n';
00856 }
00857 if ((ep[c] = *tp++) == '\\' && *tp == 'n') {
00858 ep[c] = '\n';
00859 tp++;
00860 }
00861 if ((ep[c] == delim) || (ep[c] == '\0')) return(BAD);
00862 }
00863
00864 if (*tp != delim)
00865 return(BAD);
00866
00867 cp = ++tp;
00868
00869 for (c = 0; c < 128; c++)
00870 if (ep[c] == 0) ep[c] = c;
00871
00872 return(ep + 0x80);
00873 }
00874
00875 void quit(n)
00876 int n;
00877 {
00878
00879
00880
00881 exit(n);
00882 }
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907 extern char linebuf[];
00908 extern sedcmd cmds[];
00909 extern long linenum[];
00910
00911
00912 extern int nflag;
00913 extern int eargc;
00914 extern char **eargv;
00915 extern char bits[];
00916
00917
00918
00919 #define MAXHOLD MAXBUF
00920 #define GENSIZ MAXBUF
00921
00922 #define TRUE 1
00923 #define FALSE 0
00924
00925 static char LTLMSG[] = "sed: line too long\n";
00926
00927 static char *spend;
00928 static long lnum = 0L;
00929
00930
00931 static sedcmd *appends[MAXAPPENDS];
00932 static sedcmd **aptr = appends;
00933
00934
00935 static char genbuf[GENSIZ];
00936 static char *loc1;
00937 static char *loc2;
00938 static char *locs;
00939
00940
00941 static int lastline;
00942 static int jump;
00943 static int delete;
00944
00945
00946 static char *bracend[MAXTAGS];
00947 static char *brastart[MAXTAGS];
00948
00949 static int anysub;
00950
00951
00952 void execute()
00953
00954 {
00955 register char *p1;
00956 register sedcmd *ipc;
00957 char *execp;
00958
00959
00960 initget();
00961
00962
00963 for (;;) {
00964
00965
00966 if ((execp = getline(linebuf)) == BAD) return;
00967 spend = execp;
00968 anysub = FALSE;
00969
00970
00971 for (ipc = cmds; ipc->command;) {
00972 if (!selected(ipc)) {
00973 ipc++;
00974 continue;
00975 }
00976 command(ipc);
00977
00978 if (delete)
00979 break;
00980
00981 if (jump) {
00982 jump = FALSE;
00983 if ((ipc = ipc->u.link) == 0) {
00984 ipc = cmds;
00985 break;
00986 }
00987 } else
00988 ipc++;
00989 }
00990
00991
00992
00993
00994 if (!nflag && !delete) {
00995 for (p1 = linebuf; p1 < spend; p1++) putc(*p1, stdout);
00996 putc('\n', stdout);
00997 }
00998
00999
01000 if (aptr > appends) readout();
01001
01002 delete = FALSE;
01003 }
01004 }
01005
01006 static int selected(ipc)
01007
01008 sedcmd *ipc;
01009 {
01010 register char *p1 = ipc->addr1;
01011 register char *p2 = ipc->addr2;
01012 int c;
01013 int sel = TRUE;
01014
01015 if (!p1)
01016 ;
01017 else if (ipc->flags.inrange) {
01018 if (*p2 == CEND);
01019 else if (*p2 == CLNUM) {
01020 c = p2[1] & CMASK;
01021 if (lnum >= linenum[c]) {
01022 ipc->flags.inrange = FALSE;
01023 if (lnum > linenum[c]) sel = FALSE;
01024 }
01025 } else if (match(p2, 0))
01026 ipc->flags.inrange = FALSE;
01027 } else if (*p1 == CEND) {
01028 if (!lastline) sel = FALSE;
01029 } else if (*p1 == CLNUM) {
01030 c = p1[1] & CMASK;
01031 if (lnum != linenum[c])
01032 sel = FALSE;
01033 else if (p2)
01034 ipc->flags.inrange = TRUE;
01035 } else if (match(p1, 0)) {
01036 if (p2) ipc->flags.inrange = TRUE;
01037 } else
01038 sel = FALSE;
01039
01040 return ipc->flags.allbut ? !sel : sel;
01041 }
01042
01043 static int match(expbuf, gf)
01044
01045 char *expbuf;
01046 int gf;
01047 {
01048 register char *p1, *p2, c;
01049
01050 if (gf) {
01051 if (*expbuf) return(FALSE);
01052 p1 = linebuf;
01053 p2 = genbuf;
01054 while (*p1++ = *p2++);
01055 locs = p1 = loc2;
01056 } else {
01057 p1 = linebuf;
01058 locs = FALSE;
01059 }
01060
01061 p2 = expbuf;
01062 if (*p2++) {
01063 loc1 = p1;
01064 if (*p2 == CCHR && p2[1] != *p1)
01065 return(FALSE);
01066 return(advance(p1, p2));
01067 }
01068
01069
01070 if (*p2 == CCHR) {
01071 c = p2[1];
01072 do {
01073 if (*p1 != c) continue;
01074 if (advance(p1, p2))
01075 return(loc1 = p1, 1);
01076 } while
01077 (*p1++);
01078 return(FALSE);
01079 }
01080
01081
01082 do {
01083 if (advance(p1, p2)) return(loc1 = p1, 1);
01084 } while
01085 (*p1++);
01086
01087
01088 return(FALSE);
01089 }
01090
01091 static int advance(lp, ep)
01092
01093 register char *lp;
01094 register char *ep;
01095 {
01096 register char *curlp;
01097 char c;
01098 char *bbeg;
01099 int ct;
01100
01101 for (;;) switch (*ep++) {
01102 case CCHR:
01103 if (*ep++ == *lp++)
01104 continue;
01105 return(FALSE);
01106
01107 case CDOT:
01108 if (*lp++)
01109 continue;
01110 return(FALSE);
01111
01112 case CNL:
01113 case CDOL:
01114 if (*lp == 0)
01115 continue;
01116 return(FALSE);
01117
01118 case CEOF:
01119 loc2 = lp;
01120 return(TRUE);
01121
01122 case CCL:
01123 c = *lp++ & 0177;
01124 if (ep[c >> 3] & bits[c & 07]) {
01125 ep += 16;
01126 continue;
01127 }
01128 return(FALSE);
01129
01130 case CBRA:
01131 brastart[*ep++] = lp;
01132 continue;
01133
01134 case CKET:
01135 bracend[*ep++] = lp;
01136 continue;
01137
01138 case CBACK:
01139 bbeg = brastart[*ep];
01140 ct = bracend[*ep++] - bbeg;
01141
01142 if (Memcmp(bbeg, lp, ct)) {
01143 lp += ct;
01144 continue;
01145 }
01146 return(FALSE);
01147
01148 case CBACK | STAR:
01149 bbeg = brastart[*ep];
01150 ct = bracend[*ep++] - bbeg;
01151 curlp = lp;
01152 while (Memcmp(bbeg, lp, ct)) lp += ct;
01153
01154 while (lp >= curlp) {
01155 if (advance(lp, ep)) return(TRUE);
01156 lp -= ct;
01157 }
01158 return(FALSE);
01159
01160
01161 case CDOT | STAR:
01162 curlp = lp;
01163 while (*lp++);
01164 goto star;
01165
01166 case CCHR | STAR:
01167 curlp = lp;
01168 while (*lp++ == *ep);
01169 ep++;
01170 goto star;
01171
01172 case CCL | STAR:
01173 curlp = lp;
01174 do {
01175 c = *lp++ & 0x7F;
01176 } while
01177 (ep[c >> 3] & bits[c & 07]);
01178 ep += 16;
01179 goto star;
01180
01181 star:
01182 if (--lp == curlp)
01183 continue;
01184
01185 if (*ep == CCHR) {
01186 c = ep[1];
01187 do {
01188 if (*lp != c) continue;
01189 if (advance(lp, ep)) return (TRUE);
01190 } while
01191 (lp-- > curlp);
01192 return(FALSE);
01193 }
01194 if (*ep == CBACK) {
01195 c = *(brastart[ep[1]]);
01196 do {
01197 if (*lp != c) continue;
01198 if (advance(lp, ep)) return (TRUE);
01199 } while
01200 (lp-- > curlp);
01201 return(FALSE);
01202 }
01203 do {
01204 if (lp == locs) break;
01205 if (advance(lp, ep)) return (TRUE);
01206 } while
01207 (lp-- > curlp);
01208 return(FALSE);
01209
01210 default:
01211 fprintf(stderr, "sed: RE error, %o\n", *--ep);
01212 quit(2);
01213 }
01214 }
01215
01216 static int substitute(ipc)
01217
01218 sedcmd *ipc;
01219 {
01220 int nullmatch;
01221
01222 if (match(ipc->u.lhs, 0)) {
01223 nullmatch = (loc1 == loc2);
01224 dosub(ipc->rhs);
01225 } else
01226 return(FALSE);
01227
01228 if (ipc->flags.global)
01229 while (*loc2) {
01230 if (nullmatch) loc2++;
01231 if (match(ipc->u.lhs, 1)) {
01232 nullmatch = (loc1 == loc2);
01233 dosub(ipc->rhs);
01234 } else
01235 break;
01236 }
01237 return(TRUE);
01238 }
01239
01240 static void dosub(rhsbuf)
01241
01242 char *rhsbuf;
01243 {
01244 register char *lp, *sp, *rp;
01245 int c;
01246
01247
01248 lp = linebuf;
01249 sp = genbuf;
01250 while (lp < loc1) *sp++ = *lp++;
01251
01252 for (rp = rhsbuf; c = *rp++;) {
01253 if (c == '&') {
01254 sp = place(sp, loc1, loc2);
01255 continue;
01256 } else if (c & 0200 && (c &= 0177) >= '1' && c < MAXTAGS + '1') {
01257 sp = place(sp, brastart[c - '1'], bracend[c - '1']);
01258 continue;
01259 }
01260 *sp++ = c & 0177;
01261 if (sp >= genbuf + MAXBUF) fprintf(stderr, LTLMSG);
01262 }
01263 lp = loc2;
01264 loc2 = sp - genbuf + linebuf;
01265 while (*sp++ = *lp++)
01266 if (sp >= genbuf + MAXBUF) fprintf(stderr, LTLMSG);
01267 lp = linebuf;
01268 sp = genbuf;
01269 while (*lp++ = *sp++);
01270 spend = lp - 1;
01271 }
01272
01273 static char *place(asp, al1, al2)
01274
01275 register char *asp, *al1, *al2;
01276 {
01277 while (al1 < al2) {
01278 *asp++ = *al1++;
01279 if (asp >= genbuf + MAXBUF) fprintf(stderr, LTLMSG);
01280 }
01281 return(asp);
01282 }
01283
01284 static void listto(p1, fp)
01285
01286 register char *p1;
01287 FILE *fp;
01288 {
01289 p1--;
01290 while (*p1++)
01291 if (isprint(*p1))
01292 putc(*p1, fp);
01293 else {
01294 putc('\\', fp);
01295 switch (*p1) {
01296 case '\b':
01297 putc('b', fp);
01298 break;
01299 case '\t':
01300 putc('t', fp);
01301 break;
01302 case '\n':
01303 putc('n', fp);
01304 break;
01305 case '\r':
01306 putc('r', fp);
01307 break;
01308 case '\33':
01309 putc('e', fp);
01310 break;
01311 default:
01312 fprintf(fp, "%02x", *p1 & 0xFF);
01313 }
01314 }
01315 putc('\n', fp);
01316 }
01317
01318 static void truncated(h)
01319 int h;
01320 {
01321 static long last = 0L;
01322
01323 if (lnum == last) return;
01324 last = lnum;
01325
01326 fprintf(stderr, "sed: ");
01327 fprintf(stderr, h ? "hold space" : "line %ld", lnum);
01328 fprintf(stderr, " truncated to %d characters\n", MAXBUF);
01329 }
01330
01331 static void command(ipc)
01332
01333 sedcmd *ipc;
01334 {
01335 static char holdsp[MAXHOLD + 1];
01336 static char *hspend = holdsp;
01337 register char *p1, *p2;
01338 char *execp;
01339 int didsub;
01340
01341 switch (ipc->command) {
01342 case ACMD:
01343 *aptr++ = ipc;
01344 if (aptr >= appends + MAXAPPENDS) fprintf(stderr,
01345 "sed: too many appends after line %ld\n",
01346 lnum);
01347 *aptr = 0;
01348 break;
01349
01350 case CCMD:
01351 delete = TRUE;
01352 if (!ipc->flags.inrange || lastline) printf("%s\n", ipc->u.lhs);
01353 break;
01354
01355 case DCMD:
01356 delete++;
01357 break;
01358
01359 case CDCMD:
01360 p1 = p2 = linebuf;
01361 while (*p1 != '\n')
01362 if (delete = (*p1++ == 0)) return;
01363 p1++;
01364 while (*p2++ = *p1++) continue;
01365 spend = p2 - 1;
01366 jump++;
01367 break;
01368
01369 case EQCMD:
01370 fprintf(stdout, "%ld\n", lnum);
01371 break;
01372
01373 case GCMD:
01374 p1 = linebuf;
01375 p2 = holdsp;
01376 while (*p1++ = *p2++);
01377 spend = p1 - 1;
01378 break;
01379
01380 case CGCMD:
01381 *spend++ = '\n';
01382 p1 = spend;
01383 p2 = holdsp;
01384 do
01385 if (p1 > linebuf + MAXBUF) {
01386 truncated(0);
01387 p1[-1] = 0;
01388 break;
01389 }
01390 while (*p1++ = *p2++);
01391
01392 spend = p1 - 1;
01393 break;
01394
01395 case HCMD:
01396 p1 = holdsp;
01397 p2 = linebuf;
01398 while (*p1++ = *p2++);
01399 hspend = p1 - 1;
01400 break;
01401
01402 case CHCMD:
01403 *hspend++ = '\n';
01404 p1 = hspend;
01405 p2 = linebuf;
01406 do
01407 if (p1 > holdsp + MAXBUF) {
01408 truncated(1);
01409 p1[-1] = 0;
01410 break;
01411 }
01412 while (*p1++ = *p2++);
01413
01414 hspend = p1 - 1;
01415 break;
01416
01417 case ICMD:
01418 printf("%s\n", ipc->u.lhs);
01419 break;
01420
01421 case BCMD:
01422 jump = TRUE;
01423 break;
01424
01425 case LCMD:
01426 listto(linebuf, (ipc->fout != NULL) ? ipc->fout : stdout);
01427 break;
01428
01429 case NCMD:
01430 if (!nflag) puts(linebuf);
01431 if (aptr > appends) readout();
01432 if ((execp = getline(linebuf)) == BAD) {
01433 delete = TRUE;
01434 break;
01435 }
01436 spend = execp;
01437 anysub = FALSE;
01438 break;
01439
01440 case CNCMD:
01441 if (aptr > appends) readout();
01442 *spend++ = '\n';
01443 if ((execp = getline(spend)) == BAD) {
01444 *--spend = 0;
01445 break;
01446 }
01447 spend = execp;
01448 anysub = FALSE;
01449 break;
01450
01451 case PCMD:
01452 puts(linebuf);
01453 break;
01454
01455 case CPCMD:
01456 cpcom:
01457 for (p1 = linebuf; *p1 != '\n' && *p1 != '\0';) putc(*p1++, stdout);
01458 putc('\n', stdout);
01459 break;
01460
01461 case QCMD:
01462 if (!nflag) puts(linebuf);
01463 if (aptr > appends)
01464 readout();
01465 quit(0);
01466
01467 case RCMD:
01468 *aptr++ = ipc;
01469 if (aptr >= appends + MAXAPPENDS) fprintf(stderr,
01470 "sed: too many reads after line %ld\n",
01471 lnum);
01472 *aptr = 0;
01473 break;
01474
01475 case SCMD:
01476 didsub = substitute(ipc);
01477 if (didsub) anysub = TRUE;
01478 if (ipc->flags.print && didsub)
01479 if (ipc->flags.print == TRUE)
01480 puts(linebuf);
01481 else
01482 goto cpcom;
01483 if (didsub && ipc->fout) fprintf(ipc->fout, "%s\n", linebuf);
01484 break;
01485
01486 case TCMD:
01487 case CTCMD:
01488 if (anysub == (ipc->command == CTCMD))
01489 break;
01490 anysub = FALSE;
01491 jump = TRUE;
01492 break;
01493
01494 case CWCMD:
01495 for (p1 = linebuf; *p1 != '\n' && *p1 != '\0';)
01496 putc(*p1++, ipc->fout);
01497 putc('\n', ipc->fout);
01498 break;
01499
01500 case WCMD:
01501 fprintf(ipc->fout, "%s\n", linebuf);
01502 break;
01503
01504 case XCMD:
01505 p1 = linebuf;
01506 p2 = genbuf;
01507 while (*p2++ = *p1++) continue;
01508 p1 = holdsp;
01509 p2 = linebuf;
01510 while (*p2++ = *p1++) continue;
01511 spend = p2 - 1;
01512 p1 = genbuf;
01513 p2 = holdsp;
01514 while (*p2++ = *p1++) continue;
01515 hspend = p2 - 1;
01516 break;
01517
01518 case YCMD:
01519 p1 = linebuf;
01520 p2 = ipc->u.lhs;
01521 while (*p1 = p2[*p1]) p1++;
01522 break;
01523 }
01524 }
01525
01526 static void openfile(file)
01527 char *file;
01528
01529 {
01530 if (freopen(file, "r", stdin) == NULL) {
01531 fprintf(stderr, "sed: can't open %s\n", file);
01532 quit(1);
01533 }
01534 }
01535
01536 static int c;
01537
01538
01539 static void get()
01540
01541 {
01542 while ((c = getchar()) == EOF && --eargc >= 0) openfile(*eargv++);
01543 }
01544
01545 static void initget()
01546
01547 {
01548 if (--eargc >= 0) openfile(*eargv++);
01549 get();
01550 }
01551
01552 static char *getline(buf)
01553
01554 register char *buf;
01555 {
01556 if (c == EOF) return BAD;
01557
01558 lnum++;
01559
01560 do {
01561 if (c == '\n') {
01562 get();
01563 break;
01564 }
01565 if (buf <= linebuf + MAXBUF) *buf++ = c;
01566 get();
01567 } while (c != EOF);
01568
01569 if (c == EOF) lastline = TRUE;
01570
01571 if (buf > linebuf + MAXBUF) {
01572 truncated(0);
01573 --buf;
01574 }
01575 *buf = 0;
01576 return buf;
01577 }
01578
01579 static int Memcmp(a, b, count)
01580
01581 register char *a, *b;
01582 int count;
01583 {
01584 while (count--)
01585 if (*a++ != *b++)
01586 return(FALSE);
01587 return(TRUE);
01588 }
01589
01590 static void readout()
01591
01592 {
01593 register int t;
01594 FILE *fi;
01595
01596 aptr = appends - 1;
01597 while (*++aptr)
01598 if ((*aptr)->command == ACMD)
01599 printf("%s\n", (*aptr)->u.lhs);
01600 else {
01601 if ((fi = fopen((*aptr)->u.lhs, "r")) == NULL) {
01602 fprintf(stderr, "sed: can't open %s\n",
01603 (*aptr)->u.lhs);
01604 continue;
01605 }
01606 while ((t = getc(fi)) != EOF) putc((char) t, stdout);
01607 fclose(fi);
01608 }
01609 aptr = appends;
01610 *aptr = 0;
01611 }
01612
01613