woodman@suvax1.UUCP (David Woodman) (07/28/88)
Now that I have the ver. 1.3 diffs and GNU sed, I decided to try and upgrade my ver. 1.2 system. Sed is not exactly working very well on my system. 1) Bit fields are not supported - no problem. 2) when taking posting #19 out of shar I got a "out of string space" error. - Where did THAT error message come from? 3) sed sometimes leaves a file with a size of 0 (zero). Flakey. could someone please e-mail me the source code to a <working> sed? I am not really thrilled with the idea of spelunking sed code right now. Thanks, P.S. Please don't suggest getting it from an archive, I did. (listserv@ndsuvm1) ------------------------------------------------------------------------------ David Woodman UUCP: ...!uw-entropy!dataio!suvax1!woodman Seattle University USNail: P.O. Box 23202, Seattle WA 98102 Phone: (206) 223-9470 ------------------------------------------------------------------------------
rivers@xyzzy.UUCP (Dave Rivers) (08/03/88)
In article <1178@suvax1.UUCP> woodman@suvax1.UUCP (David Woodman) writes: Now that I have the ver. 1.3 diffs and GNU sed, I decided to try and upgrade my ver. 1.2 system. Sed is not exactly working very well on my system. 1) Bit fields are not supported - no problem. 2) when taking posting #19 out of shar I got a "out of string space" error. - Where did THAT error message come from? 3) sed sometimes leaves a file with a size of 0 (zero). Flakey. could someone please e-mail me the source code to a <working> sed? I am not really thrilled with the idea of spelunking sed code right now. Thanks, --------------------------------------------------------------------------- Me too... It would appear that while I received all the fixs to sed, I never got the original source. The "sed patches" I received discussed a version that was posted sometime in late '87. Could someone please mail that to me, or better yet, if there seems to be a lot of requests, repost it. Thanx in advance - - Dave Rivers - -- +----------------------------------------------------------------------+ | Time Sharing is the use of | Dave Rivers: | | many people by the computer. | UUCP {Backbones}!rti!dg-rtp!rivers | | | Phone: (919) 248-6137 | +----------------------------------------------------------------------+
wswietse@eutrc3.UUCP (Wietse Venema) (08/05/88)
This is the sed source I got from comp.os.minix in late 1987, plus my already applied patch to get it working on a sun-3/160 an on 80286 unix (microport). Wietse Venema uucp: mcvax!eutrc3!wswietse | Eindhoven University of Technology bitnet: wswietse@heithe5 | Dept. of Mathematics and Computing Science surf: tuerc5::wswietse | Eindhoven, The Netherlands. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: makefile debug.h sed.h sedcomp.c sedexec.c sedpatch # Wrapped by wswietse@tuewsa on Fri Aug 5 16:26:13 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"makefile\" else echo shar: Extracting \"makefile\" \(117 characters\) sed "s/^X//" >makefile <<'END_OF_makefile' XCFLAGS = -g XOBJECTS = sedcomp.o sedexec.o X Xsed: $(OBJECTS) X cc $(CFLAGS) -o $@ $(OBJECTS) X X$(OBJECTS): debug.h sed.h END_OF_makefile if test 117 -ne `wc -c <makefile`; then echo shar: \"makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f debug.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"debug.h\" else echo shar: Extracting \"debug.h\" \(39 characters\) sed "s/^X//" >debug.h <<'END_OF_debug.h' X#define PASS(x) X/*printf("%s\n", x)*/ END_OF_debug.h if test 39 -ne `wc -c <debug.h`; then echo shar: \"debug.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f sed.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"sed.h\" else echo shar: Extracting \"sed.h\" \(3987 characters\) sed "s/^X//" >sed.h <<'END_OF_sed.h' X/* sed.h -- types and constants for the stream editor */ X X/* data area sizes used by both modules */ X#define MAXBUF 4000 /* current line buffer size */ X#define MAXAPPENDS 20 /* maximum number of appends */ X#define MAXTAGS 9 /* tagged patterns are \1 to \9 */ X X/* constants for compiled-command representation */ X#define EQCMD 0x01 /* = -- print current line number */ X#define ACMD 0x02 /* a -- append text after current line */ X#define BCMD 0x03 /* b -- branch to label */ X#define CCMD 0x04 /* c -- change current line */ X#define DCMD 0x05 /* d -- delete all of pattern space */ X#define CDCMD 0x06 /* D -- delete first line of pattern space */ X#define GCMD 0x07 /* g -- copy hold space to pattern space */ X#define CGCMD 0x08 /* G -- append hold space to pattern space */ X#define HCMD 0x09 /* h -- copy pattern space to hold space */ X#define CHCMD 0x0A /* H -- append hold space to pattern space */ X#define ICMD 0x0B /* i -- insert text before current line */ X#define LCMD 0x0C /* l -- print pattern space in escaped form */ X#define NCMD 0x0D /* n -- get next line into pattern space */ X#define CNCMD 0x0E /* N -- append next line to pattern space */ X#define PCMD 0x0F /* p -- print pattern space to output */ X#define CPCMD 0x10 /* P -- print first line of pattern space */ X#define QCMD 0x11 /* q -- exit the stream editor */ X#define RCMD 0x12 /* r -- read in a file after current line */ X#define SCMD 0x13 /* s -- regular-expression substitute */ X#define TCMD 0x14 /* t -- branch on last substitute successful */ X#define CTCMD 0x15 /* T -- branch on last substitute failed */ X#define WCMD 0x16 /* w -- write pattern space to file */ X#define CWCMD 0x17 /* W -- write first line of pattern space */ X#define XCMD 0x18 /* x -- exhange pattern and hold spaces */ X#define YCMD 0x19 /* y -- transliterate text */ X Xstruct cmd_t /* compiled-command representation */ X{ X char *addr1; /* first address for command */ X char *addr2; /* second address for command */ X union X { X char *lhs; /* s command lhs */ X struct cmd_t *link; /* label link */ X } u; X char command; /* command code */ X char *rhs; /* s command replacement string */ X FILE *fout; /* associated output file descriptor */ X struct X { X char allbut ; /* was negation specified? */ X char global ; /* was p postfix specified? */ X char print ; /* was g postfix specified? */ X char inrange ; /* in an address range? */ X } flags; X}; Xtypedef struct cmd_t sedcmd; /* use this name for declarations */ X X#define BAD ((char *) -1) /* guaranteed not a string ptr */ X X X/* address and regular expression compiled-form markers */ X#define STAR 1 /* marker for Kleene star */ X#define CCHR 2 /* non-newline character to be matched follows */ X#define CDOT 4 /* dot wild-card marker */ X#define CCL 6 /* character class follows */ X#define CNL 8 /* match line start */ X#define CDOL 10 /* match line end */ X#define CBRA 12 /* tagged pattern start marker */ X#define CKET 14 /* tagged pattern end marker */ X#define CBACK 16 /* backslash-digit pair marker */ X#define CLNUM 18 /* numeric-address index follows */ X#define CEND 20 /* symbol for end-of-source */ X#define CEOF 22 /* end-of-field mark */ X X/* sed.h ends here */ END_OF_sed.h if test 3987 -ne `wc -c <sed.h`; then echo shar: \"sed.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f sedcomp.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"sedcomp.c\" else echo shar: Extracting \"sedcomp.c\" \(37219 characters\) sed "s/^X//" >sedcomp.c <<'END_OF_sedcomp.c' X#ifdef foo X #include "compiler.h" X #ifdef LATTICE X #define void int X #endif X#endif X X#include "debug.h" X/* sedcomp.c -- stream editor main and compilation phase X X The stream editor compiles its command input (from files or -e options) Xinto an internal form using compile() then executes the compiled form using Xexecute(). Main() just initializes data structures, interprets command line Xoptions, and calls compile() and execute() in appropriate sequence. X The data structure produced by compile() is an array of compiled-command Xstructures (type sedcmd). These contain several pointers into pool[], the Xregular-expression and text-data pool, plus a command code and g & p flags. XIn the special case that the command is a label the struct will hold a ptr Xinto the labels array labels[] during most of the compile, until resolve() Xresolves references at the end. X The operation of execute() is described in its source module. X X==== Written for the GNU operating system by Eric S. Raymond ==== */ X X#include <stdio.h> /* uses getc, fprintf, fopen, fclose */ X#include "sed.h" /* command type struct and name defines */ X X/* imported functions */ Xextern int strcmp(); /* test strings for equality */ Xextern void execute(); /* execute compiled command */ X X/***** public stuff ******/ X X#define MAXCMDS 200 /* maximum number of compiled commands */ X#define MAXLINES 256 /* max # numeric addresses to compile */ X X/* main data areas */ Xchar linebuf[MAXBUF+1]; /* current-line buffer */ Xsedcmd cmds[MAXCMDS+1]; /* hold compiled commands */ Xlong linenum[MAXLINES]; /* numeric-addresses table */ X X/* miscellaneous shared variables */ Xint nflag; /* -n option flag */ Xint eargc; /* scratch copy of argument count */ Xsedcmd *pending = NULL; /* next command to be executed */ Xchar bits[] = {1,2,4,8,16,32,64,128}; X X/***** module common stuff *****/ X X#define POOLSIZE 10000 /* size of string-pool space */ X#define WFILES 10 /* max # w output files that can be compiled */ X#define RELIMIT 256 /* max chars in compiled RE */ X#define MAXDEPTH 20 /* maximum {}-nesting level */ X#define MAXLABS 50 /* max # of labels that can be handled */ X X#define SKIPWS(pc) while ((*pc==' ') || (*pc=='\t')) pc++ X#define ABORT(msg) (fprintf(stderr, msg, linebuf), exit(2)) X#define IFEQ(x, v) if (*x == v) x++ , /* do expression */ X X/* error messages */ Xstatic char AGMSG[] = "sed: garbled address %s\n"; Xstatic char CGMSG[] = "sed: garbled command %s\n"; Xstatic char TMTXT[] = "sed: too much text: %s\n"; Xstatic char AD1NG[] = "sed: no addresses allowed for %s\n"; Xstatic char AD2NG[] = "sed: only one address allowed for %s\n"; Xstatic char TMCDS[] = "sed: too many commands, last was %s\n"; Xstatic char COCFI[] = "sed: cannot open command-file %s\n"; Xstatic char UFLAG[] = "sed: unknown flag %c\n"; Xstatic char COOFI[] = "sed: cannot open %s\n"; Xstatic char CCOFI[] = "sed: cannot create %s\n"; Xstatic char ULABL[] = "sed: undefined label %s\n"; Xstatic char TMLBR[] = "sed: too many {'s\n"; Xstatic char FRENL[] = "sed: first RE must be non-null\n"; Xstatic char NSCAX[] = "sed: no such command as %s\n"; Xstatic char TMRBR[] = "sed: too many }'s\n"; Xstatic char DLABL[] = "sed: duplicate label %s\n"; Xstatic char TMLAB[] = "sed: too many labels: %s\n"; Xstatic char TMWFI[] = "sed: too many w files\n"; Xstatic char REITL[] = "sed: RE too long: %s\n"; Xstatic char TMLNR[] = "sed: too many line numbers\n"; Xstatic char TRAIL[] = "sed: command \"%s\" has trailing garbage\n"; X Xtypedef struct /* represent a command label */ X{ X char *name; /* the label name */ X sedcmd *last; /* it's on the label search list */ X sedcmd *address; /* pointer to the cmd it labels */ X} Xlabel; X X/* label handling */ Xstatic label labels[MAXLABS]; /* here's the label table */ Xstatic label *lab = labels + 1; /* pointer to current label */ Xstatic label *lablst = labels; /* header for search list */ X X/* string pool for regular expressions, append text, etc. etc. */ Xstatic char pool[POOLSIZE]; /* the pool */ Xstatic char *fp = pool; /* current pool pointer */ Xstatic char *poolend = pool + POOLSIZE; /* pointer past pool end */ X X/* compilation state */ Xstatic FILE *cmdf = NULL; /* current command source */ Xstatic char *cp = linebuf; /* compile pointer */ Xstatic sedcmd *cmdp = cmds; /* current compiled-cmd ptr */ Xstatic char *lastre = NULL; /* old RE pointer */ Xstatic int bdepth = 0; /* current {}-nesting level */ Xstatic int bcount = 0; /* # tagged patterns in current RE */ Xstatic char **eargv; /* scratch copy of argument list */ X X/* compilation flags */ Xstatic int eflag; /* -e option flag */ Xstatic int gflag; /* -g option flag */ X X Xmain(argc, argv) X/* main sequence of the stream editor */ Xint argc; Xchar *argv[]; X{ X void compile(), resolve(); X X eargc = argc; /* set local copy of argument count */ X eargv = argv; /* set local copy of argument list */ X cmdp->addr1 = pool; /* 1st addr expand will be at pool start */ X if (eargc == 1) X exit(0); /* exit immediately if no arguments */ XPASS("main(): setup"); X /* scan through the arguments, interpreting each one */ X while ((--eargc > 0) && (**++eargv == '-')) X switch (eargv[0][1]) X { X case 'e': X eflag++; compile(); /* compile with e flag on */ X eflag = 0; X continue; /* get another argument */ X case 'f': X if (eargc-- <= 0) /* barf if no -f file */ X exit(2); X if ((cmdf = fopen(*++eargv, "r")) == NULL) X { X fprintf(stderr, COCFI, *eargv); X exit(2); X } X compile(); /* file is O.K., compile it */ X fclose(cmdf); X continue; /* go back for another argument */ X case 'g': X gflag++; /* set global flag on all s cmds */ X continue; X case 'n': X nflag++; /* no print except on p flag or w */ X continue; X default: X fprintf(stdout, UFLAG, eargv[0][1]); X continue; X } X XPASS("main(): argscan"); X X if (cmdp == cmds) /* no commands have been compiled */ X { X eargv--; eargc++; X eflag++; compile(); eflag = 0; X eargv++; eargc--; X } X X if (bdepth) /* we have unbalanced squigglies */ X ABORT(TMLBR); X X lablst->address = cmdp; /* set up header of label linked list */ X resolve(); /* resolve label table indirections */ XPASS("main(): resolve"); X if (eargc <= 0) /* if there were no -e commands */ X execute(NULL); /* execute commands from stdin only */ X else while(--eargc>=0) /* else execute only -e commands */ X execute(*eargv++); XPASS("main(): end & exit OK"); X exit(0); /* everything was O.K. if we got here */ X} X X X#define H 0x80 /* 128 bit, on if there's really code for command */ X#define LOWCMD 56 /* = '8', lowest char indexed in cmdmask */ X X/* indirect through this to get command internal code, if it exists */ Xstatic char cmdmask[] = X{ X 0, 0, H, 0, 0, H+EQCMD,0, 0, X 0, 0, 0, 0, H+CDCMD,0, 0, CGCMD, X CHCMD, 0, 0, 0, 0, 0, CNCMD, 0, X CPCMD, 0, 0, 0, H+CTCMD,0, 0, H+CWCMD, X 0, 0, 0, 0, 0, 0, 0, 0, X 0, H+ACMD, H+BCMD, H+CCMD, DCMD, 0, 0, GCMD, X HCMD, H+ICMD, 0, 0, H+LCMD, 0, NCMD, 0, X PCMD, H+QCMD, H+RCMD, H+SCMD, H+TCMD, 0, 0, H+WCMD, X XCMD, H+YCMD, 0, H+BCMD, 0, H, 0, 0, X}; X Xstatic void compile() X/* precompile sed commands out of a file */ X{ X char ccode, *address(); X XPASS("compile(): entry"); X X for(;;) /* main compilation loop */ X { X if (*cp != ';') /* get a new command line */ X if (cmdline(cp = linebuf) < 0) X break; X SKIPWS(cp); X if (*cp=='\0' || *cp=='#') /* a comment */ X continue; X if (*cp == ';') /* ; separates cmds */ X { X cp++; X continue; X } X X /* compile first address */ X if (fp > poolend) X ABORT(TMTXT); X else if ((fp = address(cmdp->addr1 = fp)) == BAD) X ABORT(AGMSG); X X if (fp == cmdp->addr1) /* if empty RE was found */ X { X if (lastre) /* if there was previous RE */ X cmdp->addr1 = lastre; /* use it */ X else X ABORT(FRENL); X } X else if (fp == NULL) /* if fp was NULL */ X { X fp = cmdp->addr1; /* use current pool location */ X cmdp->addr1 = NULL; X } X else X { X lastre = cmdp->addr1; X if (*cp == ',' || *cp == ';') /* there's 2nd addr */ X { X cp++; X if (fp > poolend) ABORT(TMTXT); X fp = address(cmdp->addr2 = fp); X if (fp == BAD || fp == NULL) ABORT(AGMSG); X if (fp == cmdp->addr2) X cmdp->addr2 = lastre; X else X lastre = cmdp->addr2; X } X else X cmdp->addr2 = NULL; /* no 2nd address */ X } X if (fp > poolend) ABORT(TMTXT); X X SKIPWS(cp); /* discard whitespace after address */ X IFEQ(cp, '!') cmdp->flags.allbut = 1; X X SKIPWS(cp); /* get cmd char, range-check it */ X if ((*cp < LOWCMD) || (*cp > '~') X || ((ccode = cmdmask[*cp - LOWCMD]) == 0)) X ABORT(NSCAX); X X cmdp->command = ccode & ~H; /* fill in command value */ X if ((ccode & H) == 0) /* if no compile-time code */ X cp++; /* discard command char */ X else if (cmdcomp(*cp++)) /* execute it; if ret = 1 */ X continue; /* skip next line read */ X X if (++cmdp >= cmds + MAXCMDS) ABORT(TMCDS); X X SKIPWS(cp); /* look for trailing stuff */ X if (*cp != '\0') X if (*++cp == ';') X continue; X else if (cp[-1] != '#') X ABORT(TRAIL); X } X} X Xstatic int cmdcomp(cchar) X/* compile a single command */ Xregister char cchar; /* character name of command */ X{ X char *gettext(), *rhscomp(), *recomp(), *ycomp(); X static sedcmd **cmpstk[MAXDEPTH]; /* current cmd stack for {} */ X static char *fname[WFILES]; /* w file name pointers */ X static FILE *fout[WFILES]; /* w file file ptrs */ X static int nwfiles = 1; /* count of open w files */ X int i; /* indexing dummy used in w */ X sedcmd *sp1, *sp2; /* temps for label searches */ X label *lpt, *search(); /* ditto, and the searcher */ X char redelim; /* current RE delimiter */ X X fout[0] = stdout; X switch(cchar) X { X case '{': /* start command group */ X cmdp->flags.allbut = !cmdp->flags.allbut; X cmpstk[bdepth++] = &(cmdp->u.link); X if (++cmdp >= cmds + MAXCMDS) ABORT(TMCDS); X if (*cp == '\0') *cp = ';'; /* get next cmd w/o lineread */ X return(1); X X case '}': /* end command group */ X if (cmdp->addr1) ABORT(AD1NG); /* no addresses allowed */ X if (--bdepth < 0) ABORT(TMRBR); /* too many right braces */ X *cmpstk[bdepth] = cmdp; /* set the jump address */ X return(1); X X case '=': /* print current source line number */ X case 'q': /* exit the stream editor */ X if (cmdp->addr2) ABORT(AD2NG); X break; X X case ':': /* label declaration */ X if (cmdp->addr1) ABORT(AD1NG); /* no addresses allowed */ X fp = gettext(lab->name = fp); /* get the label name */ X if (lpt = search(lab)) /* does it have a double? */ X { X if (lpt->address) ABORT(DLABL); /* yes, abort */ X } X else /* check that it doesn't overflow label table */ X { X lab->last = NULL; X lpt = lab; X if (++lab >= labels + MAXLABS) ABORT(TMLAB); X } X lpt->address = cmdp; X return(1); X X case 'b': /* branch command */ X case 't': /* branch-on-succeed command */ X case 'T': /* branch-on-fail command */ X SKIPWS(cp); X if (*cp == '\0') /* if branch is to start of cmds... */ X { X /* add current command to end of label last */ X if (sp1 = lablst->last) X { X while(sp2 = sp1->u.link) X sp1 = sp2; X sp1->u.link = cmdp; X } X else /* lablst->last == NULL */ X lablst->last = cmdp; X break; X } X fp = gettext(lab->name = fp); /* else get label into pool */ X if (lpt = search(lab)) /* enter branch to it */ X { X if (lpt->address) X cmdp->u.link = lpt->address; X else X { X sp1 = lpt->last; X while(sp2 = sp1->u.link) X sp1 = sp2; X sp1->u.link = cmdp; X } X } X else /* matching named label not found */ X { X lab->last = cmdp; /* add the new label */ X lab->address = NULL; /* it's forward of here */ X if (++lab >= labels + MAXLABS) /* overflow if last */ X ABORT(TMLAB); X } X break; X X case 'a': /* append text */ X case 'i': /* insert text */ X case 'r': /* read file into stream */ X if (cmdp->addr2) ABORT(AD2NG); X case 'c': /* change text */ X if ((*cp == '\\') && (*++cp == '\n')) cp++; X fp = gettext(cmdp->u.lhs = fp); X break; X X case 'D': /* delete current line in hold space */ X cmdp->u.link = cmds; X break; X X case 's': /* substitute regular expression */ X redelim = *cp++; /* get delimiter from 1st ch */ X if ((fp = recomp(cmdp->u.lhs = fp, redelim)) == BAD) X ABORT(CGMSG); X if (fp == cmdp->u.lhs) /* if compiled RE zero len */ X cmdp->u.lhs = lastre; /* use the previous one */ X else /* otherwise */ X lastre = cmdp->u.lhs; /* save the one just found */ X if ((cmdp->rhs = fp) > poolend) ABORT(TMTXT); X if ((fp = rhscomp(cmdp->rhs, redelim)) == BAD) ABORT(CGMSG); X if (gflag) cmdp->flags.global++; X while (*cp == 'g' || *cp == 'p' || *cp == 'P') X { X IFEQ(cp, 'g') cmdp->flags.global++; X IFEQ(cp, 'p') cmdp->flags.print = 1; X IFEQ(cp, 'P') cmdp->flags.print = 2; X } X X case 'l': /* list pattern space */ X if (*cp == 'w') X cp++; /* and execute a w command! */ X else X break; /* s or l is done */ X X case 'w': /* write-pattern-space command */ X case 'W': /* write-first-line command */ X if (nwfiles >= WFILES) ABORT(TMWFI); X fp=gettext(fname[nwfiles]=fp); /* filename will be in pool */ X for(i = nwfiles-1; i >= 0; i--) /* match it in table */ X if (strcmp(fname[nwfiles], fname[i]) == 0) X { X cmdp->fout = fout[i]; X return(0); X } X /* if didn't find one, open new out file */ X if ((cmdp->fout = fopen(fname[nwfiles], "w")) == NULL) X { X fprintf(stderr, CCOFI, fname[nwfiles]); X exit(2); X } X fout[nwfiles++] = cmdp->fout; X break; X X case 'y': /* transliterate text */ X fp = ycomp(cmdp->u.lhs = fp, *cp++); /* compile translit */ X if (fp == BAD) ABORT(CGMSG); /* fail on bad form */ X if (fp > poolend) ABORT(TMTXT); /* fail on overflow */ X break; X } X return(0); /* succeeded in interpreting one command */ X} X Xstatic char *rhscomp(rhsp, delim) /* uses bcount */ X/* generate replacement string for substitute command right hand side */ Xregister char *rhsp; /* place to compile expression to */ Xregister char delim; /* regular-expression end-mark to look for */ X{ X register char *p = cp; /* strictly for speed */ X X for(;;) X if ((*rhsp = *p++) == '\\') /* copy; if it's a \, */ X { X *rhsp = *p++; /* copy escaped char */ X /* check validity of pattern tag */ X if (*rhsp > bcount + '0' && *rhsp <= '9') X return(BAD); X *rhsp++ |= 0x80; /* mark the good ones */ X continue; X } X else if (*rhsp == delim) /* found RE end, hooray... */ X { X *rhsp++ = '\0'; /* cap the expression string */ X cp = p; X return(rhsp); /* pt at 1 past the RE */ X } X else if (*rhsp++ == '\0') /* last ch not RE end, help! */ X return(BAD); X} X Xstatic char *recomp(expbuf, redelim) /* uses cp, bcount */ X/* compile a regular expression to internal form */ Xchar *expbuf; /* place to compile it to */ Xchar redelim; /* RE end-marker to look for */ X{ X register char *ep = expbuf; /* current-compiled-char pointer */ X register char *sp = cp; /* source-character ptr */ X register int c; /* current-character pointer */ X char negclass; /* all-but flag */ X char *lastep; /* ptr to last expr compiled */ X char *svclass; /* start of current char class */ X char brnest[MAXTAGS]; /* bracket-nesting array */ X char *brnestp; /* ptr to current bracket-nest */ X char *pp; /* scratch pointer */ X int classct; /* class element count */ X int tags; /* # of closed tags */ X X if (*cp == redelim) /* if first char is RE endmarker */ X return(cp++, expbuf); /* leave existing RE unchanged */ X X lastep = NULL; /* there's no previous RE */ X brnestp = brnest; /* initialize ptr to brnest array */ X tags = bcount = 0; /* initialize counters */ X X if (*ep++ = (*sp == '^')) /* check for start-of-line syntax */ X sp++; X X for (;;) X { X if (ep >= expbuf + RELIMIT) /* match is too large */ X return(cp = sp, BAD); X if ((c = *sp++) == redelim) /* found the end of the RE */ X { X cp = sp; X if (brnestp != brnest) /* \(, \) unbalanced */ X return(BAD); X *ep++ = CEOF; /* write end-of-pattern mark */ X return(ep); /* return ptr to compiled RE */ X } X if ((c != '*') && (c != '+')) /* if we're a postfix op */ X lastep = ep; /* get ready to match last */ X X switch (c) X { X case '\\': X if ((c = *sp++) == '(') /* start tagged section */ X { X if (bcount >= MAXTAGS) X return(cp = sp, BAD); X *brnestp++ = bcount; /* update tag stack */ X *ep++ = CBRA; /* enter tag-start */ X *ep++ = bcount++; /* bump tag count */ X continue; X } X else if (c == ')') /* end tagged section */ X { X if (brnestp <= brnest) /* extra \) */ X return(cp = sp, BAD); X *ep++ = CKET; /* enter end-of-tag */ X *ep++ = *--brnestp; /* pop tag stack */ X tags++; /* count closed tags */ X continue; X } X else if (c >= '1' && c <= '9') /* tag use */ X { X if ((c -= '1') >= tags) /* too few */ X return(BAD); X *ep++ = CBACK; /* enter tag mark */ X *ep++ = c; /* and the number */ X continue; X } X else if (c == '\n') /* escaped newline no good */ X return(cp = sp, BAD); X else if (c == 'n') /* match a newline */ X c = '\n'; X else if (c == 't') /* match a tab */ X c = '\t'; X goto defchar; /* else match \c */ X X case '\0': /* ignore nuls */ X continue; X X case '\n': /* trailing pattern delimiter is missing */ X return(cp = sp, BAD); X X case '.': /* match any char except newline */ X *ep++ = CDOT; X continue; X X case '+': /* 1 to n repeats of previous pattern */ X if (lastep == NULL) /* if + not first on line */ X goto defchar; /* match a literal + */ X if (*lastep == CKET) /* can't iterate a tag */ X return(cp = sp, BAD); X pp = ep; /* else save old ep */ X while (lastep < pp) /* so we can blt the pattern */ X *ep++ = *lastep++; X *lastep |= STAR; /* flag the copy */ X continue; X X case '*': /* 0..n repeats of previous pattern */ X if (lastep == NULL) /* if * isn't first on line */ X goto defchar; /* match a literal * */ X if (*lastep == CKET) /* can't iterate a tag */ X return(cp = sp, BAD); X *lastep |= STAR; /* flag previous pattern */ X continue; X X case '$': /* match only end-of-line */ X if (*sp != redelim) /* if we're not at end of RE */ X goto defchar; /* match a literal $ */ X *ep++ = CDOL; /* insert end-symbol mark */ X continue; X X case '[': /* begin character set pattern */ X if (ep + 17 >= expbuf + RELIMIT) X ABORT(REITL); X *ep++ = CCL; /* insert class mark */ X if (negclass = ((c = *sp++) == '^')) X c = *sp++; X svclass = sp; /* save ptr to class start */ X do { X if (c == '\0') ABORT(CGMSG); X X /* handle character ranges */ X if (c == '-' && sp > svclass && *sp != ']') X for (c = sp[-2]; c < *sp; c++) X ep[c >> 3] |= bits[c & 7]; X X /* handle escape sequences in sets */ X if (c == '\\') X if ((c = *sp++) == 'n') X c = '\n'; X else if (c == 't') X c = '\t'; X X /* enter (possibly translated) char in set */ X ep[c >> 3] |= bits[c & 7]; X } while X ((c = *sp++) != ']'); X X /* invert the bitmask if all-but was specified */ X if (negclass) X for(classct = 0; classct < 16; classct++) X ep[classct] ^= 0xFF; X ep[0] &= 0xFE; /* never match ASCII 0 */ X ep += 16; /* advance ep past set mask */ X continue; X X defchar: /* match literal character */ X default: /* which is what we'd do by default */ X *ep++ = CCHR; /* insert character mark */ X *ep++ = c; X } X } X} X Xstatic int cmdline(cbuf) /* uses eflag, eargc, cmdf */ X/* read next command from -e argument or command file */ Xregister char *cbuf; X{ X register int inc; /* not char because must hold EOF */ X X cbuf--; /* so pre-increment points us at cbuf */ X X /* e command flag is on */ X if (eflag) X { X register char *p; /* ptr to current -e argument */ X static char *savep; /* saves previous value of p */ X X if (eflag > 0) /* there are pending -e arguments */ X { X eflag = -1; X if (eargc-- <= 0) X exit(2); /* if no arguments, barf */ X X /* else transcribe next e argument into cbuf */ X p = *++eargv; X while(*++cbuf = *p++) X if (*cbuf == '\\') X { X if ((*++cbuf = *p++) == '\0') X return(savep = NULL, -1); X else X continue; X } X else if (*cbuf == '\n') /* end of 1 cmd line */ X { X *cbuf = '\0'; X return(savep = p, 1); X /* we'll be back for the rest... */ X } X X /* found end-of-string; can advance to next argument */ X return(savep = NULL, 1); X } X X if ((p = savep) == NULL) X return(-1); X X while(*++cbuf = *p++) X if (*cbuf == '\\') X { X if ((*++cbuf = *p++) == '0') X return(savep = NULL, -1); X else X continue; X } X else if (*cbuf == '\n') X { X *cbuf = '\0'; X return(savep = p, 1); X } X X return(savep = NULL, 1); X } X X /* if no -e flag read from command file descriptor */ X while((inc = getc(cmdf)) != EOF) /* get next char */ X if ((*++cbuf = inc) == '\\') /* if it's escape */ X *++cbuf = inc = getc(cmdf); /* get next char */ X else if (*cbuf == '\n') /* end on newline */ X return(*cbuf = '\0', 1); /* cap the string */ X X return(*++cbuf = '\0', -1); /* end-of-file, no more chars */ X} X Xstatic char *address(expbuf) /* uses cp, linenum */ X/* expand an address at *cp... into expbuf, return ptr at following char */ Xregister char *expbuf; X{ X static int numl = 0; /* current ind in addr-number table */ X register char *rcp; /* temp compile ptr for forwd look */ X long lno; /* computed value of numeric address */ X X if (*cp == '$') /* end-of-source address */ X { X *expbuf++ = CEND; /* write symbolic end address */ X *expbuf++ = CEOF; /* and the end-of-address mark (!) */ X cp++; /* go to next source character */ X return(expbuf); /* we're done */ X } X if (*cp == '/') /* start of regular-expression match */ X return(recomp(expbuf, *cp++)); /* compile the RE */ X X rcp = cp; lno = 0; /* now handle a numeric address */ X while(*rcp >= '0' && *rcp <= '9') /* collect digits */ X lno = lno*10 + *rcp++ - '0'; /* compute their value */ X X if (rcp > cp) /* if we caught a number... */ X { X *expbuf++ = CLNUM; /* put a numeric-address marker */ X *expbuf++ = numl; /* and the address table index */ X linenum[numl++] = lno; /* and set the table entry */ X if (numl >= MAXLINES) /* oh-oh, address table overflow */ X ABORT(TMLNR); /* abort with error message */ X *expbuf++ = CEOF; /* write the end-of-address marker */ X cp = rcp; /* point compile past the address */ X return(expbuf); /* we're done */ X } X X return(NULL); /* no legal address was found */ X} X Xstatic char *gettext(txp) /* uses global cp */ X/* accept multiline input from *cp..., discarding leading whitespace */ Xregister char *txp; /* where to put the text */ X{ X register char *p = cp; /* this is for speed */ X X SKIPWS(p); /* discard whitespace */ X do { X if ((*txp = *p++) == '\\') /* handle escapes */ X *txp = *p++; X if (*txp == '\0') /* we're at end of input */ X return(cp = --p, ++txp); X else if (*txp == '\n') /* also SKIPWS after newline */ X SKIPWS(p); X } while X (txp++); /* keep going till we find that nul */ X} X Xstatic label *search(ptr) /* uses global lablst */ X/* find the label matching *ptr, return NULL if none */ Xregister label *ptr; X{ X register label *rp; X for(rp = lablst; rp < ptr; rp++) X if (strcmp(rp->name, ptr->name) == 0) X return(rp); X return(NULL); X} X Xstatic void resolve() /* uses global lablst */ X/* write label links into the compiled-command space */ X{ X register label *lptr; X register sedcmd *rptr, *trptr; X X /* loop through the label table */ X for(lptr = lablst; lptr < lab; lptr++) X if (lptr->address == NULL) /* barf if not defined */ X { X fprintf(stderr, ULABL, lptr->name); X exit(2); X } X else if (lptr->last) /* if last is non-null */ X { X rptr = lptr->last; /* chase it */ X while(trptr = rptr->u.link) /* resolve refs */ X { X rptr->u.link = lptr->address; X rptr = trptr; X } X rptr->u.link = lptr->address; X } X} X Xstatic char *ycomp(ep, delim) X/* compile a y (transliterate) command */ Xregister char *ep; /* where to compile to */ Xchar delim; /* end delimiter to look for */ X{ X register char *tp, *sp; X register int c; X X /* scan the 'from' section for invalid chars */ X for(sp = tp = cp; *tp != delim; tp++) X { X if (*tp == '\\') X tp++; X if ((*tp == '\n') || (*tp == '\0')) X return(BAD); X } X tp++; /* tp now points at first char of 'to' section */ X X /* now rescan the 'from' section */ X while((c = *sp++ & 0x7F) != delim) X { X if (c == '\\' && *sp == 'n') X { X sp++; X c = '\n'; X } X if ((ep[c] = *tp++) == '\\' && *tp == 'n') X { X ep[c] = '\n'; X tp++; X } X if ((ep[c] == delim) || (ep[c] == '\0')) X return(BAD); X } X X if (*tp != delim) /* 'to', 'from' parts have unequal lengths */ X return(BAD); X X cp = ++tp; /* point compile ptr past translit */ X X for(c = 0; c < 128; c++) /* fill in self-map entries in table */ X if (ep[c] == 0) X ep[c] = c; X X return(ep + 0x80); /* return first free location past table end */ X} X END_OF_sedcomp.c if test 37219 -ne `wc -c <sedcomp.c`; then echo shar: \"sedcomp.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f sedexec.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"sedexec.c\" else echo shar: Extracting \"sedexec.c\" \(28610 characters\) sed "s/^X//" >sedexec.c <<'END_OF_sedexec.c' X#ifdef foo X #include "compiler.h" X #ifdef LATTICE X #define void int X #endif X#endif X X#include "debug.h" X/* Xsedexec.c -- execute compiled form of stream editor commands X X The single entry point of this module is the function execute(). It Xmay take a string argument (the name of a file to be used as text) or Xthe argument NULL which tells it to filter standard input. It executes Xthe compiled commands in cmds[] on each line in turn. X The function command() does most of the work. Match() and advance() Xare used for matching text against precompiled regular expressions and Xdosub() does right-hand-side substitution. Getline() does text input; Xreadout() and memcmp() are output and string-comparison utilities. X X==== Written for the GNU operating system by Eric S. Raymond ==== X*/ X X#include <stdio.h> /* {f}puts, {f}printf, getc/putc, f{re}open, fclose */ X#include <ctype.h> /* for isprint(), isdigit(), toascii() macros */ X#include "sed.h" /* command type structures & miscellaneous constants */ X Xextern char *strcpy(); /* used in dosub */ X X/***** shared variables imported from the main ******/ X X/* main data areas */ Xextern char linebuf[]; /* current-line buffer */ Xextern sedcmd cmds[]; /* hold compiled commands */ Xextern long linenum[]; /* numeric-addresses table */ X X/* miscellaneous shared variables */ Xextern int nflag; /* -n option flag */ Xextern int eargc; /* scratch copy of argument count */ Xextern sedcmd *pending; /* ptr to command waiting to be executed */ Xextern char bits[]; /* the bits table */ X X/***** end of imported stuff *****/ X X#define MAXHOLD MAXBUF /* size of the hold space */ X#define GENSIZ BUFSIZ /* maximum genbuf size */ X X#define TRUE 1 X#define FALSE 0 X Xstatic char LTLMSG[] = "sed: line too long\n"; X Xstatic char *spend; /* current end-of-line-buffer pointer */ Xstatic long lnum = 0L; /* current source line number */ X X/* append buffer maintenance */ Xstatic sedcmd *appends[MAXAPPENDS]; /* array of ptrs to a,i,c commands */ Xstatic sedcmd **aptr = appends; /* ptr to current append */ X X/* genbuf and its pointers */ Xstatic char genbuf[GENSIZ]; Xstatic char *lcomend = genbuf + GENSIZ; Xstatic char *loc1; Xstatic char *loc2; Xstatic char *locs; X X/* command-logic flags */ Xstatic int lastline; /* do-line flag */ Xstatic int jump; /* jump to cmd's link address if set */ Xstatic int delete; /* delete command flag */ X X/* tagged-pattern tracking */ Xstatic char *bracend[MAXTAGS]; /* tagged pattern start pointers */ Xstatic char *brastart[MAXTAGS]; /* tagged pattern end pointers */ X X Xvoid execute(file) X/* execute the compiled commands in cmds[] on a file */ Xchar *file; /* name of text source file to be filtered */ X{ X register char *p1, *p2; /* dummy copy ptrs */ X register sedcmd *ipc; /* ptr to current command */ X char *execp; /* ptr to source */ X char *getline(); /* input-getting functions */ X void command(), readout(); X XPASS("execute(): entry"); X X if (file != NULL) /* filter text from a named file */ X if (freopen(file, "r", stdin) == NULL) X fprintf(stderr, "sed: can't open %s\n", file); XPASS("execute(): reopen"); X X if (pending) /* there's a command waiting */ X { X ipc = pending; /* it will be first executed */ X pending = FALSE; /* turn off the waiting flag */ X goto doit; /* go to execute it immediately */ X } X X /* here's the main command-execution loop */ X for(;;) X { XPASS("execute(): main loop entry"); X X /* get next line to filter */ X if ((execp = getline(linebuf)) == BAD) X return; XPASS("execute(): getline"); X spend = execp; X X /* loop through compiled commands, executing them */ X for(ipc = cmds; ipc->command; ) X { XPASS("execute(): command loop entry"); X /* all no-address commands are selected */ X if (ipc->addr1 && !selected(ipc)) X { X ipc++; X continue; X } X doit: XPASS("execute(): doit"); X command(ipc); /* execute the command pointed at */ XPASS("execute(): command"); X X if (delete) /* if delete flag is set */ X break; /* don't exec rest of compiled cmds */ X X if (jump) /* if jump set, follow cmd's link */ X { X jump = FALSE; X if ((ipc = ipc->u.link) == 0) X { X ipc = cmds; X break; X } X } X else /* normal goto next command */ X ipc++; XPASS("execute(): end command loop"); X } X /* we've now done all modification commands on the line */ X X /* here's where the transformed line is output */ XPASS("execute(): output"); X if (!nflag && !delete) X { X for(p1 = linebuf; p1 < spend; p1++) X putc(*p1, stdout); X putc('\n', stdout); X } X X /* if we've been set up for append, emit the text from it */ X if (aptr > appends) X readout(); X X delete = FALSE; /* clear delete flag; about to get next cmd */ XPASS("execute(): end main loop"); X } XPASS("execute(): end execute"); X} X Xstatic int selected(ipc) X/* is current command selected */ Xsedcmd *ipc; X{ X register char *p1 = ipc->addr1; /* point p1 at first address */ X register char *p2 = ipc->addr2; /* and p2 at second */ X char c; X X if (ipc->flags.inrange) X { X if (*p2 == CEND) X p1 = NULL; X else if (*p2 == CLNUM) X { X c = p2[1]; X if (lnum > linenum[c]) X { X ipc->flags.inrange = FALSE; X if (ipc->flags.allbut) X return(TRUE); X ipc++; X return(FALSE); X } X if (lnum == linenum[c]) X ipc->flags.inrange = FALSE; X } X else if (match(p2, 0)) X ipc->flags.inrange = FALSE; X } X else if (*p1 == CEND) X { X if (!lastline) X { X if (ipc->flags.allbut) X return(TRUE); X ipc++; X return(FALSE); X } X } X else if (*p1 == CLNUM) X { X c = p1[1]; X if (lnum != linenum[c]) X { X if (ipc->flags.allbut) X return(TRUE); X ipc++; X return(FALSE); X } X if (p2) X ipc->flags.inrange = TRUE; X } X else if (match(p1, 0)) X { X if (p2) X ipc->flags.inrange = TRUE; X } X else X { X if (ipc->flags.allbut) X return(TRUE); X ipc++; X return(FALSE); X } X return(!ipc->flags.allbut); X} X Xstatic int match(expbuf, gf) /* uses genbuf */ X/* match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */ Xchar *expbuf; X{ X register char *p1, *p2, c; X X if (gf) X { X if (*expbuf) X return(FALSE); X p1 = linebuf; p2 = genbuf; X while (*p1++ = *p2++); X locs = p1 = loc2; X } X else X { X p1 = linebuf; X locs = FALSE; X } X X p2 = expbuf; X if (*p2++) X { X loc1 = p1; X if(*p2 == CCHR && p2[1] != *p1) /* 1st char is wrong */ X return(FALSE); /* so fail */ X return(advance(p1, p2)); /* else try to match rest */ X } X X /* quick check for 1st character if it's literal */ X if (*p2 == CCHR) X { X c = p2[1]; /* pull out character to search for */ X do { X if (*p1 != c) X continue; /* scan the source string */ X if (advance(p1, p2)) /* found it, match the rest */ X return(loc1 = p1, 1); X } while X (*p1++); X return(FALSE); /* didn't find that first char */ X } X X /* else try for unanchored match of the pattern */ X do { X if (advance(p1, p2)) X return(loc1 = p1, 1); X } while X (*p1++); X X /* if got here, didn't match either way */ X return(FALSE); X} X Xstatic int advance(lp, ep) X/* attempt to advance match pointer by one pattern element */ Xregister char *lp; /* source (linebuf) ptr */ Xregister char *ep; /* regular expression element ptr */ X{ X register char *curlp; /* save ptr for closures */ X char c; /* scratch character holder */ X char *bbeg; X int ct; X X for (;;) X switch (*ep++) X { X case CCHR: /* literal character */ X if (*ep++ == *lp++) /* if chars are equal */ X continue; /* matched */ X return(FALSE); /* else return false */ X X case CDOT: /* anything but newline */ X if (*lp++) /* first NUL is at EOL */ X continue; /* keep going if didn't find */ X return(FALSE); /* else return false */ X X case CNL: /* start-of-line */ X case CDOL: /* end-of-line */ X if (*lp == 0) /* found that first NUL? */ X continue; /* yes, keep going */ X return(FALSE); /* else return false */ X X case CEOF: /* end-of-address mark */ X loc2 = lp; /* set second loc */ X return(TRUE); /* return true */ X X case CCL: /* a closure */ X c = *lp++ & 0177; X if (ep[c>>3] & bits[c & 07]) /* is char in set? */ X { X ep += 16; /* then skip rest of bitmask */ X continue; /* and keep going */ X } X return(FALSE); /* else return false */ X X case CBRA: /* start of tagged pattern */ X brastart[*ep++] = lp; /* mark it */ X continue; /* and go */ X X case CKET: /* end of tagged pattern */ X bracend[*ep++] = lp; /* mark it */ X continue; /* and go */ X X case CBACK: X bbeg = brastart[*ep]; X ct = bracend[*ep++] - bbeg; X X if (memcmp(bbeg, lp, ct)) X { X lp += ct; X continue; X } X return(FALSE); X X case CBACK|STAR: X bbeg = brastart[*ep]; X ct = bracend[*ep++] - bbeg; X curlp = lp; X while(memcmp(bbeg, lp, ct)) X lp += ct; X X while(lp >= curlp) X { X if (advance(lp, ep)) X return(TRUE); X lp -= ct; X } X return(FALSE); X X X case CDOT|STAR: /* match .* */ X curlp = lp; /* save closure start loc */ X while (*lp++); /* match anything */ X goto star; /* now look for followers */ X X case CCHR|STAR: /* match <literal char>* */ X curlp = lp; /* save closure start loc */ X while (*lp++ == *ep); /* match many of that char */ X ep++; /* to start of next element */ X goto star; /* match it and followers */ X X case CCL|STAR: /* match [...]* */ X curlp = lp; /* save closure start loc */ X do { X c = *lp++ & 0x7F; /* match any in set */ X } while X (ep[c>>3] & bits[c & 07]); X ep += 16; /* skip past the set */ X goto star; /* match followers */ X X star: /* the recursion part of a * or + match */ X if (--lp == curlp) /* 0 matches */ X continue; X X if (*ep == CCHR) X { X c = ep[1]; X do { X if (*lp != c) X continue; X if (advance(lp, ep)) X return(TRUE); X } while X (lp-- > curlp); X return(FALSE); X } X X if (*ep == CBACK) X { X c = *(brastart[ep[1]]); X do { X if (*lp != c) X continue; X if (advance(lp, ep)) X return(TRUE); X } while X (lp-- > curlp); X return(FALSE); X } X X do { X if (lp == locs) X break; X if (advance(lp, ep)) X return(TRUE); X } while X (lp-- > curlp); X return(FALSE); X X default: X fprintf(stderr, "sed: RE error, %o\n", *--ep); X } X} X Xstatic int substitute(ipc) X/* perform s command */ Xsedcmd *ipc; /* ptr to s command struct */ X{ X void dosub(); /* for if we find a match */ X X if (match(ipc->u.lhs, 0)) /* if no match */ X dosub(ipc->rhs); /* perform it once */ X else X return(FALSE); /* command fails */ X X if (ipc->flags.global) /* if global flag enabled */ X while(*loc2) /* cycle through possibles */ X if (match(ipc->u.lhs, 1)) /* found another */ X dosub(ipc->rhs); /* so substitute */ X else /* otherwise, */ X break; /* we're done */ X return(TRUE); /* we succeeded */ X} X Xstatic void dosub(rhsbuf) /* uses linebuf, genbuf, spend */ X/* generate substituted right-hand side (of s command) */ Xchar *rhsbuf; /* where to put the result */ X{ X register char *lp, *sp, *rp; X int c; X char *place(); X X /* copy linebuf to genbuf up to location 1 */ X lp = linebuf; sp = genbuf; X while (lp < loc1) *sp++ = *lp++; X X for (rp = rhsbuf; c = *rp++; ) X { X if (c == '&') X { X sp = place(sp, loc1, loc2); X continue; X } X else if (c & 0200 && (c &= 0177) >= '1' && c < MAXTAGS+'1') X { X sp = place(sp, brastart[c-'1'], bracend[c-'1']); X continue; X } X *sp++ = c & 0177; X if (sp >= genbuf + MAXBUF) X fprintf(stderr, LTLMSG); X } X lp = loc2; X/* MRY loc2 = sp - genbuf + linebuf; */ X loc2 = sp - (genbuf - linebuf); X while (*sp++ = *lp++) X if (sp >= genbuf + MAXBUF) X fprintf(stderr, LTLMSG); X lp = linebuf; sp = genbuf; X while (*lp++ = *sp++); X spend = lp-1; X} X Xstatic char *place(asp, al1, al2) /* uses genbuf */ X/* place chars at *al1...*(al1 - 1) at asp... in genbuf[] */ Xregister char *asp, *al1, *al2; X{ X while (al1 < al2) X { X *asp++ = *al1++; X if (asp >= genbuf + MAXBUF) X fprintf(stderr, LTLMSG); X } X return(asp); X} X Xstatic void listto(p1, fp) X/* write a hex dump expansion of *p1... to fp */ Xregister char *p1; /* the source */ XFILE *fp; /* output stream to write to */ X{ X p1--; X while(*p1++) X if (isprint(*p1)) X putc(*p1, fp); /* pass it through */ X else X { X putc('\134', fp); /* emit a backslash */ X switch(*p1) X { X case '\10': putc('b', fp); break; /* BS */ X case '\11': putc('t', fp); break; /* TAB */ X/* \11 was \9 --MRY */ X case '\12': putc('n', fp); break; /* NL */ X case '\15': putc('r', fp); break; /* CR */ X case '\33': putc('e', fp); break; /* ESC */ X default: fprintf(fp, "%02x", *p1 & 0xFF); X } X } X putc('\n', fp); X} X Xstatic void command(ipc) X/* execute compiled command pointed at by ipc */ Xsedcmd *ipc; X{ X static int didsub; /* true if last s succeeded */ X static char holdsp[MAXHOLD]; /* the hold space */ X static char *hspend = holdsp; /* hold space end pointer */ X register char *p1, *p2, *p3; X register int i; X char *execp; X X switch(ipc->command) X { X case ACMD: /* append */ X *aptr++ = ipc; X if (aptr >= appends + MAXAPPENDS) X fprintf(stderr, X "sed: too many appends after line %ld\n", X lnum); X *aptr = 0; X break; X X case CCMD: /* change pattern space */ X delete = TRUE; X if (!ipc->flags.inrange || lastline) X printf("%s\n", ipc->u.lhs); X break; X X case DCMD: /* delete pattern space */ X delete++; X break; X X case CDCMD: /* delete a line in hold space */ X p1 = p2 = linebuf; X while(*p1 != '\n') X if (delete = (*p1++ == 0)) X return; X p1++; X while(*p2++ = *p1++) continue; X spend = p2-1; X jump++; X break; X X case EQCMD: /* show current line number */ X fprintf(stdout, "%ld\n", lnum); X break; X X case GCMD: /* copy hold space to pattern space */ X p1 = linebuf; p2 = holdsp; while(*p1++ = *p2++); X spend = p1-1; X break; X X case CGCMD: /* append hold space to pattern space */ X *spend++ = '\n'; X p1 = spend; p2 = holdsp; X while(*p1++ = *p2++) X if (p1 >= linebuf + MAXBUF) X break; X spend = p1-1; X break; X X case HCMD: /* copy pattern space to hold space */ X p1 = holdsp; p2 = linebuf; while(*p1++ = *p2++); X hspend = p1-1; X break; X X case CHCMD: /* append pattern space to hold space */ X *hspend++ = '\n'; X p1 = hspend; p2 = linebuf; X while(*p1++ = *p2++) X if (p1 >= holdsp + MAXBUF) X break; X hspend = p1-1; X break; X X case ICMD: /* insert text */ X printf("%s\n", ipc->u.lhs); X break; X X case BCMD: /* branch to label */ X jump = TRUE; X break; X X case LCMD: /* list text */ X listto(linebuf, (ipc->fout != NULL)?ipc->fout:stdout); break; X X case NCMD: /* read next line into pattern space */ X if (!nflag) X puts(linebuf); /* flush out the current line */ X if (aptr > appends) X readout(); /* do pending a, r commands */ X if ((execp = getline(linebuf)) == BAD) X { X pending = ipc; X delete = TRUE; X break; X } X spend = execp; X break; X X case CNCMD: /* append next line to pattern space */ X if (aptr > appends) X readout(); X *spend++ = '\n'; X if ((execp = getline(spend)) == BAD) X { X pending = ipc; X delete = TRUE; X break; X } X spend = execp; X break; X X case PCMD: /* print pattern space */ X puts(linebuf); X break; X X case CPCMD: /* print one line from pattern space */ X cpcom: /* so s command can jump here */ X for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; ) X putc(*p1++, stdout); X putc('\n', stdout); X break; X X case QCMD: /* quit the stream editor */ X if (!nflag) X puts(linebuf); /* flush out the current line */ X if (aptr > appends) X readout(); /* do any pending a and r commands */ X exit(0); X X case RCMD: /* read a file into the stream */ X *aptr++ = ipc; X if (aptr >= appends + MAXAPPENDS) X fprintf(stderr, X "sed: too many reads after line %ld\n", X lnum); X *aptr = 0; X break; X X case SCMD: /* substitute RE */ X didsub = substitute(ipc); X if (ipc->flags.print && didsub) X if (ipc->flags.print == TRUE) X puts(linebuf); X else X goto cpcom; X if (didsub && ipc->fout) X fprintf(ipc->fout, "%s\n", linebuf); X break; X X case TCMD: /* branch on last s successful */ X case CTCMD: /* branch on last s failed */ X if (didsub == (ipc->command == CTCMD)) X break; /* no branch if last s failed, else */ X didsub = FALSE; X jump = TRUE; /* set up to jump to assoc'd label */ X break; X X case CWCMD: /* write one line from pattern space */ X for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; ) X putc(*p1++, ipc->fout); X putc('\n', ipc->fout); X break; X X case WCMD: /* write pattern space to file */ X fprintf(ipc->fout, "%s\n", linebuf); X break; X X case XCMD: /* exchange pattern and hold spaces */ X p1 = linebuf; p2 = genbuf; while(*p2++ = *p1++) continue; X p1 = holdsp; p2 = linebuf; while(*p2++ = *p1++) continue; X spend = p2 - 1; X p1 = genbuf; p2 = holdsp; while(*p2++ = *p1++) continue; X hspend = p2 - 1; X break; X X case YCMD: X p1 = linebuf; p2 = ipc->u.lhs; X while(*p1 = p2[*p1]) X p1++; X break; X } X} X Xstatic char *getline(buf) X/* get next line of text to be filtered */ Xregister char *buf; /* where to send the input */ X{ X if (gets(buf) != NULL) X { X lnum++; /* note that we got another line */ X while(*buf++); /* find the end of the input */ X return(--buf); /* return ptr to terminating null */ X } X else X { X if (eargc == 0) /* if no more args */ X lastline = TRUE; /* set a flag */ X return(BAD); X } X} X Xstatic int memcmp(a, b, count) X/* return TRUE if *a... == *b... for count chars, FALSE otherwise */ Xregister char *a, *b; X{ X while(count--) /* look at count characters */ X if (*a++ != *b++) /* if any are nonequal */ X return(FALSE); /* return FALSE for false */ X return(TRUE); /* compare succeeded */ X} X Xstatic void readout() X/* write file indicated by r command to output */ X{ X register char *p1; /* character-fetching dummy */ X register int t; /* hold input char or EOF */ X FILE *fi; /* ptr to file to be read */ X X aptr = appends - 1; /* arrange for pre-increment to work right */ X while(*++aptr) X if ((*aptr)->command == ACMD) /* process "a" cmd */ X printf("%s\n", (*aptr)->u.lhs); X else /* process "r" cmd */ X { X if ((fi = fopen((*aptr)->u.lhs, "r")) == NULL) X continue; X while((t = getc(fi)) != EOF) X putc((char) t, stdout); X fclose(fi); X } X aptr = appends; /* reset the append ptr */ X *aptr = 0; X} X X/* sedexec.c ends here */ X END_OF_sedexec.c if test 28610 -ne `wc -c <sedexec.c`; then echo shar: \"sedexec.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f sedpatch -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"sedpatch\" else echo shar: Extracting \"sedpatch\" \(2884 characters\) sed "s/^X//" >sedpatch <<'END_OF_sedpatch' XFrom eutwc1!wzvpc1!news Thu Apr 14 22:39:50 1988 XReturn-Path: <eutwc1!wzvpc1!news> XReceived: by tuewsa.lso.uucp (3.2/SMI-3.2) X id AA08678; Thu, 14 Apr 88 22:39:49 +0200 XDate: Thu, 14 Apr 88 22:39:49 +0200 XFrom: eutwc1!wzvpc1!news (Wietse Venema) XMessage-Id: <8804142039.AA08678@tuewsa.lso.uucp> XTo: eutwc1!tuewsa!wswietse XSubject: sedpatch XStatus: R X XThe following patches to the sed program (posted sept 1987?) solve Xthe problems I stumbled upon. The program now seems to work fine Xon the Sun 3/160 and an AT running System-V. X XFor real UNIX compatibility you should remove the support for the + Xoperator in regular expressions... X X*** sedcomp.c.orig Fri Apr 15 11:27:22 1988 X--- sedcomp.c Fri Apr 15 13:11:43 1988 X*************** X*** 538,545 **** X c = '\n'; X else if (c == 't') /* match a tab */ X c = '\t'; X! else X! goto defchar; /* else match \c */ X X case '\0': /* ignore nuls */ X continue; X--- 538,544 ---- X c = '\n'; X else if (c == 't') /* match a tab */ X c = '\t'; X! goto defchar; /* else match \c */ X X case '\0': /* ignore nuls */ X continue; X*************** X*** 786,792 **** X register char *ep; /* where to compile to */ X char delim; /* end delimiter to look for */ X { X! register char c, *tp, *sp; X X /* scan the 'from' section for invalid chars */ X for(sp = tp = cp; *tp != delim; tp++) X--- 785,792 ---- X register char *ep; /* where to compile to */ X char delim; /* end delimiter to look for */ X { X! register char *tp, *sp; X! register int c; X X /* scan the 'from' section for invalid chars */ X for(sp = tp = cp; *tp != delim; tp++) X*** sedexec.c.orig Fri Apr 15 11:27:25 1988 X--- sedexec.c Fri Apr 15 14:54:31 1988 X*************** X*** 43,49 **** X /***** end of imported stuff *****/ X X #define MAXHOLD MAXBUF /* size of the hold space */ X! #define GENSIZ 71 /* maximum genbuf size */ X X #define TRUE 1 X #define FALSE 0 X--- 43,49 ---- X /***** end of imported stuff *****/ X X #define MAXHOLD MAXBUF /* size of the hold space */ X! #define GENSIZ BUFSIZ /* maximum genbuf size */ X X #define TRUE 1 X #define FALSE 0 X*************** X*** 225,230 **** X--- 225,231 ---- X ipc++; X return(FALSE); X } X+ return(!ipc->flags.allbut); X } X X static int match(expbuf, gf) /* uses genbuf */ END_OF_sedpatch if test 2884 -ne `wc -c <sedpatch`; then echo shar: \"sedpatch\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0 -- uucp: mcvax!eutrc3!wswietse | Eindhoven University of Technology bitnet: wswietse@heithe5 | Dept. of Mathematics and Computing Science surf: tuerc5::wswietse | Eindhoven, The Netherlands.