[comp.os.minix] SED

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.