Annotation of 41BSD/cmd/csh/sh.dol.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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