Subversion Repositories planix.SVN

Rev

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

#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include        <stdio.h>
#include "sed.h"

#define Read(f, buf, n) (fflush(stdout), read(f, buf, n))

void
execute(uchar *file)
{
        uchar *p1, *p2;
        union reptr     *ipc;
        int     c;
        long    l;
        uchar   *execp;

        if (file) {
                if ((f = open((char*)file, O_RDONLY)) < 0) {
                        fprintf(stderr, "sed: Can't open %s\n", file);
                }
        } else
                f = 0;

        ebp = ibuf;
        cbp = ibuf;

        if(pending) {
                ipc = pending;
                pending = 0;
                goto yes;
        }

        for(;;) {
                if((execp = gline(linebuf)) == badp) {
                        close(f);
                        return;
                }
                spend = execp;

                for(ipc = ptrspace; ipc->r1.command; ) {

                        p1 = ipc->r1.ad1;
                        p2 = ipc->r1.ad2;

                        if(p1) {

                                if(ipc->r1.inar) {
                                        if(*p2 == CEND) {
                                                p1 = 0;
                                        } else if(*p2 == CLNUM) {
                                                l = p2[1]&0377
                                                        | ((p2[2]&0377)<<8)
                                                        | ((p2[3]&0377)<<16)
                                                        | ((p2[4]&0377)<<24);
                                                if(lnum > l) {
                                                        ipc->r1.inar = 0;
                                                        if(ipc->r1.negfl)
                                                                goto yes;
                                                        ipc++;
                                                        continue;
                                                }
                                                if(lnum == l) {
                                                        ipc->r1.inar = 0;
                                                }
                                        } else if(match(p2, 0)) {
                                                ipc->r1.inar = 0;
                                        }
                                } else if(*p1 == CEND) {
                                        if(!dolflag) {
                                                if(ipc->r1.negfl)
                                                        goto yes;
                                                ipc++;
                                                continue;
                                        }

                                } else if(*p1 == CLNUM) {
                                        l = p1[1]&0377
                                                | ((p1[2]&0377)<<8)
                                                | ((p1[3]&0377)<<16)
                                                | ((p1[4]&0377)<<24);
                                        if(lnum != l) {
                                                if(ipc->r1.negfl)
                                                        goto yes;
                                                ipc++;
                                                continue;
                                        }
                                        if(p2)
                                                ipc->r1.inar = 1;
                                } else if(match(p1, 0)) {
                                        if(p2)
                                                ipc->r1.inar = 1;
                                } else {
                                        if(ipc->r1.negfl)
                                                goto yes;
                                        ipc++;
                                        continue;
                                }
                        }

                        if(ipc->r1.negfl) {
                                ipc++;
                                continue;
                        }
        yes:
                        command(ipc);

                        if(delflag)
                                break;

                        if(jflag) {
                                jflag = 0;
                                if((ipc = ipc->r2.lb1) == 0) {
                                        ipc = ptrspace;
                                        break;
                                }
                        } else
                                ipc++;

                }
                if(!nflag && !delflag) {
                        for(p1 = linebuf; p1 < spend; p1++)
                                putc(*p1, stdout);
                        putc('\n', stdout);
                }

                if(aptr > abuf) {
                        arout();
                }

                delflag = 0;

        }
}
int
match(uchar *expbuf, int gf)
{
        uchar   *p1, *p2;
        int c;

        if(gf) {
                if(*expbuf)     return(0);
                p1 = linebuf;
                p2 = genbuf;
                while(*p1++ = *p2++);
                locs = p1 = loc2;
        } else {
                p1 = linebuf;
                locs = 0;
        }

        p2 = expbuf;
        if(*p2++) {
                loc1 = p1;
                if(*p2 == CCHR && p2[1] != *p1)
                        return(0);
                return(advance(p1, p2));
        }

        /* fast check for first character */

        if(*p2 == CCHR) {
                c = p2[1];
                do {
                        if(*p1 != c)
                                continue;
                        if(advance(p1, p2)) {
                                loc1 = p1;
                                return(1);
                        }
                } while(*p1++);
                return(0);
        }

        do {
                if(advance(p1, p2)) {
                        loc1 = p1;
                        return(1);
                }
        } while(*p1++);
        return(0);
}
int
advance(uchar *alp, uchar *aep)
{
        uchar *lp, *ep, *curlp;
        uchar   c;
        uchar *bbeg;
        int     ct;

/*fprintf(stderr, "*lp = %c, %o\n*ep = %c, %o\n", *lp, *lp, *ep, *ep);  /*DEBUG*/

        lp = alp;
        ep = aep;
        for (;;) switch (*ep++) {

        case CCHR:
                if (*ep++ == *lp++)
                        continue;
                return(0);

        case CDOT:
                if (*lp++)
                        continue;
                return(0);

        case CNL:
        case CDOL:
                if (*lp == 0)
                        continue;
                return(0);

        case CEOF:
                loc2 = lp;
                return(1);

        case CCL:
                c = *lp++;
                if(ep[c>>3] & bittab[c & 07]) {
                        ep += 32;
                        continue;
                }
                return(0);

        case CBRA:
                braslist[*ep++] = lp;
                continue;

        case CKET:
                braelist[*ep++] = lp;
                continue;

        case CBACK:
                bbeg = braslist[*ep];
                ct = braelist[*ep++] - bbeg;

                if(ecmp(bbeg, lp, ct)) {
                        lp += ct;
                        continue;
                }
                return(0);

        case CBACK|STAR:
                bbeg = braslist[*ep];
                ct = braelist[*ep++] - bbeg;
                curlp = lp;
                while(ecmp(bbeg, lp, ct))
                        lp += ct;

                while(lp >= curlp) {
                        if(advance(lp, ep))     return(1);
                        lp -= ct;
                }
                return(0);


        case CDOT|STAR:
                curlp = lp;
                while (*lp++);
                goto star;

        case CCHR|STAR:
                curlp = lp;
                while (*lp++ == *ep);
                ep++;
                goto star;

        case CCL|STAR:
                curlp = lp;
                do {
                        c = *lp++;
                } while(ep[c>>3] & bittab[c & 07]);
                ep += 32;
                goto star;

        star:
                if(--lp == curlp) {
                        continue;
                }

                if(*ep == CCHR) {
                        c = ep[1];
                        do {
                                if(*lp != c)
                                        continue;
                                if(advance(lp, ep))
                                        return(1);
                        } while(lp-- > curlp);
                        return(0);
                }

                if(*ep == CBACK) {
                        c = *(braslist[ep[1]]);
                        do {
                                if(*lp != c)
                                        continue;
                                if(advance(lp, ep))
                                        return(1);
                        } while(lp-- > curlp);
                        return(0);
                }

                do {
                        if(lp == locs)  break;
                        if (advance(lp, ep))
                                return(1);
                } while (lp-- > curlp);
                return(0);

        default:
                fprintf(stderr, "sed:  RE botch, %o\n", *--ep);
                exit(1);
        }
}
int
substitute(union reptr *ipc)
{
        uchar   *oloc2;

        if(match(ipc->r1.re1, 0)) {

                sflag = 1;
                if(!ipc->r1.gfl) {
                        dosub(ipc->r1.rhs);
                        return(1);
                }

                oloc2 = NULL;
                do {
                        if(oloc2 == loc2) {
                                loc2++;
                                continue;
                        } else {
                                dosub(ipc->r1.rhs);
                                if(*loc2 == 0)
                                        break;
                                oloc2 = loc2;
                        }
                } while(match(ipc->r1.re1, 1));
                return(1);
        }
        return(0);
}

