From: Ben Gras Date: Tue, 22 Jun 2010 00:32:21 +0000 (+0000) Subject: no more minix sed. X-Git-Tag: v3.1.8~421 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/mult.png?a=commitdiff_plain;h=1b2189c205ad4d3ef1769df14028dba044f03aa1;p=minix.git no more minix sed. --- diff --git a/commands/Makefile b/commands/Makefile index 42f26b6b7..8054fa5db 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -24,7 +24,7 @@ SUBDIR= aal add_route adduser advent arp ash at autil awk \ profile progressbar proto pr_routes ps pwd pwdauth \ ramdisk rarpd rawspeed rcp rdate readall readclock \ readfs reboot remsync rev rget rlogin rlogind rmdir \ - rotate rsh rshd sed service setup shar size \ + rotate rsh rshd service setup shar size \ sleep slip sort spell split srccrc stat strings strip \ stty su sum svclog swapfs swifi sync synctree sysenv \ syslogd tail talk talkd tcpd tcpdp tcpstat tee telnet \ diff --git a/commands/sed/Makefile b/commands/sed/Makefile deleted file mode 100644 index 17c515e40..000000000 --- a/commands/sed/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -PROG= sed -BINDIR= /bin -MAN= - -.include diff --git a/commands/sed/sed.c b/commands/sed/sed.c deleted file mode 100644 index 4f11bfa64..000000000 --- a/commands/sed/sed.c +++ /dev/null @@ -1,1613 +0,0 @@ -/* sed - stream editor Author: Eric S. Raymond */ - -/* This used to be three different files with the following makefile: - * (Note the chmem). - -CFLAGS= -F -T. - -OBJS= sedcomp.s sedexec.s - -sed: $(OBJS) - cc -T. -o sed $(OBJS) - @chmem =13312 sed - -$(OBJS): sed.h - - * If you want longer lines: increase MAXBUF. - * If you want scripts with more text: increase POOLSIZE. - * If you want more commands per script: increase MAXCMDS. - */ - -#include -#include -#include -#include -#include -#include - -/*+++++++++++++++*/ - -/* Sed.h -- types and constants for the stream editor */ - -/* Data area sizes used by both modules */ -#define MAXBUF 4000 /* current line buffer size */ -#define MAXAPPENDS 20 /* maximum number of appends */ -#define MAXTAGS 9 /* tagged patterns are \1 to \9 */ - -/* Constants for compiled-command representation */ -#define EQCMD 0x01 /* = -- print current line number */ -#define ACMD 0x02 /* a -- append text after current line */ -#define BCMD 0x03 /* b -- branch to label */ -#define CCMD 0x04 /* c -- change current line */ -#define DCMD 0x05 /* d -- delete all of pattern space */ -#define CDCMD 0x06 /* D -- delete first line of pattern space */ -#define GCMD 0x07 /* g -- copy hold space to pattern space */ -#define CGCMD 0x08 /* G -- append hold space to pattern space */ -#define HCMD 0x09 /* h -- copy pattern space to hold space */ -#define CHCMD 0x0A /* H -- append pattern space to hold space */ -#define ICMD 0x0B /* i -- insert text before current line */ -#define LCMD 0x0C /* l -- print pattern space in escaped form */ -#define NCMD 0x0D /* n -- get next line into pattern space */ -#define CNCMD 0x0E /* N -- append next line to pattern space */ -#define PCMD 0x0F /* p -- print pattern space to output */ -#define CPCMD 0x10 /* P -- print first line of pattern space */ -#define QCMD 0x11 /* q -- exit the stream editor */ -#define RCMD 0x12 /* r -- read in a file after current line */ -#define SCMD 0x13 /* s -- regular-expression substitute */ -#define TCMD 0x14 /* t -- branch on any substitute successful */ -#define CTCMD 0x15 /* T -- branch on any substitute failed */ -#define WCMD 0x16 /* w -- write pattern space to file */ -#define CWCMD 0x17 /* W -- write first line of pattern space */ -#define XCMD 0x18 /* x -- exhange pattern and hold spaces */ -#define YCMD 0x19 /* y -- transliterate text */ - -struct cmd_t { /* compiled-command representation */ - char *addr1; /* first address for command */ - char *addr2; /* second address for command */ - union { - char *lhs; /* s command lhs */ - struct cmd_t *link; /* label link */ - } u; - char command; /* command code */ - char *rhs; /* s command replacement string */ - FILE *fout; /* associated output file descriptor */ - struct { - char allbut; /* was negation specified? */ - char global; /* was g postfix specified? */ - char print; /* was p postfix specified? */ - char inrange; /* in an address range? */ - } flags; -}; -typedef struct cmd_t sedcmd; /* use this name for declarations */ - -#define BAD ((char *) -1) /* guaranteed not a string ptr */ - - - -/* Address and regular expression compiled-form markers */ -#define STAR 1 /* marker for Kleene star */ -#define CCHR 2 /* non-newline character to be matched - * follows */ -#define CDOT 4 /* dot wild-card marker */ -#define CCL 6 /* character class follows */ -#define CNL 8 /* match line start */ -#define CDOL 10 /* match line end */ -#define CBRA 12 /* tagged pattern start marker */ -#define CKET 14 /* tagged pattern end marker */ -#define CBACK 16 /* backslash-digit pair marker */ -#define CLNUM 18 /* numeric-address index follows */ -#define CEND 20 /* symbol for end-of-source */ -#define CEOF 22 /* end-of-field mark */ - -/* Sed.h ends here */ - -#ifndef CMASK -#define CMASK 0xFF /* some char type should have been unsigned - * char? */ -#endif - -/*+++++++++++++++*/ - -/* Sed - stream editor Author: Eric S. Raymond */ - -/* - The stream editor compiles its command input (from files or -e options) - into an internal form using compile() then executes the compiled form using - execute(). Main() just initializes data structures, interprets command line - options, and calls compile() and execute() in appropriate sequence. - - The data structure produced by compile() is an array of compiled-command - structures (type sedcmd). These contain several pointers into pool[], the - regular-expression and text-data pool, plus a command code and g & p flags. - In the special case that the command is a label the struct will hold a ptr - into the labels array labels[] during most of the compile, until resolve() - resolves references at the end. - - The operation of execute() is described in its source module. -*/ - -/* #include */ -/* #include "sed.h" */ - -/* Imported functions */ - -/***** public stuff ******/ - -#define MAXCMDS 500 /* maximum number of compiled commands */ -#define MAXLINES 256 /* max # numeric addresses to compile */ - -/* Main data areas */ -char linebuf[MAXBUF + 1]; /* current-line buffer */ -sedcmd cmds[MAXCMDS + 1]; /* hold compiled commands */ -long linenum[MAXLINES]; /* numeric-addresses table */ - -/* Miscellaneous shared variables */ -int nflag; /* -n option flag */ -int eargc; /* scratch copy of argument count */ -char **eargv; /* scratch copy of argument list */ -char bits[] = {1, 2, 4, 8, 16, 32, 64, 128}; - -/***** module common stuff *****/ - -#define POOLSIZE 20000 /* size of string-pool space */ -#define WFILES 10 /* max # w output files that can be compiled */ -#define RELIMIT 256 /* max chars in compiled RE */ -#define MAXDEPTH 20 /* maximum {}-nesting level */ -#define MAXLABS 50 /* max # of labels that can be handled */ - -#define SKIPWS(pc) while ((*pc==' ') || (*pc=='\t')) pc++ -#define ABORT(msg) (fprintf(stderr, msg, linebuf), quit(2)) -#define IFEQ(x, v) if (*x == v) x++ , /* do expression */ - -/* Error messages */ -static char AGMSG[] = "sed: garbled address %s\n"; -static char CGMSG[] = "sed: garbled command %s\n"; -static char TMTXT[] = "sed: too much text: %s\n"; -static char AD1NG[] = "sed: no addresses allowed for %s\n"; -static char AD2NG[] = "sed: only one address allowed for %s\n"; -static char TMCDS[] = "sed: too many commands, last was %s\n"; -static char COCFI[] = "sed: cannot open command-file %s\n"; -static char UFLAG[] = "sed: unknown flag %c\n"; -static char CCOFI[] = "sed: cannot create %s\n"; -static char ULABL[] = "sed: undefined label %s\n"; -static char TMLBR[] = "sed: too many {'s\n"; -static char FRENL[] = "sed: first RE must be non-null\n"; -static char NSCAX[] = "sed: no such command as %s\n"; -static char TMRBR[] = "sed: too many }'s\n"; -static char DLABL[] = "sed: duplicate label %s\n"; -static char TMLAB[] = "sed: too many labels: %s\n"; -static char TMWFI[] = "sed: too many w files\n"; -static char REITL[] = "sed: RE too long: %s\n"; -static char TMLNR[] = "sed: too many line numbers\n"; -static char TRAIL[] = "sed: command \"%s\" has trailing garbage\n"; - -typedef struct { /* represent a command label */ - char *name; /* the label name */ - sedcmd *last; /* it's on the label search list */ - sedcmd *address; /* pointer to the cmd it labels */ -} - - label; - -/* Label handling */ -static label labels[MAXLABS]; /* here's the label table */ -static label *lab = labels + 1; /* pointer to current label */ -static label *lablst = labels; /* header for search list */ - -/* String pool for regular expressions, append text, etc. etc. */ -static char pool[POOLSIZE]; /* the pool */ -static char *fp = pool; /* current pool pointer */ -static char *poolend = pool + POOLSIZE; /* pointer past pool end */ - -/* Compilation state */ -static FILE *cmdf = NULL; /* current command source */ -static char *cp = linebuf; /* compile pointer */ -static sedcmd *cmdp = cmds; /* current compiled-cmd ptr */ -static char *lastre = NULL; /* old RE pointer */ -static int bdepth = 0; /* current {}-nesting level */ -static int bcount = 0; /* # tagged patterns in current RE */ - -/* Compilation flags */ -static int eflag; /* -e option flag */ -static int gflag; /* -g option flag */ - -_PROTOTYPE(int main, (int argc, char **argv)); -_PROTOTYPE(static void compile, (void)); -_PROTOTYPE(static int cmdcomp, (int cchar)); -_PROTOTYPE(static char *rhscomp, (char *rhsp, int delim)); -_PROTOTYPE(static char *recomp, (char *expbuf, int redelim)); -_PROTOTYPE(static int cmdline, (char *cbuf)); -_PROTOTYPE(static char *address, (char *expbuf)); -_PROTOTYPE(static char *gettext, (char *txp)); -_PROTOTYPE(static label *search, (label *ptr)); -_PROTOTYPE(static void resolve, (void)); -_PROTOTYPE(static char *ycomp, (char *ep, int delim)); -_PROTOTYPE(void quit, (int n)); -_PROTOTYPE(void execute, (void)); -_PROTOTYPE(static int selected, (sedcmd *ipc)); -_PROTOTYPE(static int match, (char *expbuf, int gf)); -_PROTOTYPE(static int advance, (char *lp, char *ep)); -_PROTOTYPE(static int substitute, (sedcmd *ipc)); -_PROTOTYPE(static void dosub, (char *rhsbuf)); -_PROTOTYPE(static char *place, (char *asp, char *al1, char *al2)); -_PROTOTYPE(static void listto, (char *p1, FILE *fp)); -_PROTOTYPE(static void truncated, (int h)); -_PROTOTYPE(static void command, (sedcmd *ipc)); -_PROTOTYPE(static void openfile, (char *file)); -_PROTOTYPE(static void get, (void)); -_PROTOTYPE(static void initget, (void)); -_PROTOTYPE(static char *getline, (char *buf)); -_PROTOTYPE(static int Memcmp, (char *a, char *b, int count)); -_PROTOTYPE(static void readout, (void)); - -int main(argc, argv) -/* Main sequence of the stream editor */ -int argc; -char *argv[]; -{ - eargc = argc; /* set local copy of argument count */ - eargv = argv; /* set local copy of argument list */ - cmdp->addr1 = pool; /* 1st addr expand will be at pool start */ - if (eargc == 1) quit(0); /* exit immediately if no arguments */ - /* Scan through the arguments, interpreting each one */ - while ((--eargc > 0) && (**++eargv == '-')) switch (eargv[0][1]) { - case 'e': - eflag++; - compile(); /* compile with e flag on */ - eflag = 0; - continue; /* get another argument */ - case 'f': - if (eargc-- <= 0) /* barf if no -f file */ - quit(2); - if ((cmdf = fopen(*++eargv, "r")) == NULL) { - fprintf(stderr, COCFI, *eargv); - quit(2); - } - compile(); /* file is O.K., compile it */ - fclose(cmdf); - continue; /* go back for another argument */ - case 'g': - gflag++; /* set global flag on all s cmds */ - continue; - case 'n': - nflag++; /* no print except on p flag or w */ - continue; - default: - fprintf(stdout, UFLAG, eargv[0][1]); - continue; - } - - - if (cmdp == cmds) { /* no commands have been compiled */ - eargv--; - eargc++; - eflag++; - compile(); - eflag = 0; - eargv++; - eargc--; - } - if (bdepth) /* we have unbalanced squigglies */ - ABORT(TMLBR); - - lablst->address = cmdp; /* set up header of label linked list */ - resolve(); /* resolve label table indirections */ - execute(); /* execute commands */ - quit(0); /* everything was O.K. if we got here */ - return(0); -} - - -#define H 0x80 /* 128 bit, on if there's really code for - * command */ -#define LOWCMD 56 /* = '8', lowest char indexed in cmdmask */ - -/* Indirect through this to get command internal code, if it exists */ -static char cmdmask[] = -{ - 0, 0, H, 0, 0, H + EQCMD, 0, 0, - 0, 0, 0, 0, H + CDCMD, 0, 0, CGCMD, - CHCMD, 0, 0, 0, 0, 0, CNCMD, 0, - CPCMD, 0, 0, 0, H + CTCMD, 0, 0, H + CWCMD, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, H + ACMD, H + BCMD, H + CCMD, DCMD, 0, 0, GCMD, - HCMD, H + ICMD, 0, 0, H + LCMD, 0, NCMD, 0, - PCMD, H + QCMD, H + RCMD, H + SCMD, H + TCMD, 0, 0, H + WCMD, - XCMD, H + YCMD, 0, H + BCMD, 0, H, 0, 0, -}; - -static void compile() -/* Precompile sed commands out of a file */ -{ - char ccode; - - - for (;;) { /* main compilation loop */ - if (*cp == '\0') { /* get a new command line */ - *linebuf = '\0'; /* K.H */ - if (cmdline(cp = linebuf) < 0) break; - } - SKIPWS(cp); - if (*cp == '\0') /* empty */ - continue; - if (*cp == '#') { /* comment */ - while (*cp) ++cp; - continue; - } - if (*cp == ';') { /* ; separates cmds */ - cp++; - continue; - } - - /* Compile first address */ - if (fp > poolend) - ABORT(TMTXT); - else if ((fp = address(cmdp->addr1 = fp)) == BAD) - ABORT(AGMSG); - - if (fp == cmdp->addr1) {/* if empty RE was found */ - if (lastre) /* if there was previous RE */ - cmdp->addr1 = lastre; /* use it */ - else - ABORT(FRENL); - } else if (fp == NULL) {/* if fp was NULL */ - fp = cmdp->addr1; /* use current pool location */ - cmdp->addr1 = NULL; - } else { - lastre = cmdp->addr1; - if (*cp == ',' || *cp == ';') { /* there's 2nd addr */ - cp++; - if (fp > poolend) ABORT(TMTXT); - fp = address(cmdp->addr2 = fp); - if (fp == BAD || fp == NULL) ABORT(AGMSG); - if (fp == cmdp->addr2) - cmdp->addr2 = lastre; - else - lastre = cmdp->addr2; - } else - cmdp->addr2 = NULL; /* no 2nd address */ - } - if (fp > poolend) ABORT(TMTXT); - - SKIPWS(cp); /* discard whitespace after address */ - IFEQ(cp, '!') cmdp->flags.allbut = 1; - - SKIPWS(cp); /* get cmd char, range-check it */ - if ((*cp < LOWCMD) || (*cp > '~') - || ((ccode = cmdmask[*cp - LOWCMD]) == 0)) - ABORT(NSCAX); - - cmdp->command = ccode & ~H; /* fill in command value */ - if ((ccode & H) == 0) /* if no compile-time code */ - cp++; /* discard command char */ - else if (cmdcomp(*cp++))/* execute it; if ret = 1 */ - continue; /* skip next line read */ - - if (++cmdp >= cmds + MAXCMDS) ABORT(TMCDS); - - SKIPWS(cp); /* look for trailing stuff */ - if (*cp != '\0' && *cp != ';' && *cp != '#') ABORT(TRAIL); - } -} - -static int cmdcomp(cchar) -/* Compile a single command */ -register char cchar; /* character name of command */ -{ - static sedcmd **cmpstk[MAXDEPTH]; /* current cmd stack for {} */ - static char *fname[WFILES]; /* w file name pointers */ - static FILE *fout[WFILES]; /* w file file ptrs */ - static int nwfiles = 1; /* count of open w files */ - int i; /* indexing dummy used in w */ - sedcmd *sp1, *sp2; /* temps for label searches */ - label *lpt; - char redelim; /* current RE delimiter */ - - fout[0] = stdout; - switch (cchar) { - case '{': /* start command group */ - cmdp->flags.allbut = !cmdp->flags.allbut; - cmpstk[bdepth++] = &(cmdp->u.link); - if (++cmdp >= cmds + MAXCMDS) ABORT(TMCDS); - return(1); - - case '}': /* end command group */ - if (cmdp->addr1) ABORT(AD1NG); /* no addresses allowed */ - if (--bdepth < 0) ABORT(TMRBR); /* too many right braces */ - *cmpstk[bdepth] = cmdp; /* set the jump address */ - return(1); - - case '=': /* print current source line number */ - case 'q': /* exit the stream editor */ - if (cmdp->addr2) ABORT(AD2NG); - break; - - case ':': /* label declaration */ - if (cmdp->addr1) ABORT(AD1NG); /* no addresses allowed */ - fp = gettext(lab->name = fp); /* get the label name */ - if (lpt = search(lab)) {/* does it have a double? */ - if (lpt->address) ABORT(DLABL); /* yes, abort */ - } else { /* check that it doesn't overflow label table */ - lab->last = NULL; - lpt = lab; - if (++lab >= labels + MAXLABS) ABORT(TMLAB); - } - lpt->address = cmdp; - return(1); - - case 'b': /* branch command */ - case 't': /* branch-on-succeed command */ - case 'T': /* branch-on-fail command */ - SKIPWS(cp); - if (*cp == '\0') { /* if branch is to start of cmds... */ - /* Add current command to end of label last */ - if (sp1 = lablst->last) { - while (sp2 = sp1->u.link) sp1 = sp2; - sp1->u.link = cmdp; - } else /* lablst->last == NULL */ - lablst->last = cmdp; - break; - } - fp = gettext(lab->name = fp); /* else get label into pool */ - if (lpt = search(lab)) {/* enter branch to it */ - if (lpt->address) - cmdp->u.link = lpt->address; - else { - sp1 = lpt->last; - while (sp2 = sp1->u.link) sp1 = sp2; - sp1->u.link = cmdp; - } - } else { /* matching named label not found */ - lab->last = cmdp; /* add the new label */ - lab->address = NULL; /* it's forward of here */ - if (++lab >= labels + MAXLABS) /* overflow if last */ - ABORT(TMLAB); - } - break; - - case 'a': /* append text */ - case 'i': /* insert text */ - case 'r': /* read file into stream */ - if (cmdp->addr2) ABORT(AD2NG); - case 'c': /* change text */ - if ((*cp == '\\') && (*++cp == '\n')) cp++; - fp = gettext(cmdp->u.lhs = fp); - break; - - case 'D': /* delete current line in hold space */ - cmdp->u.link = cmds; - break; - - case 's': /* substitute regular expression */ - redelim = *cp++; /* get delimiter from 1st ch */ - if ((fp = recomp(cmdp->u.lhs = fp, redelim)) == BAD) ABORT(CGMSG); - if (fp == cmdp->u.lhs) /* if compiled RE zero len */ - cmdp->u.lhs = lastre; /* use the previous one */ - else /* otherwise */ - lastre = cmdp->u.lhs; /* save the one just found */ - if ((cmdp->rhs = fp) > poolend) ABORT(TMTXT); - if ((fp = rhscomp(cmdp->rhs, redelim)) == BAD) ABORT(CGMSG); - if (gflag) cmdp->flags.global ++; - while (*cp == 'g' || *cp == 'p' || *cp == 'P') { - IFEQ(cp, 'g') cmdp->flags.global ++; - IFEQ(cp, 'p') cmdp->flags.print = 1; - IFEQ(cp, 'P') cmdp->flags.print = 2; - } - - case 'l': /* list pattern space */ - if (*cp == 'w') - cp++; /* and execute a w command! */ - else - break; /* s or l is done */ - - case 'w': /* write-pattern-space command */ - case 'W': /* write-first-line command */ - if (nwfiles >= WFILES) ABORT(TMWFI); - fp = gettext(fname[nwfiles] = fp); /* filename will be in pool */ - for (i = nwfiles - 1; i >= 0; i--) /* match it in table */ - if ((fname[i] != NULL) && - (strcmp(fname[nwfiles], fname[i]) == 0)) { - cmdp->fout = fout[i]; - return(0); - } - - /* If didn't find one, open new out file */ - if ((cmdp->fout = fopen(fname[nwfiles], "w")) == NULL) { - fprintf(stderr, CCOFI, fname[nwfiles]); - quit(2); - } - fout[nwfiles++] = cmdp->fout; - break; - - case 'y': /* transliterate text */ - fp = ycomp(cmdp->u.lhs = fp, *cp++); /* compile translit */ - if (fp == BAD) ABORT(CGMSG); /* fail on bad form */ - if (fp > poolend) ABORT(TMTXT); /* fail on overflow */ - break; - } - return(0); /* succeeded in interpreting one command */ -} - -static char *rhscomp(rhsp, delim) /* uses bcount */ - /* Generate replacement string for substitute command right hand side */ -register char *rhsp; /* place to compile expression to */ -register char delim; /* regular-expression end-mark to look for */ -{ - register char *p = cp; /* strictly for speed */ - - for (;;) - if ((*rhsp = *p++) == '\\') { /* copy; if it's a \, */ - *rhsp = *p++; /* copy escaped char */ - /* Check validity of pattern tag */ - if (*rhsp > bcount + '0' && *rhsp <= '9') return(BAD); - *rhsp++ |= 0x80;/* mark the good ones */ - continue; - } else if (*rhsp == delim) { /* found RE end, hooray... */ - *rhsp++ = '\0'; /* cap the expression string */ - cp = p; - return(rhsp); /* pt at 1 past the RE */ - } else if (*rhsp++ == '\0') /* last ch not RE end, help! */ - return(BAD); -} - -static char *recomp(expbuf, redelim) /* uses cp, bcount */ - /* Compile a regular expression to internal form */ -char *expbuf; /* place to compile it to */ -char redelim; /* RE end-marker to look for */ -{ - register char *ep = expbuf; /* current-compiled-char pointer */ - register char *sp = cp; /* source-character ptr */ - register int c; /* current-character pointer */ - char negclass; /* all-but flag */ - char *lastep; /* ptr to last expr compiled */ - char *svclass; /* start of current char class */ - char brnest[MAXTAGS]; /* bracket-nesting array */ - char *brnestp; /* ptr to current bracket-nest */ - int classct; /* class element count */ - int tags; /* # of closed tags */ - - if (*cp == redelim) /* if first char is RE endmarker */ - return(cp++, expbuf); /* leave existing RE unchanged */ - - lastep = NULL; /* there's no previous RE */ - brnestp = brnest; /* initialize ptr to brnest array */ - tags = bcount = 0; /* initialize counters */ - - if (*ep++ = (*sp == '^')) /* check for start-of-line syntax */ - sp++; - - for (;;) { - if (ep >= expbuf + RELIMIT) /* match is too large */ - return(cp = sp, BAD); - if ((c = *sp++) == redelim) { /* found the end of the RE */ - cp = sp; - if (brnestp != brnest) /* \(, \) unbalanced */ - return(BAD); - *ep++ = CEOF; /* write end-of-pattern mark */ - return(ep); /* return ptr to compiled RE */ - } - if (c != '*') /* if we're a postfix op */ - lastep = ep; /* get ready to match last */ - - switch (c) { - case '\\': - if ((c = *sp++) == '(') { /* start tagged section */ - if (bcount >= MAXTAGS) return(cp = sp, BAD); - *brnestp++ = bcount; /* update tag stack */ - *ep++ = CBRA; /* enter tag-start */ - *ep++ = bcount++; /* bump tag count */ - continue; - } else if (c == ')') { /* end tagged section */ - if (brnestp <= brnest) /* extra \) */ - return(cp = sp, BAD); - *ep++ = CKET; /* enter end-of-tag */ - *ep++ = *--brnestp; /* pop tag stack */ - tags++; /* count closed tags */ - continue; - } else if (c >= '1' && c <= '9') { /* tag use */ - if ((c -= '1') >= tags) /* too few */ - return(BAD); - *ep++ = CBACK; /* enter tag mark */ - *ep++ = c; /* and the number */ - continue; - } else if (c == '\n') /* escaped newline no good */ - return(cp = sp, BAD); - else if (c == 'n') /* match a newline */ - c = '\n'; - else if (c == 't') /* match a tab */ - c = '\t'; - else if (c == 'r') /* match a return */ - c = '\r'; - goto defchar; - - case '\0': /* ignore nuls */ - continue; - - case '\n': /* trailing pattern delimiter is missing */ - return(cp = sp, BAD); - - case '.': /* match any char except newline */ - *ep++ = CDOT; - continue; - case '*': /* 0..n repeats of previous pattern */ - if (lastep == NULL) /* if * isn't first on line */ - goto defchar; /* match a literal * */ - if (*lastep == CKET) /* can't iterate a tag */ - return(cp = sp, BAD); - *lastep |= STAR;/* flag previous pattern */ - continue; - - case '$': /* match only end-of-line */ - if (*sp != redelim) /* if we're not at end of RE */ - goto defchar; /* match a literal $ */ - *ep++ = CDOL; /* insert end-symbol mark */ - continue; - - case '[': /* begin character set pattern */ - if (ep + 17 >= expbuf + RELIMIT) ABORT(REITL); - *ep++ = CCL; /* insert class mark */ - if (negclass = ((c = *sp++) == '^')) c = *sp++; - svclass = sp; /* save ptr to class start */ - do { - if (c == '\0') ABORT(CGMSG); - - /* Handle character ranges */ - if (c == '-' && sp > svclass && *sp != ']') - for (c = sp[-2]; c < *sp; c++) - ep[c >> 3] |= bits[c & 7]; - - /* Handle escape sequences in sets */ - if (c == '\\') - if ((c = *sp++) == 'n') - c = '\n'; - else if (c == 't') - c = '\t'; - else if (c == 'r') - c = '\r'; - - /* Enter (possibly translated) char in set */ - ep[c >> 3] |= bits[c & 7]; - } while - ((c = *sp++) != ']'); - - /* Invert the bitmask if all-but was specified */ - if (negclass) for (classct = 0; classct < 16; classct++) - ep[classct] ^= 0xFF; - ep[0] &= 0xFE; /* never match ASCII 0 */ - ep += 16; /* advance ep past set mask */ - continue; - - defchar: /* match literal character */ - default: /* which is what we'd do by default */ - *ep++ = CCHR; /* insert character mark */ - *ep++ = c; - } - } -} - -static int cmdline(cbuf) /* uses eflag, eargc, cmdf */ - /* Read next command from -e argument or command file */ -register char *cbuf; -{ - register int inc; /* not char because must hold EOF */ - - *cbuf-- = 0; /* so pre-increment points us at cbuf */ - - /* E command flag is on */ - if (eflag) { - register char *p; /* ptr to current -e argument */ - static char *savep; /* saves previous value of p */ - - if (eflag > 0) { /* there are pending -e arguments */ - eflag = -1; - if (eargc-- <= 0) quit(2); /* if no arguments, barf */ - - /* Else transcribe next e argument into cbuf */ - p = *++eargv; - while (*++cbuf = *p++) - if (*cbuf == '\\') { - if ((*++cbuf = *p++) == '\0') - return(savep = NULL, -1); - else - continue; - } else if (*cbuf == '\n') { /* end of 1 cmd line */ - *cbuf = '\0'; - return(savep = p, 1); - /* We'll be back for the rest... */ - } - - /* Found end-of-string; can advance to next argument */ - return(savep = NULL, 1); - } - if ((p = savep) == NULL) return(-1); - - while (*++cbuf = *p++) - if (*cbuf == '\\') { - if ((*++cbuf = *p++) == '0') - return(savep = NULL, -1); - else - continue; - } else if (*cbuf == '\n') { - *cbuf = '\0'; - return(savep = p, 1); - } - return(savep = NULL, 1); - } - - /* If no -e flag read from command file descriptor */ - while ((inc = getc(cmdf)) != EOF) /* get next char */ - if ((*++cbuf = inc) == '\\') /* if it's escape */ - *++cbuf = inc = getc(cmdf); /* get next char */ - else if (*cbuf == '\n') /* end on newline */ - return(*cbuf = '\0', 1); /* cap the string */ - - return(*++cbuf = '\0', -1); /* end-of-file, no more chars */ -} - -static char *address(expbuf) /* uses cp, linenum */ - /* Expand an address at *cp... into expbuf, return ptr at following char */ -register char *expbuf; -{ - static int numl = 0; /* current ind in addr-number table */ - register char *rcp; /* temp compile ptr for forwd look */ - long lno; /* computed value of numeric address */ - - if (*cp == '$') { /* end-of-source address */ - *expbuf++ = CEND; /* write symbolic end address */ - *expbuf++ = CEOF; /* and the end-of-address mark (!) */ - cp++; /* go to next source character */ - return(expbuf); /* we're done */ - } - if (*cp == '/' || *cp == '\\') { /* start of regular-expression match */ - if (*cp == '\\') cp++; - return(recomp(expbuf, *cp++)); /* compile the RE */ - } - - rcp = cp; - lno = 0; /* now handle a numeric address */ - while (*rcp >= '0' && *rcp <= '9') /* collect digits */ - lno = lno * 10 + *rcp++ - '0'; /* compute their value */ - - if (rcp > cp) { /* if we caught a number... */ - *expbuf++ = CLNUM; /* put a numeric-address marker */ - *expbuf++ = numl; /* and the address table index */ - linenum[numl++] = lno; /* and set the table entry */ - if (numl >= MAXLINES) /* oh-oh, address table overflow */ - ABORT(TMLNR); /* abort with error message */ - *expbuf++ = CEOF; /* write the end-of-address marker */ - cp = rcp; /* point compile past the address */ - return(expbuf); /* we're done */ - } - return(NULL); /* no legal address was found */ -} - -static char *gettext(txp) /* uses global cp */ - /* Accept multiline input from *cp..., discarding leading whitespace */ -register char *txp; /* where to put the text */ -{ - register char *p = cp; /* this is for speed */ - - SKIPWS(p); /* discard whitespace */ - do { - if ((*txp = *p++) == '\\') /* handle escapes */ - *txp = *p++; - if (*txp == '\0') /* we're at end of input */ - return(cp = --p, ++txp); - else if (*txp == '\n') /* also SKIPWS after newline */ - SKIPWS(p); - } while - (txp++); /* keep going till we find that nul */ - return(txp); -} - -static label *search(ptr) /* uses global lablst */ - /* Find the label matching *ptr, return NULL if none */ -register label *ptr; -{ - register label *rp; - for (rp = lablst; rp < ptr; rp++) - if ((rp->name != NULL) && (strcmp(rp->name, ptr->name) == 0)) - return(rp); - return(NULL); -} - -static void resolve() -{ /* uses global lablst */ - /* Write label links into the compiled-command space */ - register label *lptr; - register sedcmd *rptr, *trptr; - - /* Loop through the label table */ - for (lptr = lablst; lptr < lab; lptr++) - if (lptr->address == NULL) { /* barf if not defined */ - fprintf(stderr, ULABL, lptr->name); - quit(2); - } else if (lptr->last) {/* if last is non-null */ - rptr = lptr->last; /* chase it */ - while (trptr = rptr->u.link) { /* resolve refs */ - rptr->u.link = lptr->address; - rptr = trptr; - } - rptr->u.link = lptr->address; - } -} - -static char *ycomp(ep, delim) -/* Compile a y (transliterate) command */ -register char *ep; /* where to compile to */ -char delim; /* end delimiter to look for */ -{ - register char *tp, *sp; - register int c; - - /* Scan the 'from' section for invalid chars */ - for (sp = tp = cp; *tp != delim; tp++) { - if (*tp == '\\') tp++; - if ((*tp == '\n') || (*tp == '\0')) return (BAD); - } - tp++; /* tp now points at first char of 'to' - * section */ - - /* Now rescan the 'from' section */ - while ((c = *sp++ & 0x7F) != delim) { - if (c == '\\' && *sp == 'n') { - sp++; - c = '\n'; - } - if ((ep[c] = *tp++) == '\\' && *tp == 'n') { - ep[c] = '\n'; - tp++; - } - if ((ep[c] == delim) || (ep[c] == '\0')) return(BAD); - } - - if (*tp != delim) /* 'to', 'from' parts have unequal lengths */ - return(BAD); - - cp = ++tp; /* point compile ptr past translit */ - - for (c = 0; c < 128; c++) /* fill in self-map entries in table */ - if (ep[c] == 0) ep[c] = c; - - return(ep + 0x80); /* return first free location past table end */ -} - -void quit(n) -int n; -{ -/* Flush buffers and exit. Now a historical relic. Rely on exit to flush - * the buffers. - */ - exit(n); -} - -/*+++++++++++++++*/ - -/* - sedexec.c -- execute compiled form of stream editor commands - - The single entry point of this module is the function execute(). It - may take a string argument (the name of a file to be used as text) or - the argument NULL which tells it to filter standard input. It executes - the compiled commands in cmds[] on each line in turn. - - The function command() does most of the work. Match() and advance() - are used for matching text against precompiled regular expressions and - dosub() does right-hand-side substitution. Getline() does text input; - readout() and Memcmp() are output and string-comparison utilities. -*/ - -/* #include */ -/* #include */ -/* #include "sed.h" */ - -/***** shared variables imported from the main ******/ - -/* Main data areas */ -extern char linebuf[]; /* current-line buffer */ -extern sedcmd cmds[]; /* hold compiled commands */ -extern long linenum[]; /* numeric-addresses table */ - -/* Miscellaneous shared variables */ -extern int nflag; /* -n option flag */ -extern int eargc; /* scratch copy of argument count */ -extern char **eargv; /* scratch copy of argument list */ -extern char bits[]; /* the bits table */ - -/***** end of imported stuff *****/ - -#define MAXHOLD MAXBUF /* size of the hold space */ -#define GENSIZ MAXBUF /* maximum genbuf size */ - -#define TRUE 1 -#define FALSE 0 - -static char LTLMSG[] = "sed: line too long\n"; - -static char *spend; /* current end-of-line-buffer pointer */ -static long lnum = 0L; /* current source line number */ - -/* Append buffer maintenance */ -static sedcmd *appends[MAXAPPENDS]; /* array of ptrs to a,i,c commands */ -static sedcmd **aptr = appends; /* ptr to current append */ - -/* Genbuf and its pointers */ -static char genbuf[GENSIZ]; -static char *loc1; -static char *loc2; -static char *locs; - -/* Command-logic flags */ -static int lastline; /* do-line flag */ -static int jump; /* jump to cmd's link address if set */ -static int delete; /* delete command flag */ - -/* Tagged-pattern tracking */ -static char *bracend[MAXTAGS]; /* tagged pattern start pointers */ -static char *brastart[MAXTAGS]; /* tagged pattern end pointers */ - -static int anysub; /* true if any s on current line succeeded */ - - -void execute() -/* Execute the compiled commands in cmds[] */ -{ - register char *p1; /* dummy copy ptrs */ - register sedcmd *ipc; /* ptr to current command */ - char *execp; /* ptr to source */ - - - initget(); - - /* Here's the main command-execution loop */ - for (;;) { - - /* Get next line to filter */ - if ((execp = getline(linebuf)) == BAD) return; - spend = execp; - anysub = FALSE; - - /* Loop through compiled commands, executing them */ - for (ipc = cmds; ipc->command;) { - if (!selected(ipc)) { - ipc++; - continue; - } - command(ipc); /* execute the command pointed at */ - - if (delete) /* if delete flag is set */ - break; /* don't exec rest of compiled cmds */ - - if (jump) { /* if jump set, follow cmd's link */ - jump = FALSE; - if ((ipc = ipc->u.link) == 0) { - ipc = cmds; - break; - } - } else /* normal goto next command */ - ipc++; - } - - /* We've now done all modification commands on the line */ - - /* Here's where the transformed line is output */ - if (!nflag && !delete) { - for (p1 = linebuf; p1 < spend; p1++) putc(*p1, stdout); - putc('\n', stdout); - } - - /* If we've been set up for append, emit the text from it */ - if (aptr > appends) readout(); - - delete = FALSE; /* clear delete flag; about to get next cmd */ - } -} - -static int selected(ipc) -/* Is current command selected */ -sedcmd *ipc; -{ - register char *p1 = ipc->addr1; /* point p1 at first address */ - register char *p2 = ipc->addr2; /* and p2 at second */ - int c; - int sel = TRUE; /* select by default */ - - if (!p1) /* No addresses: always selected */ - ; - else if (ipc->flags.inrange) { - if (*p2 == CEND); - else if (*p2 == CLNUM) { - c = p2[1] & CMASK; - if (lnum >= linenum[c]) { - ipc->flags.inrange = FALSE; - if (lnum > linenum[c]) sel = FALSE; - } - } else if (match(p2, 0)) - ipc->flags.inrange = FALSE; - } else if (*p1 == CEND) { - if (!lastline) sel = FALSE; - } else if (*p1 == CLNUM) { - c = p1[1] & CMASK; - if (lnum != linenum[c]) - sel = FALSE; - else if (p2) - ipc->flags.inrange = TRUE; - } else if (match(p1, 0)) { - if (p2) ipc->flags.inrange = TRUE; - } else - sel = FALSE; - - return ipc->flags.allbut ? !sel : sel; -} - -static int match(expbuf, gf) /* uses genbuf */ - /* Match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */ -char *expbuf; -int gf; -{ - register char *p1, *p2, c; - - if (gf) { - if (*expbuf) return(FALSE); - p1 = linebuf; - p2 = genbuf; - while (*p1++ = *p2++); - locs = p1 = loc2; - } else { - p1 = linebuf; - locs = FALSE; - } - - p2 = expbuf; - if (*p2++) { - loc1 = p1; - if (*p2 == CCHR && p2[1] != *p1) /* 1st char is wrong */ - return(FALSE); /* so fail */ - return(advance(p1, p2));/* else try to match rest */ - } - - /* Quick check for 1st character if it's literal */ - if (*p2 == CCHR) { - c = p2[1]; /* pull out character to search for */ - do { - if (*p1 != c) continue; /* scan the source string */ - if (advance(p1, p2)) /* found it, match the rest */ - return(loc1 = p1, 1); - } while - (*p1++); - return(FALSE); /* didn't find that first char */ - } - - /* Else try for unanchored match of the pattern */ - do { - if (advance(p1, p2)) return(loc1 = p1, 1); - } while - (*p1++); - - /* If got here, didn't match either way */ - return(FALSE); -} - -static int advance(lp, ep) -/* Attempt to advance match pointer by one pattern element */ -register char *lp; /* source (linebuf) ptr */ -register char *ep; /* regular expression element ptr */ -{ - register char *curlp; /* save ptr for closures */ - char c; /* scratch character holder */ - char *bbeg; - int ct; - - for (;;) switch (*ep++) { - case CCHR: /* literal character */ - if (*ep++ == *lp++) /* if chars are equal */ - continue; /* matched */ - return(FALSE); /* else return false */ - - case CDOT: /* anything but newline */ - if (*lp++) /* first NUL is at EOL */ - continue; /* keep going if didn't find */ - return(FALSE); /* else return false */ - - case CNL: /* start-of-line */ - case CDOL: /* end-of-line */ - if (*lp == 0) /* found that first NUL? */ - continue; /* yes, keep going */ - return(FALSE); /* else return false */ - - case CEOF: /* end-of-address mark */ - loc2 = lp; /* set second loc */ - return(TRUE); /* return true */ - - case CCL: /* a closure */ - c = *lp++ & 0177; - if (ep[c >> 3] & bits[c & 07]) { /* is char in set? */ - ep += 16; /* then skip rest of bitmask */ - continue; /* and keep going */ - } - return(FALSE); /* else return false */ - - case CBRA: /* start of tagged pattern */ - brastart[*ep++] = lp; /* mark it */ - continue; /* and go */ - - case CKET: /* end of tagged pattern */ - bracend[*ep++] = lp; /* mark it */ - continue; /* and go */ - - case CBACK: - bbeg = brastart[*ep]; - ct = bracend[*ep++] - bbeg; - - if (Memcmp(bbeg, lp, ct)) { - lp += ct; - continue; - } - return(FALSE); - - case CBACK | STAR: - bbeg = brastart[*ep]; - ct = bracend[*ep++] - bbeg; - curlp = lp; - while (Memcmp(bbeg, lp, ct)) lp += ct; - - while (lp >= curlp) { - if (advance(lp, ep)) return(TRUE); - lp -= ct; - } - return(FALSE); - - - case CDOT | STAR: /* match .* */ - curlp = lp; /* save closure start loc */ - while (*lp++); /* match anything */ - goto star; /* now look for followers */ - - case CCHR | STAR: /* match * */ - curlp = lp; /* save closure start loc */ - while (*lp++ == *ep); /* match many of that char */ - ep++; /* to start of next element */ - goto star; /* match it and followers */ - - case CCL | STAR: /* match [...]* */ - curlp = lp; /* save closure start loc */ - do { - c = *lp++ & 0x7F; /* match any in set */ - } while - (ep[c >> 3] & bits[c & 07]); - ep += 16; /* skip past the set */ - goto star; /* match followers */ - - star: /* the recursion part of a * or + match */ - if (--lp == curlp) /* 0 matches */ - continue; - - if (*ep == CCHR) { - c = ep[1]; - do { - if (*lp != c) continue; - if (advance(lp, ep)) return (TRUE); - } while - (lp-- > curlp); - return(FALSE); - } - if (*ep == CBACK) { - c = *(brastart[ep[1]]); - do { - if (*lp != c) continue; - if (advance(lp, ep)) return (TRUE); - } while - (lp-- > curlp); - return(FALSE); - } - do { - if (lp == locs) break; - if (advance(lp, ep)) return (TRUE); - } while - (lp-- > curlp); - return(FALSE); - - default: - fprintf(stderr, "sed: RE error, %o\n", *--ep); - quit(2); - } -} - -static int substitute(ipc) -/* Perform s command */ -sedcmd *ipc; /* ptr to s command struct */ -{ - int nullmatch; - - if (match(ipc->u.lhs, 0)) { /* if no match */ - nullmatch = (loc1 == loc2); - dosub(ipc->rhs); /* perform it once */ - } else - return(FALSE); /* command fails */ - - if (ipc->flags.global) /* if global flag enabled */ - while (*loc2) { /* cycle through possibles */ - if (nullmatch) loc2++; - if (match(ipc->u.lhs, 1)) { /* found another */ - nullmatch = (loc1 == loc2); - dosub(ipc->rhs); /* so substitute */ - } else /* otherwise, */ - break; /* we're done */ - } - return(TRUE); /* we succeeded */ -} - -static void dosub(rhsbuf) /* uses linebuf, genbuf, spend */ - /* Generate substituted right-hand side (of s command) */ -char *rhsbuf; /* where to put the result */ -{ - register char *lp, *sp, *rp; - int c; - - /* Copy linebuf to genbuf up to location 1 */ - lp = linebuf; - sp = genbuf; - while (lp < loc1) *sp++ = *lp++; - - for (rp = rhsbuf; c = *rp++;) { - if (c == '&') { - sp = place(sp, loc1, loc2); - continue; - } else if (c & 0200 && (c &= 0177) >= '1' && c < MAXTAGS + '1') { - sp = place(sp, brastart[c - '1'], bracend[c - '1']); - continue; - } - *sp++ = c & 0177; - if (sp >= genbuf + MAXBUF) fprintf(stderr, LTLMSG); - } - lp = loc2; - loc2 = sp - genbuf + linebuf; - while (*sp++ = *lp++) - if (sp >= genbuf + MAXBUF) fprintf(stderr, LTLMSG); - lp = linebuf; - sp = genbuf; - while (*lp++ = *sp++); - spend = lp - 1; -} - -static char *place(asp, al1, al2) /* uses genbuf */ - /* Place chars at *al1...*(al1 - 1) at asp... in genbuf[] */ -register char *asp, *al1, *al2; -{ - while (al1 < al2) { - *asp++ = *al1++; - if (asp >= genbuf + MAXBUF) fprintf(stderr, LTLMSG); - } - return(asp); -} - -static void listto(p1, fp) -/* Write a hex dump expansion of *p1... to fp */ -register char *p1; /* the source */ -FILE *fp; /* output stream to write to */ -{ - p1--; - while (*p1++) - if (isprint(*p1)) - putc(*p1, fp); /* pass it through */ - else { - putc('\\', fp); /* emit a backslash */ - switch (*p1) { - case '\b': - putc('b', fp); - break; /* BS */ - case '\t': - putc('t', fp); - break; /* TAB */ - case '\n': - putc('n', fp); - break; /* NL */ - case '\r': - putc('r', fp); - break; /* CR */ - case '\33': - putc('e', fp); - break; /* ESC */ - default: - fprintf(fp, "%02x", *p1 & 0xFF); - } - } - putc('\n', fp); -} - -static void truncated(h) -int h; -{ - static long last = 0L; - - if (lnum == last) return; - last = lnum; - - fprintf(stderr, "sed: "); - fprintf(stderr, h ? "hold space" : "line %ld", lnum); - fprintf(stderr, " truncated to %d characters\n", MAXBUF); -} - -static void command(ipc) -/* Execute compiled command pointed at by ipc */ -sedcmd *ipc; -{ - static char holdsp[MAXHOLD + 1]; /* the hold space */ - static char *hspend = holdsp; /* hold space end pointer */ - register char *p1, *p2; - char *execp; - int didsub; /* true if last s succeeded */ - - switch (ipc->command) { - case ACMD: /* append */ - *aptr++ = ipc; - if (aptr >= appends + MAXAPPENDS) fprintf(stderr, - "sed: too many appends after line %ld\n", - lnum); - *aptr = 0; - break; - - case CCMD: /* change pattern space */ - delete = TRUE; - if (!ipc->flags.inrange || lastline) printf("%s\n", ipc->u.lhs); - break; - - case DCMD: /* delete pattern space */ - delete++; - break; - - case CDCMD: /* delete a line in hold space */ - p1 = p2 = linebuf; - while (*p1 != '\n') - if (delete = (*p1++ == 0)) return; - p1++; - while (*p2++ = *p1++) continue; - spend = p2 - 1; - jump++; - break; - - case EQCMD: /* show current line number */ - fprintf(stdout, "%ld\n", lnum); - break; - - case GCMD: /* copy hold space to pattern space */ - p1 = linebuf; - p2 = holdsp; - while (*p1++ = *p2++); - spend = p1 - 1; - break; - - case CGCMD: /* append hold space to pattern space */ - *spend++ = '\n'; - p1 = spend; - p2 = holdsp; - do - if (p1 > linebuf + MAXBUF) { - truncated(0); - p1[-1] = 0; - break; - } - while (*p1++ = *p2++); - - spend = p1 - 1; - break; - - case HCMD: /* copy pattern space to hold space */ - p1 = holdsp; - p2 = linebuf; - while (*p1++ = *p2++); - hspend = p1 - 1; - break; - - case CHCMD: /* append pattern space to hold space */ - *hspend++ = '\n'; - p1 = hspend; - p2 = linebuf; - do - if (p1 > holdsp + MAXBUF) { - truncated(1); - p1[-1] = 0; - break; - } - while (*p1++ = *p2++); - - hspend = p1 - 1; - break; - - case ICMD: /* insert text */ - printf("%s\n", ipc->u.lhs); - break; - - case BCMD: /* branch to label */ - jump = TRUE; - break; - - case LCMD: /* list text */ - listto(linebuf, (ipc->fout != NULL) ? ipc->fout : stdout); - break; - - case NCMD: /* read next line into pattern space */ - if (!nflag) puts(linebuf); /* flush out the current line */ - if (aptr > appends) readout(); /* do pending a, r commands */ - if ((execp = getline(linebuf)) == BAD) { - delete = TRUE; - break; - } - spend = execp; - anysub = FALSE; - break; - - case CNCMD: /* append next line to pattern space */ - if (aptr > appends) readout(); - *spend++ = '\n'; - if ((execp = getline(spend)) == BAD) { - *--spend = 0; - break; - } - spend = execp; - anysub = FALSE; - break; - - case PCMD: /* print pattern space */ - puts(linebuf); - break; - - case CPCMD: /* print one line from pattern space */ -cpcom: /* so s command can jump here */ - for (p1 = linebuf; *p1 != '\n' && *p1 != '\0';) putc(*p1++, stdout); - putc('\n', stdout); - break; - - case QCMD: /* quit the stream editor */ - if (!nflag) puts(linebuf); /* flush out the current line */ - if (aptr > appends) - readout(); /* do any pending a and r commands */ - quit(0); - - case RCMD: /* read a file into the stream */ - *aptr++ = ipc; - if (aptr >= appends + MAXAPPENDS) fprintf(stderr, - "sed: too many reads after line %ld\n", - lnum); - *aptr = 0; - break; - - case SCMD: /* substitute RE */ - didsub = substitute(ipc); - if (didsub) anysub = TRUE; - if (ipc->flags.print && didsub) - if (ipc->flags.print == TRUE) - puts(linebuf); - else - goto cpcom; - if (didsub && ipc->fout) fprintf(ipc->fout, "%s\n", linebuf); - break; - - case TCMD: /* branch on any s successful */ - case CTCMD: /* branch on any s failed */ - if (anysub == (ipc->command == CTCMD)) - break; /* no branch if any s failed, else */ - anysub = FALSE; - jump = TRUE; /* set up to jump to assoc'd label */ - break; - - case CWCMD: /* write one line from pattern space */ - for (p1 = linebuf; *p1 != '\n' && *p1 != '\0';) - putc(*p1++, ipc->fout); - putc('\n', ipc->fout); - break; - - case WCMD: /* write pattern space to file */ - fprintf(ipc->fout, "%s\n", linebuf); - break; - - case XCMD: /* exchange pattern and hold spaces */ - p1 = linebuf; - p2 = genbuf; - while (*p2++ = *p1++) continue; - p1 = holdsp; - p2 = linebuf; - while (*p2++ = *p1++) continue; - spend = p2 - 1; - p1 = genbuf; - p2 = holdsp; - while (*p2++ = *p1++) continue; - hspend = p2 - 1; - break; - - case YCMD: - p1 = linebuf; - p2 = ipc->u.lhs; - while (*p1 = p2[*p1]) p1++; - break; - } -} - -static void openfile(file) -char *file; -/* Replace stdin by given file */ -{ - if (freopen(file, "r", stdin) == NULL) { - fprintf(stderr, "sed: can't open %s\n", file); - quit(1); - } -} - -static int c; /* Will be the next char to read, a kind of - * lookahead */ - -static void get() -/* Read next character into c treating all argument files as run through cat */ -{ - while ((c = getchar()) == EOF && --eargc >= 0) openfile(*eargv++); -} - -static void initget() -/* Initialise character input */ -{ - if (--eargc >= 0) openfile(*eargv++); /* else input == stdin */ - get(); -} - -static char *getline(buf) -/* Get next line of text to be edited, return pointer to end */ -register char *buf; /* where to send the input */ -{ - if (c == EOF) return BAD; - - lnum++; /* we can read a new line */ - - do { - if (c == '\n') { - get(); - break; - } - if (buf <= linebuf + MAXBUF) *buf++ = c; - get(); - } while (c != EOF); - - if (c == EOF) lastline = TRUE; - - if (buf > linebuf + MAXBUF) { - truncated(0); - --buf; - } - *buf = 0; - return buf; -} - -static int Memcmp(a, b, count) -/* Return TRUE if *a... == *b... for count chars, FALSE otherwise */ -register char *a, *b; -int count; -{ - while (count--) /* look at count characters */ - if (*a++ != *b++) /* if any are nonequal */ - return(FALSE); /* return FALSE for false */ - return(TRUE); /* compare succeeded */ -} - -static void readout() -/* Write file indicated by r command to output */ -{ - register int t; /* hold input char or EOF */ - FILE *fi; /* ptr to file to be read */ - - aptr = appends - 1; /* arrange for pre-increment to work right */ - while (*++aptr) - if ((*aptr)->command == ACMD) /* process "a" cmd */ - printf("%s\n", (*aptr)->u.lhs); - else { /* process "r" cmd */ - if ((fi = fopen((*aptr)->u.lhs, "r")) == NULL) { - fprintf(stderr, "sed: can't open %s\n", - (*aptr)->u.lhs); - continue; - } - while ((t = getc(fi)) != EOF) putc((char) t, stdout); - fclose(fi); - } - aptr = appends; /* reset the append ptr */ - *aptr = 0; -} - -/* Sedexec.c ends here */