Annotation of 40BSD/cmd/oldcsh/sh.dol.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) 1979 Regents of the University of California */
                      2: #include "sh.h"
                      3: 
                      4: /*
                      5:  * C shell
                      6:  */
                      7: 
                      8: /*
                      9:  * These routines perform variable substitution and quoting via ' and ".
                     10:  * To this point these constructs have been preserved in the divided
                     11:  * input words.  Here we expand variables and turn quoting via ' and " into
                     12:  * QUOTE bits on characters (which prevent further interpretation).
                     13:  * If the `:q' modifier was applied during history expansion, then
                     14:  * some QUOTEing may have occurred already, so we dont "scan(,&trim)" here.
                     15:  */
                     16: 
                     17: int    Dpeekc, Dpeekrd;                /* Peeks for DgetC and Dreadc */
                     18: char   *Dcp, **Dvp;                    /* Input vector for Dreadc */
                     19: 
                     20: #define        DEOF    -1
                     21: 
                     22: #define        unDgetC(c)      Dpeekc = c
                     23: 
                     24: char   *QUOTES = "\\'`\"";
                     25: 
                     26: /*
                     27:  * The following variables give the information about the current
                     28:  * $ expansion, recording the current word position, the remaining
                     29:  * words within this expansion, the count of remaining words, and the
                     30:  * information about any : modifier which is being applied.
                     31:  */
                     32: char   *dolp;                  /* Remaining chars from this word */
                     33: char   **dolnxt;               /* Further words */
                     34: int    dolcnt;                 /* Count of further words */
                     35: char   dolmod;                 /* : modifier character */
                     36: int    dolmcnt;                /* :gx -> 10000, else 1 */
                     37: 
                     38: int    Dtest();                /* Test for \ " ` or ' */
                     39: 
                     40: /*
                     41:  * Fix up the $ expansions and quotations in the
                     42:  * argument list to command t.
                     43:  */
                     44: Dfix(t)
                     45:        register struct command *t;
                     46: {
                     47: 
                     48:        if (noexec)
                     49:                return;
                     50:        gflag = 0, rscan(t->t_dcom, Dtest);
                     51:        if (gflag == 0)
                     52:                return;
                     53:        Dfix2(t->t_dcom);
                     54:        blkfree(t->t_dcom), t->t_dcom = gargv, gargv = 0;
                     55: }
                     56: 
                     57: /*
                     58:  * $ substitute one word, for i/o redirection
                     59:  */
                     60: char *
                     61: Dfix1(cp)
                     62:        register char *cp;
                     63: {
                     64:        char *Dv[2];
                     65: 
                     66:        if (noexec)
                     67:                return (0);
                     68:        Dv[0] = cp; Dv[1] = NOSTR;
                     69:        Dfix2(Dv);
                     70:        if (gargc != 1) {
                     71:                setname(cp);
                     72:                bferr("Ambiguous");
                     73:        }
                     74:        cp = savestr(gargv[0]);
                     75:        blkfree(gargv), gargv = 0;
                     76:        return (cp);
                     77: }
                     78: 
                     79: /*
                     80:  * Subroutine to do actual fixing after state initialization.
                     81:  */
                     82: Dfix2(v)
                     83:        char **v;
                     84: {
                     85:        char *agargv[GAVSIZ];
                     86: 
                     87:        ginit(agargv);                  /* Initialize glob's area pointers */
                     88:        Dvp = v; Dcp = "";              /* Setup input vector for Dreadc */
                     89:        unDgetC(0); unDredc(0);         /* Clear out any old peeks (at error) */
                     90:        dolp = 0; dolcnt = 0;           /* Clear out residual $ expands (...) */
                     91:        while (Dword())
                     92:                continue;
                     93:        gargv = copyblk(gargv);
                     94: }
                     95: 
                     96: /*
                     97:  * Get a word.  This routine is analogous to the routine
                     98:  * word() in sh.lex.c for the main lexical input.  One difference
                     99:  * here is that we don't get a newline to terminate our expansion.
                    100:  * Rather, DgetC will return a DEOF when we hit the end-of-input.
                    101:  */
                    102: Dword()
                    103: {
                    104:        register int c, c1;
                    105:        char wbuf[BUFSIZ];
                    106:        register char *wp = wbuf;
                    107:        register int i = BUFSIZ - 4;
                    108:        register bool dolflg;
                    109:        bool sofar = 0;
                    110: 
                    111: loop:
                    112:        c = DgetC(DODOL);
                    113:        switch (c) {
                    114: 
                    115:        case DEOF:
                    116: deof:
                    117:                if (sofar == 0)
                    118:                        return (0);
                    119:                /* finish this word and catch the code above the next time */
                    120:                unDredc(c);
                    121:                /* fall into ... */
                    122: 
                    123:        case '\n':
                    124:                *wp = 0;
                    125:                goto ret;
                    126: 
                    127:        case ' ':
                    128:        case '\t':
                    129:                goto loop;
                    130: 
                    131:        case '`':
                    132:                /* We preserve ` quotations which are done yet later */
                    133:                *wp++ = c, --i;
                    134:        case '\'':
                    135:        case '"':
                    136:                /*
                    137:                 * Note that DgetC never returns a QUOTES character
                    138:                 * from an expansion, so only true input quotes will
                    139:                 * get us here or out.
                    140:                 */
                    141:                c1 = c;
                    142:                dolflg = c1 == '"' ? DODOL : 0;
                    143:                for (;;) {
                    144:                        c = DgetC(dolflg);
                    145:                        if (c == c1)
                    146:                                break;
                    147:                        if (c == '\n' || c == DEOF)
                    148:                                error("Unmatched %c", c1);
                    149:                        if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
                    150:                                --wp, ++i;
                    151:                        if (--i <= 0)
                    152:                                goto toochars;
                    153:                        switch (c1) {
                    154: 
                    155:                        case '"':
                    156:                                /*
                    157:                                 * Leave any `s alone for later.
                    158:                                 * Other chars are all quoted, thus `...`
                    159:                                 * can tell it was within "...".
                    160:                                 */
                    161:                                *wp++ = c == '`' ? '`' : c | QUOTE;
                    162:                                break;
                    163: 
                    164:                        case '\'':
                    165:                                /* Prevent all further interpretation */
                    166:                                *wp++ = c | QUOTE;
                    167:                                break;
                    168: 
                    169:                        case '`':
                    170:                                /* Leave all text alone for later */
                    171:                                *wp++ = c;
                    172:                                break;
                    173:                        }
                    174:                }
                    175:                if (c1 == '`')
                    176:                        *wp++ = '`', --i;
                    177:                goto pack;              /* continue the word */
                    178: 
                    179:        case '\\':
                    180:                c = DgetC(0);           /* No $ subst! */
                    181:                if (c == '\n' || c == DEOF)
                    182:                        goto loop;
                    183:                c |= QUOTE;
                    184:                break;
                    185:        }
                    186:        unDgetC(c);
                    187: pack:
                    188:        sofar = 1;
                    189:        /* pack up more characters in this word */
                    190:        for (;;) {
                    191:                c = DgetC(DODOL);
                    192:                if (c == '\\') {
                    193:                        c = DgetC(0);
                    194:                        if (c == DEOF)
                    195:                                goto deof;
                    196:                        if (c == '\n')
                    197:                                c = ' ';
                    198:                        else
                    199:                                c |= QUOTE;
                    200:                }
                    201:                if (c == DEOF)
                    202:                        goto deof;
                    203:                if (any(c, " '`\"\t\n")) {
                    204:                        unDgetC(c);
                    205:                        if (any(c, QUOTES))
                    206:                                goto loop;
                    207:                        *wp++ = 0;
                    208:                        goto ret;
                    209:                }
                    210:                if (--i <= 0)
                    211: toochars:
                    212:                        error("Word too long");
                    213:                *wp++ = c;
                    214:        }
                    215: ret:
                    216:        Gcat("", wbuf);
                    217:        return (1);
                    218: }
                    219: 
                    220: /*
                    221:  * Get a character, performing $ substitution unless flag is 0.
                    222:  * Any QUOTES character which is returned from a $ expansion is
                    223:  * QUOTEd so that it will not be recognized above.
                    224:  */
                    225: DgetC(flag)
                    226:        register int flag;
                    227: {
                    228:        register int c;
                    229: 
                    230: top:
                    231:        if (c = Dpeekc) {
                    232:                Dpeekc = 0;
                    233:                return (c);
                    234:        }
                    235:        if (lap) {
                    236:                c = *lap++;
                    237:                if (c == 0) {
                    238:                        lap = 0;
                    239:                        goto top;
                    240:                }
                    241: quotspec:
                    242:                if (any(c, QUOTES))
                    243:                        return (c | QUOTE);
                    244:                return (c);
                    245:        }
                    246:        if (dolp) {
                    247:                if (c = *dolp++)
                    248:                        goto quotspec;
                    249:                if (dolcnt > 0) {
                    250:                        setDolp(*dolnxt++);
                    251:                        --dolcnt;
                    252:                        return (' ');
                    253:                }
                    254:                dolp = 0;
                    255:        }
                    256:        if (dolcnt > 0) {
                    257:                setDolp(*dolnxt++);
                    258:                --dolcnt;
                    259:                goto top;
                    260:        }
                    261:        c = Dredc();
                    262:        if (c == '$' && flag) {
                    263:                Dgetdol();
                    264:                goto top;
                    265:        }
                    266:        return (c);
                    267: }
                    268: 
                    269: char   *nulvec[] = { 0 };
                    270: struct varent nulargv = { nulvec, "argv", 0 };
                    271: 
                    272: /*
                    273:  * Handle the multitudinous $ expansion forms.
                    274:  * Ugh.
                    275:  */
                    276: Dgetdol()
                    277: {
                    278:        register char *np;
                    279:        register struct varent *vp;
                    280:        char name[20];
                    281:        int c, sc;
                    282:        int subscr = 0, lwb = 1, upb = 0;
                    283:        bool dimen = 0, isset = 0;
                    284: 
                    285:        dolmod = dolmcnt = 0;
                    286:        c = sc = DgetC(0);
                    287:        if (c == '{')
                    288:                c = DgetC(0);           /* sc is { to take } later */
                    289:        if ((c & TRIM) == '#')
                    290:                dimen++, c = DgetC(0);          /* $# takes dimension */
                    291:        else if (c == '?')
                    292:                isset++, c = DgetC(0);          /* $? tests existence */
                    293:        switch (c) {
                    294:        
                    295:        case '$':
                    296:                if (dimen || isset)
                    297:                        goto syntax;            /* No $?$, $#$ */
                    298:                setDolp(doldol);
                    299:                goto eatbrac;
                    300: 
                    301:        case DEOF:
                    302:        case '\n':
                    303:                goto syntax;
                    304: 
                    305:        case '*':
                    306:                strcpy(name, "argv");
                    307:                vp = adrof("argv");
                    308:                subscr = -1;                    /* Prevent eating [...] */
                    309:                break;
                    310: 
                    311:        default:
                    312:                np = name;
                    313:                if (digit(c)) {
                    314:                        if (dimen)
                    315:                                goto syntax;    /* No $#1, e.g. */
                    316:                        subscr = 0;
                    317:                        do {
                    318:                                subscr = subscr * 10 + c - '0';
                    319:                                c = DgetC(0);
                    320:                        } while (digit(c));
                    321:                        unDredc(c);
                    322:                        if (subscr < 0)
                    323:                                goto oob;
                    324:                        if (subscr == 0) {
                    325:                                if (isset) {
                    326:                                        dolp = file ? "1" : "0";
                    327:                                        goto eatbrac;
                    328:                                }
                    329:                                if (file == 0)
                    330:                                        error("No file for $0");
                    331:                                setDolp(file);
                    332:                                goto eatbrac;
                    333:                        }
                    334:                        if (isset)
                    335:                                goto syntax;
                    336:                        vp = adrof("argv");
                    337:                        if (vp == 0) {
                    338:                                vp = &nulargv;
                    339:                                goto eatmod;
                    340:                        }
                    341:                        break;
                    342:                }
                    343:                if (!letter(c))
                    344:                        goto syntax;
                    345:                for (;;) {
                    346:                        *np++ = c;
                    347:                        c = DgetC(0);
                    348:                        if (!letter(c))
                    349:                                break;
                    350:                        if (np >= &name[sizeof name - 2])
                    351: syntax:
                    352:                                error("Variable syntax");
                    353:                }
                    354:                *np++ = 0;
                    355:                unDredc(c);
                    356:                vp = adrof(name);
                    357:        }
                    358:        if (isset) {
                    359:                dolp = vp ? "1" : "0";
                    360:                goto eatbrac;
                    361:        }
                    362:        if (vp == 0)
                    363:                udvar(name);
                    364:        c = DgetC(0);
                    365:        upb = blklen(vp->vec);
                    366:        if (dimen == 0 && subscr == 0 && c == '[') {
                    367:                np = name;
                    368:                for (;;) {
                    369:                        c = DgetC(DODOL);       /* Allow $ expand within [ ] */
                    370:                        if (c == ']')
                    371:                                break;
                    372:                        if (c == '\n' || c == DEOF)
                    373:                                goto syntax;
                    374:                        if (np >= &name[sizeof name - 2])
                    375:                                goto syntax;
                    376:                        *np++ = c;
                    377:                }
                    378:                *np = 0, np = name;
                    379:                if (dolp || dolcnt)             /* $ exp must end before ] */
                    380:                        goto syntax;
                    381:                if (!*np)
                    382:                        goto syntax;
                    383:                if (digit(*np)) {
                    384:                        register int i = 0;
                    385: 
                    386:                        while (digit(*np))
                    387:                                i = i * 10 + *np++ - '0';
                    388:                        if ((i < 0 || i > upb) && !any(*np, "-*")) {
                    389: oob:
                    390:                                setname(vp->name);
                    391:                                error("Subscript out of range");
                    392:                        }
                    393:                        lwb = i;
                    394:                        if (!*np)
                    395:                                upb = lwb, np = "*";
                    396:                }
                    397:                if (*np == '*')
                    398:                        np++;
                    399:                else if (*np != '-')
                    400:                        goto syntax;
                    401:                else {
                    402:                        register int i = upb;
                    403: 
                    404:                        np++;
                    405:                        if (digit(*np)) {
                    406:                                i = 0;
                    407:                                while (digit(*np))
                    408:                                        i = i * 10 + *np++ - '0';
                    409:                                if (i < 0 || i > upb)
                    410:                                        goto oob;
                    411:                        }
                    412:                        if (i < lwb)
                    413:                                upb = lwb - 1;
                    414:                        else
                    415:                                upb = i;
                    416:                }
                    417:                if (lwb == 0) {
                    418:                        if (upb != 0)
                    419:                                goto oob;
                    420:                        upb = -1;
                    421:                }
                    422:                if (*np)
                    423:                        goto syntax;
                    424:        } else {
                    425:                if (subscr > 0)
                    426:                        if (subscr > upb)
                    427:                                lwb = 1, upb = 0;
                    428:                        else
                    429:                                lwb = upb = subscr;
                    430:                unDredc(c);
                    431:        }
                    432:        if (dimen) {
                    433:                char *cp = putn(upb - lwb + 1);
                    434: 
                    435:                addla(cp);
                    436:                xfree(cp);
                    437:        } else {
                    438: eatmod:
                    439:                c = DgetC(0);
                    440:                if (c == ':') {
                    441:                        c = DgetC(0), dolmcnt = 1;
                    442:                        if (c == 'g')
                    443:                                c = DgetC(0), dolmcnt = 10000;
                    444:                        if (!any(c, "htrqx"))
                    445:                                error("Bad : mod in $");
                    446:                        dolmod = c;
                    447:                        if (c == 'q')
                    448:                                dolmcnt = 10000;
                    449:                } else
                    450:                        unDredc(c);
                    451:                dolnxt = &vp->vec[lwb - 1];
                    452:                dolcnt = upb - lwb + 1;
                    453:        }
                    454: eatbrac:
                    455:        if (sc == '{') {
                    456:                c = Dredc();
                    457:                if (c != '}')
                    458:                        goto syntax;
                    459:        }
                    460: }
                    461: 
                    462: setDolp(cp)
                    463:        register char *cp;
                    464: {
                    465:        register char *dp;
                    466: 
                    467:        if (dolmod == 0 || dolmcnt == 0) {
                    468:                dolp = cp;
                    469:                return;
                    470:        }
                    471:        dp = domod(cp, dolmod);
                    472:        if (dp) {
                    473:                dolmcnt--;
                    474:                addla(dp);
                    475:                xfree(dp);
                    476:        } else
                    477:                addla(cp);
                    478:        dolp = "";
                    479: }
                    480: 
                    481: unDredc(c)
                    482:        int c;
                    483: {
                    484: 
                    485:        Dpeekrd = c;
                    486: }
                    487: 
                    488: Dredc()
                    489: {
                    490:        register int c;
                    491: 
                    492:        if (c = Dpeekrd) {
                    493:                Dpeekrd = 0;
                    494:                return (c);
                    495:        }
                    496:        if (Dcp && (c = *Dcp++))
                    497:                return (c);
                    498:        if (*Dvp == 0) {
                    499:                Dcp = 0;
                    500:                return (DEOF);
                    501:        }
                    502:        Dcp = *Dvp++;
                    503:        return (' ');
                    504: }
                    505: 
                    506: Dtest(c)
                    507:        register int c;
                    508: {
                    509: 
                    510:        /* Note that c isn't trimmed thus !...:q's aren't lost */
                    511:        if (any(c, "$\\'`\""))
                    512:                gflag = 1;
                    513: }
                    514: 
                    515: Dtestq(c)
                    516:        register int c;
                    517: {
                    518: 
                    519:        if (any(c, "\\'`\""))
                    520:                gflag = 1;
                    521: }
                    522: 
                    523: /*
                    524:  * Form a shell temporary file (in unit 0) from the words
                    525:  * of the shell input up to a line the same as "term".
                    526:  * Unit 0 should have been closed before this call.
                    527:  */
                    528: heredoc(term)
                    529:        char *term;
                    530: {
                    531:        register int c;
                    532:        char *Dv[2];
                    533:        char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
                    534:        int ocnt, lcnt, mcnt;
                    535:        register char *lbp, *obp, *mbp;
                    536:        char **vp;
                    537:        bool quoted;
                    538: 
                    539:        if (creat(shtemp, 0600) < 0)
                    540:                Perror(shtemp);
                    541:        close(0);
                    542:        if (open(shtemp, 2) < 0) {
                    543:                int oerrno = errno;
                    544: 
                    545:                unlink(shtemp);
                    546:                errno = oerrno;
                    547:                Perror(shtemp);
                    548:        }
                    549:        unlink(shtemp);                 /* 0 0 inode! */
                    550:        Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
                    551:        scan(Dv, trim); rscan(Dv, Dtestq); quoted = gflag;
                    552:        ocnt = BUFSIZ; obp = obuf;
                    553:        for (;;) {
                    554:                /*
                    555:                 * Read up a line
                    556:                 */
                    557:                lbp = lbuf; lcnt = BUFSIZ - 4;
                    558:                for (;;) {
                    559:                        c = readc(1);           /* 1 -> Want EOF returns */
                    560:                        if (c < 0) {
                    561:                                setname(term);
                    562:                                bferr("<< terminator not found");
                    563:                        }
                    564:                        if (c == '\n')
                    565:                                break;
                    566:                        if (c &= TRIM) {
                    567:                                *lbp++ = c;
                    568:                                if (--lcnt < 0) {
                    569:                                        setname("<<");
                    570:                                        error("Line overflow");
                    571:                                } 
                    572:                        }
                    573:                }
                    574:                *lbp = 0;
                    575: 
                    576:                /*
                    577:                 * Compare to terminator -- before expansion
                    578:                 */
                    579:                if (eq(lbuf, term)) {
                    580:                        write(0, obuf, BUFSIZ - ocnt);
                    581:                        lseek(0, 0l, 0);
                    582:                        return;
                    583:                }
                    584: 
                    585:                /*
                    586:                 * If term was quoted or -n just pass it on
                    587:                 */
                    588:                if (quoted || noexec) {
                    589:                        *lbp++ = '\n'; *lbp = 0;
                    590:                        for (lbp = lbuf; c = *lbp++;) {
                    591:                                *obp++ = c;
                    592:                                if (--ocnt == 0) {
                    593:                                        write(0, obuf, BUFSIZ);
                    594:                                        obp = obuf; ocnt = BUFSIZ;
                    595:                                }
                    596:                        }
                    597:                        continue;
                    598:                }
                    599: 
                    600:                /*
                    601:                 * Term wasn't quoted so variable and then command
                    602:                 * expand the input line
                    603:                 */
                    604:                Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
                    605:                for (;;) {
                    606:                        c = DgetC(DODOL);
                    607:                        if (c == DEOF)
                    608:                                break;
                    609:                        if ((c &= TRIM) == 0)
                    610:                                continue;
                    611:                        /* \ quotes \ $ ` here */
                    612:                        if (c =='\\') {
                    613:                                c = DgetC(0);
                    614:                                if (!any(c, "$\\`"))
                    615:                                        unDgetC(c | QUOTE), c = '\\';
                    616:                                else
                    617:                                        c |= QUOTE;
                    618:                        }
                    619:                        *mbp++ = c;
                    620:                        if (--mcnt == 0) {
                    621:                                setname("<<");
                    622:                                bferr("Line overflow");
                    623:                        }
                    624:                }
                    625:                *mbp++ = 0;
                    626: 
                    627:                /*
                    628:                 * If any ` in line do command substitution
                    629:                 */
                    630:                mbp = mbuf;
                    631:                if (any('`', mbp)) {
                    632:                        /*
                    633:                         * 1 arg to dobackp causes substitution to be literal.
                    634:                         * Words are broken only at newlines so that all blanks
                    635:                         * and tabs are preserved.  Blank lines (null words)
                    636:                         * are not discarded.
                    637:                         */
                    638:                        vp = dobackp(mbuf, 1);
                    639:                } else
                    640:                        /* Setup trivial vector similar to return of dobackp */
                    641:                        Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
                    642: 
                    643:                /*
                    644:                 * Resurrect the words from the command substitution
                    645:                 * each separated by a newline.  Note that the last
                    646:                 * newline of a command substitution will have been
                    647:                 * discarded, but we put a newline after the last word
                    648:                 * because this represents the newline after the last
                    649:                 * input line!
                    650:                 */
                    651:                for (; *vp; vp++) {
                    652:                        for (mbp = *vp; *mbp; mbp++) {
                    653:                                *obp++ = *mbp & TRIM;
                    654:                                if (--ocnt == 0) {
                    655:                                        write(0, obuf, BUFSIZ);
                    656:                                        obp = obuf; ocnt = BUFSIZ;
                    657:                                }
                    658:                        }
                    659:                        *obp++ = '\n';
                    660:                        if (--ocnt == 0) {
                    661:                                write(0, obuf, BUFSIZ);
                    662:                                obp = obuf; ocnt = BUFSIZ;
                    663:                        }
                    664:                }
                    665:                if (pargv)
                    666:                        blkfree(pargv), pargv = 0;
                    667:        }
                    668: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.