void
dosub(uchar *rhsbuf)
{
        uchar *lp, *sp, *rp;
        int c;

        lp = linebuf;
        sp = genbuf;
        rp = rhsbuf;
        while (lp < loc1)
                *sp++ = *lp++;
        while(c = *rp++) {
                if (c == '\\') {
                        c = *rp++;
                        if (c >= '1' && c < NBRA+'1') {
                                sp = place(sp, braslist[c-'1'], braelist[c-'1']);
                                continue;
                        }
                } else if(c == '&') {
                                sp = place(sp, loc1, loc2);
                                continue;
                }
                *sp++ = c;
                if (sp >= &genbuf[LBSIZE])
                        fprintf(stderr, "sed: Output line too long.\n");
        }
        lp = loc2;
        loc2 = sp - genbuf + linebuf;
        while (*sp++ = *lp++)
                if (sp >= &genbuf[LBSIZE]) {
                        fprintf(stderr, "sed: Output line too long.\n");
                }
        lp = linebuf;
        sp = genbuf;
        while (*lp++ = *sp++);
        spend = lp-1;
}
uchar *
place(uchar *asp, uchar *al1, uchar *al2)
{
        uchar *sp, *l1, *l2;

        sp = asp;
        l1 = al1;
        l2 = al2;
        while (l1 < l2) {
                *sp++ = *l1++;
                if (sp >= &genbuf[LBSIZE])
                        fprintf(stderr, "sed: Output line too long.\n");
        }
        return(sp);
}

