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.