Annotation of researchv10dc/ncurses/screen/tic.c, revision 1.1.1.1

1.1       root        1: /*     @(#) tic.c: 1.1 10/15/83        (1.15   2/23/83)        */
                      2: 
                      3: #ifdef pdp11
                      4:        /* Has to be this small to fit, even split I/D, with several use='s */
                      5: # define CAPSIZ        2048
                      6: #else
                      7: # define CAPSIZ        4096
                      8: #endif
                      9: 
                     10: #define MAXHOP 32      /* max number of use= indirections */
                     11: 
                     12: #define COMMENT        '#'
                     13: #define SEPARATE       ','
                     14: #define NUMBER '#'
                     15: #define STRING '='
                     16: #define CANCEL '@'
                     17: 
                     18: #include <stdio.h>
                     19: #include <ctype.h>
                     20: #include <sys/types.h>
                     21: #include <sys/stat.h>
                     22: 
                     23: #include "../local/uparm.h"
                     24: #ifndef E_TERMINFO
                     25: #define E_TERMINFO "terminfo.src"
                     26: #endif
                     27: 
                     28: #ifndef termpath
                     29: #define termpath(name) "/usr/lib/terminfo/name"
                     30: #endif
                     31: 
                     32: /*
                     33:  * L_ctermid is only defined on USG.
                     34:  * We use it here since we don't include curses.h.
                     35:  */
                     36: #ifdef L_ctermid
                     37: #define index strchr
                     38: #endif
                     39: 
                     40: /*
                     41:  * compile: program to compile a source terminfo file into object files
                     42:  */
                     43: 
                     44: static char *tbuf;
                     45: static int hopcount;   /* detect infinite loops in terminfo, init 0 */
                     46: long   starttime;
                     47: int    verbose;
                     48: char   *terminfo;
                     49: char   *tskip();
                     50: char   *tgetstr();
                     51: char   *tdecode();
                     52: char   *getenv();
                     53: 
                     54: char *sourcefile = E_TERMINFO;
                     55: 
                     56: main(argc, argv)
                     57: char **argv;
                     58: {
                     59:        int i;
                     60: 
                     61:        time(&starttime);
                     62:        while (argc > 1 && argv[1][0] == '-') {
                     63:                switch(argv[1][1]) {
                     64:                case 'v':
                     65:                        if (argv[1][2])
                     66:                                verbose = argv[1][2] - '0';
                     67:                        else
                     68:                                verbose++;
                     69:                        break;
                     70:                default:
                     71:                        fprintf(stderr, "Usage: compile [-v] [files...]\n");
                     72:                        exit(1);
                     73:                }
                     74:                argc--; argv++;
                     75:        }
                     76: 
                     77:        terminfo = getenv("TERMINFO");
                     78: 
                     79:        if (argc == 1) {
                     80:                compfile(stdin, "stdin");
                     81:        }
                     82:        else for (i=1; i<argc; i++) {
                     83:                compfile(fopen(argv[i], "r"), argv[i]);
                     84:        }
                     85: }
                     86: 
                     87: /*
                     88:  * Compile a file.  This is very similar to the
                     89:  * code in tgetstr but it passes through the whole file.
                     90:  */
                     91: compfile(tf, fname)
                     92:        FILE *tf;
                     93:        char *fname;
                     94: {
                     95:        register char *cp;
                     96:        register int c;
                     97:        register int i = 0, cnt = 0;
                     98:        char bp[CAPSIZ];
                     99:        char ibuf[CAPSIZ];
                    100:        char *cp2;
                    101: 
                    102:        if (tf == NULL) {
                    103:                perror(fname);
                    104:                return (-1);
                    105:        }
                    106:        ibuf[0] = 0;
                    107:        for (;;) {
                    108:                tbuf = bp;
                    109:                strcpy(bp, ibuf);
                    110:                for (;;) {
                    111:                        if (fgets(ibuf, sizeof ibuf, tf) == NULL) {
                    112:                                fclose(tf);
                    113:                                if (tnchkuse(fname))
                    114:                                        store(bp);
                    115:                                return 0;
                    116:                        }
                    117:                        /* comment or blank line */
                    118:                        if (ibuf[0] == COMMENT || ibuf[0] == '\n')
                    119:                                continue;
                    120:                        cp = &ibuf[strlen(ibuf)-3];
                    121:                        /* Allow and ignore old style backslashes */
                    122:                        if (*cp == SEPARATE && cp[1] == '\\')
                    123:                                cp[1] = 0;
                    124:                        cp[2] = 0;      /* get rid of newline */
                    125:                        /* lines with leading white space are continuation */
                    126:                        if (!isspace(ibuf[0]) && *bp)
                    127:                                break;
                    128:                        if (strlen(bp) + strlen(ibuf) >= CAPSIZ) {
                    129:                                fprintf(stdout, "Terminfo entry too long:\n");
                    130:                                fprintf(stdout, "%s", bp);
                    131:                        }
                    132:                        else {
                    133:                                cp = ibuf;
                    134:                                while (isspace(*cp))
                    135:                                        cp++;
                    136:                                strcat(bp, cp);
                    137:                        }
                    138:                }
                    139: 
                    140:                /*
                    141:                 * We have it, now do something with it.
                    142:                 */
                    143:                if (tnchkuse(fname))
                    144:                        store(bp);
                    145:        }
                    146: }
                    147: 
                    148: /*
                    149:  * Get an entry for terminal name in buffer bp,
                    150:  * from the terminfo file.  Parse is very rudimentary;
                    151:  * we just notice escaped newlines.
                    152:  */
                    153: tgetent(bp, name, fname)
                    154:        char *bp, *name, *fname;
                    155: {
                    156:        register char *cp;
                    157:        register int c;
                    158:        register int i = 0, cnt = 0;
                    159:        char ibuf[CAPSIZ];
                    160:        char *cp2;
                    161:        FILE *tf;
                    162: 
                    163:        ibuf[0] = 0;
                    164:        tf = fopen(fname, "r");
                    165:        if (tf == NULL)
                    166:                return (-1);
                    167:        tbuf = bp;
                    168:        for (;;) {
                    169:                strcpy(bp, ibuf);
                    170:                for (;;) {
                    171:                        if (fgets(ibuf, sizeof ibuf, tf) == NULL) {
                    172:                                fclose(tf);
                    173:                                if (tnamatch(name))
                    174:                                        return(tnchkuse(fname));
                    175:                                return 0;
                    176:                        }
                    177:                        if (ibuf[0] == COMMENT) /* comment */
                    178:                                continue;
                    179:                        cp = &ibuf[strlen(ibuf)-3];
                    180:                        /* Allow and ignore old style backslashes */
                    181:                        if (*cp == SEPARATE && cp[1] == '\\')
                    182:                                cp[1] = 0;
                    183:                        cp[2] = 0;      /* get rid of newline */
                    184:                        /* lines with leading white space are continuation */
                    185:                        if (!isspace(ibuf[0]) && *bp)
                    186:                                break;
                    187:                        if (strlen(bp) + strlen(ibuf) >= CAPSIZ) {
                    188:                                fprintf(stdout, "Terminfo entry too long:\n");
                    189:                                fprintf(stdout, "%s", bp);
                    190:                        }
                    191:                        else {
                    192:                                cp = ibuf;
                    193:                                while (isspace(*cp))
                    194:                                        cp++;
                    195:                                strcat(bp, cp);
                    196:                        }
                    197:                }
                    198: 
                    199:                /*
                    200:                 * The real work for the match.
                    201:                 */
                    202:                if (tnamatch(name)) {
                    203:                        fclose(tf);
                    204:                        return(tnchkuse(fname));
                    205:                }
                    206:        }
                    207: }
                    208: 
                    209: /*
                    210:  * tnchkuse: check the last entry, see if it's use=xxx. If so,
                    211:  * recursively find xxx and append that entry (minus the names)
                    212:  * to take the place of the use=xxx entry. This allows terminfo
                    213:  * entries to say "like an HP2621 but doesn't turn on the labels".
                    214:  * Note that this works because of the left to right scan.
                    215:  */
                    216: tnchkuse(fname)
                    217: char *fname;
                    218: {
                    219:        register char *p, *q;
                    220:        char tcname[16];        /* name of similar terminal */
                    221:        char tcbuf[CAPSIZ];
                    222:        char restbuf[CAPSIZ];
                    223:        char *holdtbuf = tbuf;
                    224:        char *beg_use, *beg_next;
                    225:        char *strchr();
                    226:        int l;
                    227: 
                    228:        p = tbuf;
                    229:        if (++hopcount > MAXHOP) {
                    230:                fprintf(stdout, "Infinite use= loop '%s'\n", tbuf);
                    231:                return (0);
                    232:        }
                    233:        for (;;) {
                    234:                p = strchr(p, 'u');
                    235:                if (p == NULL) {
                    236:                        tbuf = holdtbuf;
                    237:                        return 1;
                    238:                }
                    239:                beg_use = p;
                    240:                if (*++p != 's' || *++p != 'e' || *++p != '=')
                    241:                        continue;
                    242:                strncpy(tcname, ++p, sizeof tcname);
                    243:                q = strchr(tcname, SEPARATE);
                    244:                if (q)
                    245:                        *q = 0;
                    246:                /* try local file ... */
                    247:                if (tgetent(tcbuf, tcname, fname) != 1) {
                    248:                        /* ... and master */
                    249:                        if (tgetent(tcbuf, tcname, E_TERMINFO) != 1) {
                    250:                                printf("Cannot find term %s\n", tcname);
                    251:                                return(0);
                    252:                        }
                    253:                }
                    254: 
                    255:                /* Find the end of the use= spec */
                    256:                for(beg_next=beg_use;
                    257:                    *beg_next && *beg_next!=SEPARATE;
                    258:                    beg_next++)
                    259:                        ;
                    260:                beg_next++;
                    261:                while (isspace(*beg_next++))
                    262:                        ;
                    263:                beg_next--;
                    264:                
                    265:                /* Now shuffle string around. */
                    266:                strcpy(restbuf, beg_next);
                    267:                p = strchr(tcbuf, SEPARATE);
                    268:                if (p == NULL)
                    269:                        p = tcbuf;
                    270:                else
                    271:                        p++;
                    272:                strcpy(beg_use, p);
                    273:                p = strchr(beg_use, '\0');
                    274:                strcpy(p, restbuf);
                    275:        }
                    276: }
                    277: 
                    278: /*
                    279:  * Tnamatch deals with name matching.  The first field of the terminfo
                    280:  * entry is a sequence of names separated by |'s, so we compare
                    281:  * against each such name.  The normal : terminator after the last
                    282:  * name (before the first field) stops us.
                    283:  */
                    284: tnamatch(np)
                    285:        char *np;
                    286: {
                    287:        register char *Np, *Bp;
                    288: 
                    289: /* printf("tnamatch, np '%s', tbuf '%s'\n", np, tbuf); */
                    290:        Bp = tbuf;
                    291:        if (*Bp == COMMENT)
                    292:                return(0);
                    293:        for (;;) {
                    294:                for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
                    295:                        ;
                    296:                if (*Np == 0 && (*Bp == '|' || *Bp == SEPARATE || *Bp == 0))
                    297:                        return (1);
                    298:                while (*Bp && *Bp != SEPARATE && *Bp != '|')
                    299:                        Bp++;
                    300:                if (*Bp == 0 || *Bp == SEPARATE)
                    301:                        return (0);
                    302:                Bp++;
                    303:        }
                    304: }
                    305: 
                    306: /*
                    307:  * Skip to the next SEPARATE delimited field.
                    308:  */
                    309: static char *
                    310: tskip(bp)
                    311:        register char *bp;
                    312: {
                    313: 
                    314:        while (*bp && *bp != SEPARATE)
                    315:                bp++;
                    316:        if (*bp == 0)
                    317:                return bp;
                    318:        bp++;
                    319:        while (isspace(*bp) || *bp == SEPARATE)
                    320:                bp++;
                    321:        return (bp);
                    322: }
                    323: 
                    324: /*
                    325:  * Return the (numeric) option id.
                    326:  * Numeric options look like
                    327:  *     li#80
                    328:  * i.e. the option string is separated from the numeric value by
                    329:  * a # character.  If the option is not found we return -1.
                    330:  * Note that we handle octal numbers beginning with 0.
                    331:  */
                    332: tgetnum(id)
                    333:        char *id;
                    334: {
                    335:        register int i, base;
                    336:        register char *bp = tbuf;
                    337:        int idl = strlen(id);
                    338:        int sign = 1;
                    339: 
                    340:        for (;;) {
                    341:                bp = tskip(bp);
                    342:                if (*bp == 0)
                    343:                        return (-1);
                    344:                if (strncmp(id, bp, idl))
                    345:                        continue;
                    346:                bp += idl;
                    347:                if (*bp == CANCEL)
                    348:                        return(-1);
                    349:                if (*bp != NUMBER && *bp != STRING)
                    350:                        continue;
                    351:                bp++;
                    352:                if (*bp == '-') {
                    353:                        sign = -1;
                    354:                        bp++;
                    355:                }
                    356:                base = 10;
                    357:                if (*bp == '0')
                    358:                        base = 8;
                    359:                i = 0;
                    360:                while (isdigit(*bp))
                    361:                        i *= base, i += *bp++ - '0';
                    362:                i *= sign;
                    363:                return (i);
                    364:        }
                    365: }
                    366: 
                    367: /*
                    368:  * Handle a flag option.
                    369:  * Flag options are given "naked", i.e. followed by a : or the end
                    370:  * of the buffer.  Return 1 if we find the option, or 0 if it is
                    371:  * not given.
                    372:  */
                    373: tgetflag(id)
                    374:        char *id;
                    375: {
                    376:        register char *bp = tbuf;
                    377:        int idl = strlen(id);
                    378: 
                    379:        for (;;) {
                    380:                bp = tskip(bp);
                    381:                if (!*bp)
                    382:                        return (0);
                    383:                if (strncmp(bp, id, idl) == 0) {
                    384:                        bp += idl;
                    385:                        if (!*bp || *bp == SEPARATE)
                    386:                                return (1);
                    387:                        else if (*bp == CANCEL)
                    388:                                return(0);
                    389:                }
                    390:        }
                    391: }
                    392: 
                    393: /*
                    394:  * Get a string valued option.
                    395:  * These are given as
                    396:  *     cl=^Z
                    397:  * Much decoding is done on the strings, and the strings are
                    398:  * placed in area, which is a ref parameter which is updated.
                    399:  * No checking on area overflow.
                    400:  */
                    401: char *
                    402: tgetstr(id, area)
                    403:        char *id, **area;
                    404: {
                    405:        register char *bp = tbuf;
                    406:        int idl = strlen(id);
                    407: 
                    408:        for (;;) {
                    409:                bp = tskip(bp);
                    410:                if (!*bp)
                    411:                        return (0);
                    412:                if (strncmp(id, bp, idl))
                    413:                        continue;
                    414:                bp += idl;
                    415:                if (*bp == CANCEL)
                    416:                        return(0);
                    417:                if (*bp != STRING)
                    418:                        continue;
                    419:                bp++;
                    420:                return (tdecode(bp, area));
                    421:        }
                    422: }
                    423: 
                    424: /*
                    425:  * Tdecode does the grung work to decode the
                    426:  * string capability escapes.
                    427:  */
                    428: static char *
                    429: tdecode(str, area)
                    430:        register char *str;
                    431:        char **area;
                    432: {
                    433:        register char *cp;
                    434:        register int c;
                    435:        register char *dp;
                    436:        int i;
                    437: 
                    438:        cp = *area;
                    439:        while ((c = *str++) && c != SEPARATE) {
                    440:                switch (c) {
                    441: 
                    442:                case '^':
                    443:                        c = *str++ & 037;
                    444:                        break;
                    445: 
                    446:                case '\\':
                    447:                        /*
                    448:                         * \x escapes understood:
                    449:                         *      \e      escape
                    450:                         *      \E      escape
                    451:                         *      \^      ^
                    452:                         *      \\      \
                    453:                         *      \,      ,
                    454:                         *      \:      :
                    455:                         *      \l      linefeed
                    456:                         *      \n      newline (=linefeed)
                    457:                         *      \r      return
                    458:                         *      \t      tab
                    459:                         *      \b      backspace
                    460:                         *      \f      formfeed
                    461:                         *      \s      space
                    462:                         *      \0      null
                    463:                         *      \###    octal ###
                    464:                         */
                    465:                        dp = "e\033E\033^^\\\\,,::l\012n\nr\rt\tb\bf\fs ";
                    466:                        c = *str++;
                    467: nextc:
                    468:                        if (*dp++ == c) {
                    469:                                c = *dp++;
                    470:                                break;
                    471:                        }
                    472:                        dp++;
                    473:                        if (*dp)
                    474:                                goto nextc;
                    475:                        if (isdigit(c)) {
                    476:                                c -= '0', i = 2;
                    477:                                do {
                    478:                                        if (!isdigit(*str))
                    479:                                                break;
                    480:                                        c <<= 3;
                    481:                                        c |= *str++ - '0';
                    482:                                } while (--i);
                    483:                                if (c == 0)
                    484:                                        c = 0200;       /* don't term. str. */
                    485:                        }
                    486:                        break;
                    487:                }
                    488:                *cp++ = c;
                    489:        }
                    490:        *cp++ = 0;
                    491:        str = *area;
                    492:        *area = cp;
                    493:        return (str);
                    494: }
                    495: 
                    496: extern char *boolnames[], *numnames[], *strnames[];
                    497: extern char *boolcodes[], *numcodes[], *strcodes[];
                    498: 
                    499: char *malloc();
                    500: char *tgetstr();
                    501: 
                    502: #define TIMAGNUM 0432
                    503: 
                    504: store(cap)
                    505: char *cap;
                    506: {
                    507:        register char *cp;
                    508:        register int i;
                    509:        register char **pp, **np;
                    510:        char tcpbuf[1024];
                    511:        char *tcp = tcpbuf;
                    512:        char *tname = cap;
                    513:        char *tnp;
                    514:        char tnbuf[256], names[256];
                    515:        char fnbuf[64], lnbuf[64];
                    516:        char strtab[4096];
                    517:        register char *strtabptr;
                    518:        FILE *fd;
                    519:        int sname, sbool;
                    520: 
                    521:        while (*cap != SEPARATE)        /* skip over names */
                    522:                cap++;
                    523:        *cap = 0;
                    524:        strcpy(tnbuf, tname);
                    525:        strcpy(names, tname);
                    526:        *cap = SEPARATE;
                    527: 
                    528:        for (tnp=tnbuf; *tnp && *tnp != '|' && *tnp != SEPARATE; tnp++)
                    529:                ;
                    530:        if (*tnp)
                    531:                *tnp++ = 0;
                    532:        if (terminfo) {
                    533:                strcpy(fnbuf, terminfo);
                    534:                strcat(fnbuf, "/");
                    535:        } else {
                    536:                strcpy(fnbuf, termpath(/));
                    537:        }
                    538:        strcat(fnbuf, tnbuf);
                    539:        checkon(fnbuf);
                    540:        if (verbose)
                    541:                printf("create '%s'\n", fnbuf);
                    542:        fd = fopen(fnbuf, "w");
                    543:        if (fd == NULL) {
                    544:                perror(fnbuf);
                    545:                return;
                    546:        }
                    547: 
                    548:        putsh(TIMAGNUM, fd);
                    549:        sname = strlen(names)+1;
                    550:        putsh(sname, fd);
                    551:        sbool = listlen(boolcodes);
                    552:        putsh(sbool, fd);
                    553:        putsh(listlen(numcodes), fd);
                    554:        putsh(listlen(strcodes), fd);
                    555:        putsh(0, fd);                   /* length of string table */
                    556: 
                    557:        /* Write out various terminal names to file, null terminated. */
                    558:        for (cp=names; *cp; cp++)
                    559:                putc(*cp, fd);
                    560:        putc(0, fd);
                    561: 
                    562:        /* Write out the booleans: flag */
                    563:        for (pp=boolnames, np=boolcodes; *np; pp++,np++) {
                    564:                i = tgetflag(*pp);
                    565:                putc(i, fd);
                    566:                if (verbose > 2)
                    567:                        printf("bool cap %s code %s val %d\n", *pp, *np, i);
                    568:        }
                    569:        if ((sname + sbool) & 1)
                    570:                putc(0, fd);
                    571: 
                    572:        /* Numbers: highbyte, lowbyte.  0377,0377 means -1 (missing) */
                    573:        for (pp=numnames, np=numcodes;   *np; pp++,np++) {
                    574:                i = tgetnum(*pp);
                    575:                putsh(i, fd);
                    576:                if (verbose > 1)
                    577:                        printf("num cap %s code %s val %d\n", *pp, *np, i);
                    578:        }
                    579: 
                    580:        /* Strings: offset into string table.  If cap is missing, -1 is used */
                    581:        strtabptr = strtab;
                    582:        for (pp=strnames, np=strcodes;   *np; pp++,np++) {
                    583:                cp = tgetstr(*pp, &tcp);
                    584:                if (verbose > 3)
                    585:                        if (cp)
                    586:                                printf("str %s code %s val %s\n", *pp, *np, cp);
                    587:                        else
                    588:                                printf("str %s code %s val NULL\n", *pp, *np);
                    589:                if (cp) {
                    590:                        putsh(strtabptr-strtab, fd);
                    591:                        while (*strtabptr++ = *cp++)
                    592:                                ;
                    593:                } else {
                    594:                        putsh(-1, fd);
                    595:                }
                    596:        }
                    597:        fwrite(strtab, 1, strtabptr-strtab, fd);
                    598:        fseek(fd, 10L, 0);      /* Back to string table size in header */
                    599:        putsh(strtabptr-strtab, fd);
                    600:        fclose(fd);
                    601:        hopcount = 0;
                    602: 
                    603:        while (*tnp) {
                    604:                i = 0;
                    605:                for (tname=tnp; *tnp && *tnp != '|' && *tnp != SEPARATE; tnp++)
                    606:                        if (isspace(*tnp))
                    607:                                i = 1;
                    608:                if (*tnp)
                    609:                        *tnp++ = 0;
                    610:                if (i)
                    611:                        continue;
                    612:                if (terminfo) {
                    613:                        strcpy(lnbuf, terminfo);
                    614:                        strcat(lnbuf, "/");
                    615:                } else {
                    616:                        strcpy(lnbuf, termpath(/));
                    617:                }
                    618:                strcat(lnbuf, tname);
                    619:                checkon(lnbuf);
                    620:                link(fnbuf, lnbuf);
                    621:                if (verbose)
                    622:                        printf("link '%s' '%s'\n", fnbuf, lnbuf);
                    623:        }
                    624: }
                    625: 
                    626: /*
                    627:  * Write a short out to the file in machine-independent format.
                    628:  */
                    629: putsh(val, fd)
                    630: register val;
                    631: FILE *fd;
                    632: {
                    633:        if (val != -1) {
                    634:                putc(val&0377, fd);
                    635:                putc((val>>8)&0377, fd);
                    636:        } else {
                    637:                /* Write -1 as two 0377's. */
                    638:                putc(0377, fd);
                    639:                putc(0377, fd);
                    640:        }
                    641: }
                    642: 
                    643: listlen(list)
                    644: register char **list;
                    645: {
                    646:        register int rv = 0;
                    647: 
                    648:        while (*list) {
                    649:                list++;
                    650:                rv++;
                    651:        }
                    652:        return rv;
                    653: }
                    654: 
                    655: /*
                    656:  * Do various processing on a file name we are about to create.
                    657:  * If it already exists, and it's older than we started, unlink it.
                    658:  * Also insert a / after the 2nd char of the tail, and make sure
                    659:  * that directory exists.
                    660:  */
                    661: checkon(fn)
                    662: char *fn;
                    663: {
                    664:        struct stat stbuf;
                    665:        char *fp, *cp;
                    666:        char nbuf[64];
                    667:        char cmdbuf[64];
                    668: 
                    669:        /* Find last / */
                    670:        for (cp=fn; *cp; cp++)
                    671:                if (*cp == '/')
                    672:                        fp = cp;
                    673:        if (cp-fp > 2) {
                    674:                cp = fp+2;
                    675:                strcpy(nbuf, fp+1);
                    676:                *cp = 0;
                    677:                if (stat(fn, &stbuf) < 0) {
                    678:                        sprintf(cmdbuf, "mkdir %s", fn);
                    679:                        if (verbose)
                    680:                                printf("%s\n", cmdbuf);
                    681:                        system(cmdbuf);
                    682:                }
                    683:                *cp++ = '/';
                    684:                strcpy(cp, nbuf);
                    685:        }
                    686:        else
                    687:                printf("%s: terminal name too short\n", fp+1);
                    688:        if (stat(fn, &stbuf) < 0)
                    689:                return;
                    690:        if (stbuf.st_mtime < starttime) {
                    691:                if (verbose > 1)
                    692:                        printf("unlink %s\n", fn);
                    693:                unlink(fn);
                    694:        }
                    695: }

unix.superglobalmegacorp.com

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