void
command(union reptr *ipc)
{
        int     i;
        uchar   *p1, *p2;
        uchar   *execp;


        switch(ipc->r1.command) {

                case ACOM:
                        *aptr++ = ipc;
                        if(aptr >= &abuf[ABUFSIZE]) {
                                fprintf(stderr, "sed: Too many appends after line %ld\n",
                                        lnum);
                        }
                        *aptr = 0;
                        break;

                case CCOM:
                        delflag = 1;
                        if(!ipc->r1.inar || dolflag) {
                                for(p1 = ipc->r1.re1; *p1; )
                                        putc(*p1++, stdout);
                                putc('\n', stdout);
                        }
                        break;
                case DCOM:
                        delflag++;
                        break;
                case CDCOM:
                        p1 = p2 = linebuf;

                        while(*p1 != '\n') {
                                if(*p1++ == 0) {
                                        delflag++;
                                        return;
                                }
                        }

                        p1++;
                        while(*p2++ = *p1++);
                        spend = p2-1;
                        jflag++;
                        break;

                case EQCOM:
                        fprintf(stdout, "%ld\n", lnum);
                        break;

                case GCOM:
                        p1 = linebuf;
                        p2 = holdsp;
                        while(*p1++ = *p2++);
                        spend = p1-1;
                        break;

                case CGCOM:
                        *spend++ = '\n';
                        p1 = spend;
                        p2 = holdsp;
                        while(*p1++ = *p2++)
                                if(p1 >= lbend)
                                        break;
                        spend = p1-1;
                        break;

                case HCOM:
                        p1 = holdsp;
                        p2 = linebuf;
                        while(*p1++ = *p2++);
                        hspend = p1-1;
                        break;

                case CHCOM:
                        *hspend++ = '\n';
                        p1 = hspend;
                        p2 = linebuf;
                        while(*p1++ = *p2++)
                                if(p1 >= hend)
                                        break;
                        hspend = p1-1;
                        break;

                case ICOM:
                        for(p1 = ipc->r1.re1; *p1; )
                                putc(*p1++, stdout);
                        putc('\n', stdout);
                        break;

                case BCOM:
                        jflag = 1;
                        break;

                case LCOM:
                        p1 = linebuf;
                        p2 = genbuf;
                        while(*p1) {
                                p2 = lformat(*p1++ & 0377, p2);
                                if(p2>lcomend && *p1) {
                                        *p2 = 0;
                                        fprintf(stdout, "%s\\\n", genbuf);
                                        p2 = genbuf;
                                }
                        }
                        if(p2>genbuf && (p1[-1]==' '||p1[-1]=='\n'))
                                        p2 = lformat('\n', p2);
                        *p2 = 0;
                        fprintf(stdout, "%s\n", genbuf);
                        break;

                case NCOM:
                        if(!nflag) {
                                for(p1 = linebuf; p1 < spend; p1++)
                                        putc(*p1, stdout);
                                putc('\n', stdout);
                        }

                        if(aptr > abuf)
                                arout();
                        if((execp = gline(linebuf)) == badp) {
                                pending = ipc;
                                delflag = 1;
                                break;
                        }
                        spend = execp;

                        break;
                case CNCOM:
                        if(aptr > abuf)
                                arout();
                        *spend++ = '\n';
                        if((execp = gline(spend)) == badp) {
                                pending = ipc;
                                delflag = 1;
                                break;
                        }
                        spend = execp;
                        break;

                case PCOM:
                        for(p1 = linebuf; p1 < spend; p1++)
                                putc(*p1, stdout);
                        putc('\n', stdout);
                        break;
                case CPCOM:
        cpcom:
                        for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
                                putc(*p1++, stdout);
                        putc('\n', stdout);
                        break;

                case QCOM:
                        if(!nflag) {
                                for(p1 = linebuf; p1 < spend; p1++)
                                        putc(*p1, stdout);
                                putc('\n', stdout);
                        }
                        if(aptr > abuf) arout();
                        fclose(stdout);
                        lseek(f,(long)(cbp-ebp),2);
                        exit(0);
                case RCOM:

                        *aptr++ = ipc;
                        if(aptr >= &abuf[ABUFSIZE])
                                fprintf(stderr, "sed: Too many reads after line%ld\n",
                                        lnum);

                        *aptr = 0;

                        break;

                case SCOM:
                        i = substitute(ipc);
                        if(ipc->r1.pfl && i)
                                if(ipc->r1.pfl == 1) {
                                        for(p1 = linebuf; p1 < spend; p1++)
                                                putc(*p1, stdout);
                                        putc('\n', stdout);
                                }
                                else
                                        goto cpcom;
                        if(i && ipc->r1.fcode)
                                goto wcom;
                        break;

                case TCOM:
                        if(sflag == 0)  break;
                        sflag = 0;
                        jflag = 1;
                        break;

                wcom:
                case WCOM:
                        fprintf(ipc->r1.fcode, "%s\n", linebuf);
                        fflush(ipc->r1.fcode);
                        break;
                case XCOM:
                        p1 = linebuf;
                        p2 = genbuf;
                        while(*p2++ = *p1++);
                        p1 = holdsp;
                        p2 = linebuf;
                        while(*p2++ = *p1++);
                        spend = p2 - 1;
                        p1 = genbuf;
                        p2 = holdsp;
                        while(*p2++ = *p1++);
                        hspend = p2 - 1;
                        break;

                case YCOM:
                        p1 = linebuf;
                        p2 = ipc->r1.re1;
                        while(*p1 = p2[*p1])    p1++;
                        break;
        }

}

