Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "sed.h"

struct label    *labtab = ltab;
char    CGMES[] = "sed: Command garbled: %s\n";
char    TMMES[] = "sed: Too much text: %s\n";
char    LTL[]   = "sed: Label too long: %s\n";
char    AD0MES[]        = "sed: No addresses allowed: %s\n";
char    AD1MES[]        = "sed: Only one address allowed: %s\n";
uchar   bittab[]  = {
                1,
                2,
                4,
                8,
                16,
                32,
                64,
                128
        };

void
main(int argc, char **argv)
{

        eargc = argc;
        eargv = (uchar**)argv;

        badp = &bad;
        aptr = abuf;
        hspend = holdsp;
        lab = labtab + 1;       /* 0 reserved for end-pointer */
        rep = ptrspace;
        rep->r1.ad1 = respace;
        lbend = &linebuf[LBSIZE];
        hend = &holdsp[LBSIZE];
        lcomend = &genbuf[64];
        ptrend = &ptrspace[PTRSIZE];
        reend = &respace[RESIZE];
        labend = &labtab[LABSIZE];
        lnum = 0;
        pending = 0;
        depth = 0;
        spend = linebuf;
        hspend = holdsp;
        fcode[0] = stdout;
        nfiles = 1;
        lastre = NULL;

        if(eargc == 1)
                exit(0);


        while (--eargc > 0 && (++eargv)[0][0] == '-')
                switch (eargv[0][1]) {

                case 'n':
                        nflag++;
                        continue;

                case 'f':
                        if(eargc-- <= 0)        exit(2);

                        if((fin = fopen((char*)(*++eargv), "r")) == NULL) {
                                fprintf(stderr, "sed: Cannot open pattern-file: %s\n", *eargv);
                                exit(2);
                        }

                        fcomp();
                        fclose(fin);
                        continue;

                case 'e':
                        eflag++;
                        fcomp();
                        eflag = 0;
                        continue;

                case 'g':
                        gflag++;
                        continue;

                default:
                        fprintf(stderr, "sed: Unknown flag: %c\n", eargv[0][1]);
                        continue;
                }


        if(compfl == 0) {
                eargv--;
                eargc++;
                eflag++;
                fcomp();
                eargv++;
                eargc--;
                eflag = 0;
        }

        if(depth) {
                fprintf(stderr, "sed: Too many {'s\n");
                exit(2);
        }

        labtab->address = rep;

        dechain();

/*      abort();        /*DEBUG*/

        if(eargc <= 0)
                execute((uchar *)NULL);
        else while(--eargc >= 0) {
                execute(*eargv++);
        }
        fclose(stdout);
        exit(0);
}
void
fcomp(void)
{

        uchar   *p, *op, *tp;
    uchar *address(uchar*);
        union reptr     *pt, *pt1;
        int     i;
        struct label    *lpt;

        compfl = 1;
        op = lastre;

        if(rline(linebuf) < 0) {
                lastre = op;
                return;
        }
        if(*linebuf == '#') {
                if(linebuf[1] == 'n')
                        nflag = 1;
        }
        else {
                cp = linebuf;
                goto comploop;
        }

        for(;;) {
                if(rline(linebuf) < 0)  break;

                cp = linebuf;

comploop:
/*      fprintf(stdout, "cp: %s\n", cp);        /*DEBUG*/
                while(*cp == ' ' || *cp == '\t')        cp++;
                if(*cp == '\0' || *cp == '#')           continue;
                if(*cp == ';') {
                        cp++;
                        goto comploop;
                }

                p = address(rep->r1.ad1);
                if(p == badp) {
                        fprintf(stderr, CGMES, linebuf);
                        exit(2);
                }

                if(p == 0) {
                        p = rep->r1.ad1;
                        rep->r1.ad1 = 0;
                } else {
                        if(p == rep->r1.ad1) {
                                if(op)
                                        rep->r1.ad1 = op;
                                else {
                                        fprintf(stderr, "sed: First RE may not be null\n");
                                        exit(2);
                                }
                        }
                        if(*rep->r1.ad1 != CLNUM && *rep->r1.ad1 != CEND)
                                op = rep->r1.ad1;
                        if(*cp == ',' || *cp == ';') {
                                cp++;
                                if((rep->r1.ad2 = p) > reend) {
                                        fprintf(stderr, TMMES, linebuf);
                                        exit(2);
                                }
                                p = address(rep->r1.ad2);
                                if(p == badp || p == 0) {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                if(p == rep->r1.ad2)
                                        rep->r1.ad2 = op;
                                else{
                                if(*rep->r1.ad2 != CLNUM && *rep->r1.ad2 != CEND)
                                        op = rep->r1.ad2;
                                }

                        } else
                                rep->r1.ad2 = 0;
                }

                if(p > reend) {
                        fprintf(stderr, "sed: Too much text: %s\n", linebuf);
                        exit(2);
                }

                while(*cp == ' ' || *cp == '\t')        cp++;

swit:
                switch(*cp++) {

                        default:
/*fprintf(stderr, "cp = %d; *cp = %o\n", cp - linebuf, *cp);*/
                                fprintf(stderr, "sed: Unrecognized command: %s\n", linebuf);
                                exit(2);

                        case '!':
                                rep->r1.negfl = 1;
                                goto swit;

                        case '{':
                                rep->r1.command = BCOM;
                                rep->r1.negfl = !(rep->r1.negfl);
                                cmpend[depth++] = &rep->r2.lb1;
                                if(++rep >= ptrend) {
                                        fprintf(stderr, "sed: Too many commands: %s\n", linebuf);
                                        exit(2);
                                }
                                rep->r1.ad1 = p;
                                if(*cp == '\0') continue;

                                goto comploop;

                        case '}':
                                if(rep->r1.ad1) {
                                        fprintf(stderr, AD0MES, linebuf);
                                        exit(2);
                                }

                                if(--depth < 0) {
                                        fprintf(stderr, "sed: Too many }'s\n");
                                        exit(2);
                                }
                                *cmpend[depth] = rep;

                                rep->r1.ad1 = p;
                                if(*cp == 0)    continue;
                                goto comploop;

                        case '=':
                                rep->r1.command = EQCOM;
                                if(rep->r1.ad2) {
                                        fprintf(stderr, AD1MES, linebuf);
                                        exit(2);
                                }
                                break;

                        case ':':
                                if(rep->r1.ad1) {
                                        fprintf(stderr, AD0MES, linebuf);
                                        exit(2);
                                }

                                while(*cp++ == ' ');
                                cp--;


                                tp = lab->asc;
                                while((*tp = *cp++) && *tp != ';')
                                        if(++tp >= &(lab->asc[8])) {
                                                fprintf(stderr, LTL, linebuf);
                                                exit(2);
                                        }
                                *tp = '\0';
                                if(*lab->asc == 0) {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }

                                if(lpt = search(lab)) {
                                        if(lpt->address) {
                                                fprintf(stderr, "sed: Duplicate labels: %s\n", linebuf);
                                                exit(2);
                                        }
                                } else {
                                        lab->chain = 0;
                                        lpt = lab;
                                        if(++lab >= labend) {
                                                fprintf(stderr, "sed: Too many labels: %s\n", linebuf);
                                                exit(2);
                                        }
                                }
                                lpt->address = rep;
                                rep->r1.ad1 = p;

                                continue;

                        case 'a':
                                rep->r1.command = ACOM;
                                if(rep->r1.ad2) {
                                        fprintf(stderr, AD1MES, linebuf);
                                        exit(2);
                                }
                                if(*cp == '\\') cp++;
                                if(*cp++ != '\n') {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                rep->r1.re1 = p;
                                p = text(rep->r1.re1);
                                break;
                        case 'c':
                                rep->r1.command = CCOM;
                                if(*cp == '\\') cp++;
                                if(*cp++ != ('\n')) {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                rep->r1.re1 = p;
                                p = text(rep->r1.re1);
                                break;
                        case 'i':
                                rep->r1.command = ICOM;
                                if(rep->r1.ad2) {
                                        fprintf(stderr, AD1MES, linebuf);
                                        exit(2);
                                }
                                if(*cp == '\\') cp++;
                                if(*cp++ != ('\n')) {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                rep->r1.re1 = p;
                                p = text(rep->r1.re1);
                                break;

                        case 'g':
                                rep->r1.command = GCOM;
                                break;

                        case 'G':
                                rep->r1.command = CGCOM;
                                break;

                        case 'h':
                                rep->r1.command = HCOM;
                                break;

                        case 'H':
                                rep->r1.command = CHCOM;
                                break;

                        case 't':
                                rep->r1.command = TCOM;
                                goto jtcommon;

                        case 'b':
                                rep->r1.command = BCOM;
jtcommon:
                                while(*cp++ == ' ');
                                cp--;

                                if(*cp == '\0') {
                                        if(pt = labtab->chain) {
                                                while(pt1 = pt->r2.lb1)
                                                        pt = pt1;
                                                pt->r2.lb1 = rep;
                                        } else
                                                labtab->chain = rep;
                                        break;
                                }
                                tp = lab->asc;
                                while((*tp = *cp++) && *tp != ';')
                                        if(++tp >= &(lab->asc[8])) {
                                                fprintf(stderr, LTL, linebuf);
                                                exit(2);
                                        }
                                cp--;
                                *tp = '\0';
                                if(*lab->asc == 0) {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }

                                if(lpt = search(lab)) {
                                        if(lpt->address) {
                                                rep->r2.lb1 = lpt->address;
                                        } else {
                                                pt = lpt->chain;
                                                while(pt1 = pt->r2.lb1)
                                                        pt = pt1;
                                                pt->r2.lb1 = rep;
                                        }
                                } else {
                                        lab->chain = rep;
                                        lab->address = 0;
                                        if(++lab >= labend) {
                                                fprintf(stderr, "sed: Too many labels: %s\n", linebuf);
                                                exit(2);
                                        }
                                }
                                break;

                        case 'n':
                                rep->r1.command = NCOM;
                                break;

                        case 'N':
                                rep->r1.command = CNCOM;
                                break;

                        case 'p':
                                rep->r1.command = PCOM;
                                break;

                        case 'P':
                                rep->r1.command = CPCOM;
                                break;

                        case 'r':
                                rep->r1.command = RCOM;
                                if(rep->r1.ad2) {
                                        fprintf(stderr, AD1MES, linebuf);
                                        exit(2);
                                }
                                if(*cp++ != ' ') {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                rep->r1.re1 = p;
                                p = text(rep->r1.re1);
                                break;

                        case 'd':
                                rep->r1.command = DCOM;
                                break;

                        case 'D':
                                rep->r1.command = CDCOM;
                                rep->r2.lb1 = ptrspace;
                                break;

                        case 'q':
                                rep->r1.command = QCOM;
                                if(rep->r1.ad2) {
                                        fprintf(stderr, AD1MES, linebuf);
                                        exit(2);
                                }
                                break;

                        case 'l':
                                rep->r1.command = LCOM;
                                break;

                        case 's':
                                rep->r1.command = SCOM;
                                seof = *cp++;
                                rep->r1.re1 = p;
                                p = compile(rep->r1.re1);
                                if(p == badp) {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                if(p == rep->r1.re1) {
                                        if(op == NULL) {
                                                fprintf(stderr, "sed: First RE may not be null.\n");
                                                exit(2);
                                        }
                                        rep->r1.re1 = op;
                                } else {
                                        op = rep->r1.re1;
                                }

                                if((rep->r1.rhs = p) > reend) {
                                        fprintf(stderr, TMMES, linebuf);
                                        exit(2);
                                }

                                if((p = compsub(rep->r1.rhs)) == badp) {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                if(*cp == 'g') {
                                        cp++;
                                        rep->r1.gfl++;
                                } else if(gflag)
                                        rep->r1.gfl++;

                                if(*cp == 'p') {
                                        cp++;
                                        rep->r1.pfl = 1;
                                }

                                if(*cp == 'P') {
                                        cp++;
                                        rep->r1.pfl = 2;
                                }

                                if(*cp == 'w') {
                                        cp++;
                                        if(*cp++ !=  ' ') {
                                                fprintf(stderr, CGMES, linebuf);
                                                exit(2);
                                        }
                                        if(nfiles >= MAXFILES) {
                                                fprintf(stderr, "sed: Too many files in w commands 1 \n");
                                                exit(2);
                                        }

                                        text((uchar*)fname[nfiles]);
                                        for(i = nfiles - 1; i >= 0; i--)
                                                if(cmp((uchar*)fname[nfiles],(uchar*)fname[i]) == 0) {
                                                        rep->r1.fcode = fcode[i];
                                                        goto done;
                                                }
                                        if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
                                                fprintf(stderr, "sed: Cannot open %s\n", fname[nfiles]);
                                                exit(2);
                                        }
                                        fcode[nfiles++] = rep->r1.fcode;
                                }
                                break;

                        case 'w':
                                rep->r1.command = WCOM;
                                if(*cp++ != ' ') {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                if(nfiles >= MAXFILES){
                                        fprintf(stderr, "sed: Too many files in w commands 2 \n");
                                        fprintf(stderr, "nfiles = %d; MAXF = %d\n", nfiles, MAXFILES);
                                        exit(2);
                                }

                                text((uchar*)fname[nfiles]);
                                for(i = nfiles - 1; i >= 0; i--)
                                        if(cmp((uchar*)fname[nfiles], (uchar*)fname[i]) == 0) {
                                                rep->r1.fcode = fcode[i];
                                                goto done;
                                        }

                                if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
                                        fprintf(stderr, "sed: Cannot create %s\n", fname[nfiles]);
                                        exit(2);
                                }
                                fcode[nfiles++] = rep->r1.fcode;
                                break;

                        case 'x':
                                rep->r1.command = XCOM;
                                break;

                        case 'y':
                                rep->r1.command = YCOM;
                                seof = *cp++;
                                rep->r1.re1 = p;
                                p = ycomp(rep->r1.re1);
                                if(p == badp) {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                if(p > reend) {
                                        fprintf(stderr, TMMES, linebuf);
                                        exit(2);
                                }
                                break;

                }
done:
                if(++rep >= ptrend) {
                        fprintf(stderr, "sed: Too many commands, last: %s\n", linebuf);
                        exit(2);
                }

                rep->r1.ad1 = p;

                if(*cp++ != '\0') {
                        if(cp[-1] == ';')
                                goto comploop;
                        fprintf(stderr, CGMES, linebuf);
                        exit(2);
                }

        }
}

uchar   *
compsub(uchar *rhsbuf)
{
        uchar   *p, *q, *r;
        p = rhsbuf;
        q = cp;
        for(;;) {
                if((*p = *q++) == '\\') {
                        *++p = *q++;
                        if(*p >= '1' && *p <= '9' && *p > numbra + '0')
                                return(badp);
                        if(*p == 'n')
                                *--p = '\n';
                } else if(*p == seof) {
                        *p++ = '\0';
                        cp = q;
                        return(p);
                }
                if(*p++ == '\0') {
                        return(badp);
                }

        }
}

uchar *
compile(uchar *expbuf)
{
        int c;
        uchar *ep, *sp;
        uchar   neg;
        uchar *lastep, *cstart;
        int cclcnt;
        int     closed;
        uchar   bracket[NBRA], *bracketp;

        if(*cp == seof) {
                cp++;
                return(expbuf);
        }

        ep = expbuf;
        lastep = 0;
        bracketp = bracket;
        closed = numbra = 0;
        sp = cp;
        if (*sp == '^') {
                *ep++ = 1;
                sp++;
        } else {
                *ep++ = 0;
        }
        for (;;) {
                if (ep >= reend) {
                        cp = sp;
                        return(badp);
                }
                if((c = *sp++) == seof) {
                        if(bracketp != bracket) {
                                cp = sp;
                                return(badp);
                        }
                        cp = sp;
                        *ep++ = CEOF;
                        return(ep);
                }
                if(c != '*')
                        lastep = ep;
                switch (c) {

                case '\\':
                        if((c = *sp++) == '(') {
                                if(numbra >= NBRA) {
                                        cp = sp;
                                        return(badp);
                                }
                                *bracketp++ = numbra;
                                *ep++ = CBRA;
                                *ep++ = numbra++;
                                continue;
                        }
                        if(c == ')') {
                                if(bracketp <= bracket) {
                                        cp = sp;
                                        return(badp);
                                }
                                *ep++ = CKET;
                                *ep++ = *--bracketp;
                                closed++;
                                continue;
                        }

                        if(c >= '1' && c <= '9') {
                                if((c -= '1') >= closed)
                                        return(badp);
        
                                *ep++ = CBACK;
                                *ep++ = c;
                                continue;
                        }
                        if(c == '\n') {
                                cp = sp;
                                return(badp);
                        }
                        if(c == 'n') {
                                c = '\n';
                        }
                        goto defchar;

                case '\0':
                case '\n':
                        cp = sp;
                        return(badp);

                case '.':
                        *ep++ = CDOT;
                        continue;

                case '*':
                        if (lastep == 0)
                                goto defchar;
                        if(*lastep == CKET) {
                                cp = sp;
                                return(badp);
                        }
                        *lastep |= STAR;
                        continue;

                case '$':
                        if (*sp != seof)
                                goto defchar;
                        *ep++ = CDOL;
                        continue;

                case '[':
                        if(&ep[33] >= reend) {
                                fprintf(stderr, "sed: RE too long: %s\n", linebuf);
                                exit(2);
                        }

                        *ep++ = CCL;

                        neg = 0;
                        if((c = *sp++) == '^') {
                                neg = 1;
                                c = *sp++;
                        }

                        cstart = sp;
                        do {
                                if(c == '\0') {
                                        fprintf(stderr, CGMES, linebuf);
                                        exit(2);
                                }
                                if (c=='-' && sp>cstart && *sp!=']') {
                                        for (c = sp[-2]; c<*sp; c++)
                                                ep[c>>3] |= bittab[c&07];
                                }
                                if(c == '\\') {
                                        switch(c = *sp++) {
                                                case 'n':
                                                        c = '\n';
                                                        break;
                                        }
                                }

                                ep[c >> 3] |= bittab[c & 07];
                        } while((c = *sp++) != ']');

                        if(neg)
                                for(cclcnt = 0; cclcnt < 32; cclcnt++)
                                        ep[cclcnt] ^= -1;
                        ep[0] &= 0376;

                        ep += 32;

                        continue;

                defchar:
                default:
                        *ep++ = CCHR;
                        *ep++ = c;
                }
        }
}
int
rline(uchar *lbuf)
{
        uchar   *p, *q;
        int     t;
        static uchar    *saveq;

        p = lbuf - 1;

        if(eflag) {
                if(eflag > 0) {
                        eflag = -1;
                        if(eargc-- <= 0)
                                exit(2);
                        q = *++eargv;
                        while(*++p = *q++) {
                                if(*p == '\\') {
                                        if((*++p = *q++) == '\0') {
                                                saveq = 0;
                                                return(-1);
                                        } else
                                                continue;
                                }
                                if(*p == '\n') {
                                        *p = '\0';
                                        saveq = q;
                                        return(1);
                                }
                        }
                        saveq = 0;
                        return(1);
                }
                if((q = saveq) == 0)    return(-1);

                while(*++p = *q++) {
                        if(*p == '\\') {
                                if((*++p = *q++) == '0') {
                                        saveq = 0;
                                        return(-1);
                                } else
                                        continue;
                        }
                        if(*p == '\n') {
                                *p = '\0';
                                saveq = q;
                                return(1);
                        }
                }
                saveq = 0;
                return(1);
        }

        while((t = getc(fin)) != EOF) {
                *++p = t;
                if(*p == '\\') {
                        t = getc(fin);
                        *++p = t;
                }
                else if(*p == '\n') {
                        *p = '\0';
                        return(1);
                }
        }
        *++p = '\0';
        return(-1);
}

uchar *
address(uchar *expbuf)
{
        uchar   *rcp;
        long    lno;

        if(*cp == '$') {
                cp++;
                *expbuf++ = CEND;
                *expbuf++ = CEOF;
                return(expbuf);
        }

        if(*cp == '/') {
                seof = '/';
                cp++;
                return(compile(expbuf));
        }

        rcp = cp;
        lno = 0;

        while(*rcp >= '0' && *rcp <= '9')
                lno = lno*10 + *rcp++ - '0';

        if(rcp > cp) {
                if(!lno){
                        fprintf(stderr, "sed: line number 0 is illegal\n");
                        exit(2);
                }
                *expbuf++ = CLNUM;
                *expbuf++ = lno;
                *expbuf++ = lno >> 8;
                *expbuf++ = lno >> 16;
                *expbuf++ = lno >> 24;
                *expbuf++ = CEOF;
                cp = rcp;
                return(expbuf);
        }
        return(0);
}
int
cmp(uchar *a, uchar *b)
{
        uchar   *ra, *rb;

        ra = a - 1;
        rb = b - 1;

        while(*++ra == *++rb)
                if(*ra == '\0') return(0);
        return(1);
}

uchar *
text(uchar *textbuf)
{
        uchar   *p, *q;

        p = textbuf;
        q = cp;
        while(*q == '\t' || *q == ' ')  q++;
        for(;;) {

                if((*p = *q++) == '\\')
                        *p = *q++;
                if(*p == '\0') {
                        cp = --q;
                        return(++p);
                }
                if(*p == '\n') {
                        while(*q == '\t' || *q == ' ')  q++;
                }
                p++;
        }
}


struct label *
search(struct label *ptr)
{
        struct label    *rp;

        rp = labtab;
        while(rp < ptr) {
                if(cmp(rp->asc, ptr->asc) == 0)
                        return(rp);
                rp++;
        }

        return(0);
}

void
dechain(void)
{
        struct label    *lptr;
        union reptr     *rptr, *trptr;

        for(lptr = labtab; lptr < lab; lptr++) {

                if(lptr->address == 0) {
                        fprintf(stderr, "sed: Undefined label: %s\n", lptr->asc);
                        exit(2);
                }

                if(lptr->chain) {
                        rptr = lptr->chain;
                        while(trptr = rptr->r2.lb1) {
                                rptr->r2.lb1 = lptr->address;
                                rptr = trptr;
                        }
                        rptr->r2.lb1 = lptr->address;
                }
        }
}

uchar *
ycomp(uchar *expbuf)
{
        uchar *ep, *tsp;
        int c;
        uchar   *sp;

        ep = expbuf;
        sp = cp;
        for(tsp = cp; *tsp != seof; tsp++) {
                if(*tsp == '\\')
                        tsp++;
                if(*tsp == '\n' || *tsp == '\0')
                        return(badp);
        }
        tsp++;

        while((c = *sp++) != seof) {
                if(c == '\\' && *sp == 'n') {
                        sp++;
                        c = '\n';
                }
                if((ep[c] = *tsp++) == '\\' && *tsp == 'n') {
                        ep[c] = '\n';
                        tsp++;
                }
                if(ep[c] == seof || ep[c] == '\0')
                        return(badp);
        }
        if(*tsp != seof)
                return(badp);
        cp = ++tsp;

        for(c = 0; c<0400; c++)
                if(ep[c] == 0)
                        ep[c] = c;

        return(ep + 0400);
}