uchar *
gline(uchar *addr)
{
        uchar   *p1, *p2;
        int     c;
        sflag = 0;
        p1 = addr;
        p2 = cbp;
        for (;;) {
                if (p2 >= ebp) {
                        if ((c = Read(f, ibuf, 512)) <= 0) {
                                return(badp);
                        }
                        p2 = ibuf;
                        ebp = ibuf+c;
                }
                if ((c = *p2++) == '\n') {
                        if(p2 >=  ebp) {
                                if((c = Read(f, ibuf, 512)) <= 0) {
                                        close(f);
                                        if(eargc == 0)
                                                        dolflag = 1;
                                }

                                p2 = ibuf;
                                ebp = ibuf + c;
                        }
                        break;
                }
                if(c)
                if(p1 < lbend)
                        *p1++ = c;
        }
        lnum++;
        *p1 = 0;
        cbp = p2;

        return(p1);
}
int
ecmp(uchar *a, uchar *b, int count)
{
        while(count--)
                if(*a++ != *b++)        return(0);
        return(1);
}

void
arout(void)
{
        uchar   *p1;
        FILE    *fi;
        uchar   c;
        int     t;

        aptr = abuf - 1;
        while(*++aptr) {
                if((*aptr)->r1.command == ACOM) {
                        for(p1 = (*aptr)->r1.re1; *p1; )
                                putc(*p1++, stdout);
                        putc('\n', stdout);
                } else {
                        if((fi = fopen((char*)((*aptr)->r1.re1), "r")) == NULL)
                                continue;
                        while((t = getc(fi)) != EOF) {
                                c = t;
                                putc(c, stdout);
                        }
                        fclose(fi);
                }
        }
        aptr = abuf;
        *aptr = 0;
}

uchar *
lformat(int c, uchar *p)
{
        int trans = 
                c=='\b'? 'b':
                c=='\t'? 't':
                c=='\n'? 'n':
                c=='\v'? 'v':
                c=='\f'? 'f':
                c=='\r'? 'r':
                c=='\\'? '\\':
                0;
        if(trans) {
                *p++ = '\\';
                *p++ = trans;
        } else if(c<040 || c>=0177) {
                *p++ = '\\';
                *p++ = ((c>>6)&07) + '0';
                *p++ = ((c>>3)&07) + '0';
                *p++ = (c&07) + '0';
        } else
                *p++ = c;
        return p;
}