Annotation of cci/usr/src/ucb/gprof/gprof.c, revision 1.1.1.2

1.1       root        1: #ifndef lint
                      2:     static     char *sccsid = "@(#)gprof.c     1.1 (Tahoe) 3/21/85";
                      3: #endif lint
                      4: 
                      5: #include "gprof.h"
                      6: 
                      7: char   *whoami = "gprof";
                      8: 
                      9:     /*
                     10:      * things which get -E excluded by default.
                     11:      */
                     12: char   *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
                     13: 
                     14: main(argc, argv)
                     15:     int argc;
                     16:     char **argv;
                     17: {
                     18:     char       **sp;
                     19: 
                     20:     --argc;
                     21:     argv++;
                     22:     debug = 0;
                     23:     bflag = TRUE;
                     24:     while ( *argv != 0 && **argv == '-' ) {
                     25:        (*argv)++;
                     26:        switch ( **argv ) {
                     27:        case 'a':
                     28:            aflag = TRUE;
                     29:            break;
                     30:        case 'b':
                     31:            bflag = FALSE;
                     32:            break;
                     33:        case 'c':
                     34:            cflag = TRUE;
                     35:            break;
                     36:        case 'd':
                     37:            dflag = TRUE;
                     38:            (*argv)++;
                     39:            debug |= atoi( *argv );
                     40:            debug |= ANYDEBUG;
                     41: #          ifdef DEBUG
                     42:                printf("[main] debug = %d\n", debug);
                     43: #          else not DEBUG
                     44:                printf("%s: -d ignored\n", whoami);
                     45: #          endif DEBUG
                     46:            break;
                     47:        case 'E':
                     48:            ++argv;
                     49:            addlist( Elist , *argv );
                     50:            Eflag = TRUE;
                     51:            addlist( elist , *argv );
                     52:            eflag = TRUE;
                     53:            break;
                     54:        case 'e':
                     55:            addlist( elist , *++argv );
                     56:            eflag = TRUE;
                     57:            break;
                     58:        case 'F':
                     59:            ++argv;
                     60:            addlist( Flist , *argv );
                     61:            Fflag = TRUE;
                     62:            addlist( flist , *argv );
                     63:            fflag = TRUE;
                     64:            break;
                     65:        case 'f':
                     66:            addlist( flist , *++argv );
                     67:            fflag = TRUE;
                     68:            break;
1.1.1.2 ! root       69:        case 'm':
        !            70:            mflag = TRUE;
        !            71:            break;
1.1       root       72:        case 's':
                     73:            sflag = TRUE;
                     74:            break;
                     75:        case 'z':
                     76:            zflag = TRUE;
                     77:            break;
                     78:        }
                     79:        argv++;
                     80:     }
                     81:     if ( *argv != 0 ) {
                     82:        a_outname  = *argv;
                     83:        argv++;
                     84:     } else {
                     85:        a_outname  = A_OUTNAME;
                     86:     }
                     87:     if ( *argv != 0 ) {
                     88:        gmonname = *argv;
                     89:        argv++;
                     90:     } else {
                     91:        gmonname = GMONNAME;
                     92:     }
                     93:        /*
                     94:         *      turn off default functions
                     95:         */
                     96:     for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
                     97:        Eflag = TRUE;
                     98:        addlist( Elist , *sp );
                     99:        eflag = TRUE;
                    100:        addlist( elist , *sp );
                    101:     }
                    102:        /*
                    103:         *      how long is a clock tick?
                    104:         */
                    105:     hz = hertz();
                    106:        /*
                    107:         *      get information about a.out file.
                    108:         */
                    109:     getnfile();
                    110:        /*
                    111:         *      get information about mon.out file(s).
                    112:         */
                    113:     do {
                    114:        getpfile( gmonname );
                    115:        if ( *argv != 0 ) {
                    116:            gmonname = *argv;
                    117:        }
                    118:     } while ( *argv++ != 0 );
                    119:        /*
                    120:         *      dump out a gmon.sum file if requested
                    121:         */
                    122:     if ( sflag ) {
                    123:        dumpsum( GMONSUM );
                    124:     }
                    125:        /*
                    126:         *      assign samples to procedures
                    127:         */
                    128:     asgnsamples();
                    129:        /*
                    130:         *      print the usual profile
                    131:         */
                    132:     printprof();       
                    133:        /*
                    134:         *      assemble and print the dynamic profile
                    135:         */
                    136:     doarcs();
1.1.1.2 ! root      137:        /*
        !           138:         *      Build a memory histogram
        !           139:         */
        !           140:     if (mflag)
        !           141:       print_mem_hist();
1.1       root      142:     done();
                    143: }
                    144: 
                    145:     /*
                    146:      * Set up string and symbol tables from a.out.
                    147:      * and optionally the text space.
                    148:      * On return symbol table is sorted by value.
                    149:      */
                    150: getnfile()
                    151: {
                    152:     FILE       *nfile;
                    153: 
                    154:     nfile = fopen( a_outname ,"r");
                    155:     if (nfile == NULL) {
                    156:        perror( a_outname );
                    157:        done();
                    158:     }
                    159:     fread(&xbuf, 1, sizeof(xbuf), nfile);
                    160:     if (N_BADMAG(xbuf)) {
                    161:        fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
                    162:        done();
                    163:     }
                    164:     getstrtab(nfile);
                    165:     getsymtab(nfile);
                    166:     gettextspace( nfile );
                    167:     qsort(nl, nname, sizeof(nltype), valcmp);
                    168:     fclose(nfile);
                    169: #   ifdef DEBUG
                    170:        if ( debug & AOUTDEBUG ) {
                    171:            register int j;
                    172: 
                    173:            for (j = 0; j < nname; j++){
                    174:                printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
                    175:            }
                    176:        }
                    177: #   endif DEBUG
                    178: }
                    179: 
                    180: getstrtab(nfile)
                    181:     FILE       *nfile;
                    182: {
                    183: 
                    184:     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
                    185:     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
                    186:        fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
                    187:                whoami , a_outname );
                    188:        done();
                    189:     }
                    190:     strtab = (char *)calloc(ssiz, 1);
                    191:     if (strtab == NULL) {
                    192:        fprintf(stderr, "%s: %s: no room for %d bytes of string table",
                    193:                whoami , a_outname , ssiz);
                    194:        done();
                    195:     }
                    196:     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
                    197:        fprintf(stderr, "%s: %s: error reading string table\n",
                    198:                whoami , a_outname );
                    199:        done();
                    200:     }
                    201: }
                    202: 
                    203:     /*
                    204:      * Read in symbol table
                    205:      */
                    206: getsymtab(nfile)
                    207:     FILE       *nfile;
                    208: {
                    209:     register long      i;
                    210:     int                        askfor;
                    211:     struct nlist       nbuf;
                    212: 
                    213:     /* pass1 - count symbols */
                    214:     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
                    215:     nname = 0;
                    216:     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
                    217:        fread(&nbuf, sizeof(nbuf), 1, nfile);
                    218:        if ( ! funcsymbol( &nbuf ) ) {
                    219:            continue;
                    220:        }
                    221:        nname++;
                    222:     }
                    223:     if (nname == 0) {
                    224:        fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
                    225:        done();
                    226:     }
                    227:     askfor = nname + 1;
                    228:     nl = (nltype *) calloc( askfor , sizeof(nltype) );
                    229:     if (nl == 0) {
                    230:        fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
                    231:                whoami, askfor * sizeof(nltype) );
                    232:        done();
                    233:     }
                    234: 
                    235:     /* pass2 - read symbols */
                    236:     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
                    237:     npe = nl;
                    238:     nname = 0;
                    239:     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
                    240:        fread(&nbuf, sizeof(nbuf), 1, nfile);
                    241:        if ( ! funcsymbol( &nbuf ) ) {
                    242: #          ifdef DEBUG
                    243:                if ( debug & AOUTDEBUG ) {
                    244:                    printf( "[getsymtab] rejecting: 0x%x %s\n" ,
                    245:                            nbuf.n_type , strtab + nbuf.n_un.n_strx );
                    246:                }
                    247: #          endif DEBUG
                    248:            continue;
                    249:        }
                    250:        npe->value = nbuf.n_value;
                    251:        npe->name = strtab+nbuf.n_un.n_strx;
                    252: #      ifdef DEBUG
                    253:            if ( debug & AOUTDEBUG ) {
                    254:                printf( "[getsymtab] %d %s 0x%08x\n" ,
                    255:                        nname , npe -> name , npe -> value );
                    256:            }
                    257: #      endif DEBUG
                    258:        npe++;
                    259:        nname++;
                    260:     }
                    261:     npe->value = -1;
                    262: }
                    263: 
                    264:     /*
                    265:      * read in the text space of an a.out file
                    266:      */
                    267: gettextspace( nfile )
                    268:     FILE       *nfile;
                    269: {
                    270:     unsigned char      *malloc();
                    271:     
                    272:     if ( cflag == 0 ) {
                    273:        return;
                    274:     }
                    275:     textspace = malloc( xbuf.a_text );
                    276:     if ( textspace == 0 ) {
                    277:        fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
                    278:                        whoami , xbuf.a_text );
                    279:        fprintf( stderr , "can't do -c\n" );
                    280:        return;
                    281:     }
                    282:     (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
                    283:     if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
                    284:        fprintf( stderr , "%s: couldn't read text space:  " , whoami );
                    285:        fprintf( stderr , "can't do -c\n" );
                    286:        free( textspace );
                    287:        textspace = 0;
                    288:        return;
                    289:     }
                    290: }
                    291:     /*
                    292:      * information from a gmon.out file is in two parts:
                    293:      * an array of sampling hits within pc ranges,
                    294:      * and the arcs.
                    295:      */
                    296: getpfile(filename)
                    297:     char *filename;
                    298: {
                    299:     FILE               *pfile;
                    300:     FILE               *openpfile();
                    301:     struct rawarc      arc;
                    302: 
                    303:     pfile = openpfile(filename);
                    304:     readsamples(pfile);
                    305:        /*
                    306:         *      the rest of the file consists of
                    307:         *      a bunch of <from,self,count> tuples.
                    308:         */
                    309:     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
                    310: #      ifdef DEBUG
                    311:            if ( debug & SAMPLEDEBUG ) {
                    312:                printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
                    313:                        arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
                    314:            }
                    315: #      endif DEBUG
                    316:            /*
                    317:             *  add this arc
                    318:             */
                    319:        tally( &arc );
                    320:     }
                    321:     fclose(pfile);
                    322: }
                    323: 
                    324: FILE *
                    325: openpfile(filename)
                    326:     char *filename;
                    327: {
                    328:     struct hdr tmp;
                    329:     FILE       *pfile;
                    330: 
                    331:     if((pfile = fopen(filename, "r")) == NULL) {
                    332:        perror(filename);
                    333:        done();
                    334:     }
                    335:     fread(&tmp, sizeof(struct hdr), 1, pfile);
                    336:     if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
                    337:         tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
                    338:        fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
                    339:        done();
                    340:     }
                    341:     h = tmp;
                    342:     s_lowpc = (unsigned long) h.lowpc;
                    343:     s_highpc = (unsigned long) h.highpc;
                    344:     lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
                    345:     highpc = (unsigned long)h.highpc / sizeof(UNIT);
                    346:     sampbytes = h.ncnt - sizeof(struct hdr);
                    347:     nsamples = sampbytes / sizeof (unsigned UNIT);
                    348: #   ifdef DEBUG
                    349:        if ( debug & SAMPLEDEBUG ) {
                    350:            printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
                    351:                h.lowpc , h.highpc , h.ncnt );
                    352:            printf( "[openpfile]   s_lowpc 0x%x   s_highpc 0x%x\n" ,
                    353:                s_lowpc , s_highpc );
                    354:            printf( "[openpfile]     lowpc 0x%x     highpc 0x%x\n" ,
                    355:                lowpc , highpc );
                    356:            printf( "[openpfile] sampbytes %d nsamples %d\n" ,
                    357:                sampbytes , nsamples );
                    358:        }
                    359: #   endif DEBUG
                    360:     return(pfile);
                    361: }
                    362: 
                    363: tally( rawp )
                    364:     struct rawarc      *rawp;
                    365: {
                    366:     nltype             *parentp;
                    367:     nltype             *childp;
                    368: 
                    369:     parentp = nllookup( rawp -> raw_frompc );
                    370:     childp = nllookup( rawp -> raw_selfpc );
                    371:     childp -> ncall += rawp -> raw_count;
                    372: #   ifdef DEBUG
                    373:        if ( debug & TALLYDEBUG ) {
                    374:            printf( "[tally] arc from %s to %s traversed %d times\n" ,
                    375:                    parentp -> name , childp -> name , rawp -> raw_count );
                    376:        }
                    377: #   endif DEBUG
                    378:     addarc( parentp , childp , rawp -> raw_count );
                    379: }
                    380: 
                    381: /*
                    382:  * dump out the gmon.sum file
                    383:  */
                    384: dumpsum( sumfile )
                    385:     char *sumfile;
                    386: {
                    387:     register nltype *nlp;
                    388:     register arctype *arcp;
                    389:     struct rawarc arc;
                    390:     FILE *sfile;
                    391: 
                    392:     if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
                    393:        perror( sumfile );
                    394:        done();
                    395:     }
                    396:     /*
                    397:      * dump the header; use the last header read in
                    398:      */
                    399:     if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
                    400:        perror( sumfile );
                    401:        done();
                    402:     }
                    403:     /*
                    404:      * dump the samples
                    405:      */
                    406:     if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) {
                    407:        perror( sumfile );
                    408:        done();
                    409:     }
                    410:     /*
                    411:      * dump the normalized raw arc information
                    412:      */
                    413:     for ( nlp = nl ; nlp < npe ; nlp++ ) {
                    414:        for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
                    415:            arc.raw_frompc = arcp -> arc_parentp -> value;
                    416:            arc.raw_selfpc = arcp -> arc_childp -> value;
                    417:            arc.raw_count = arcp -> arc_count;
                    418:            if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
                    419:                perror( sumfile );
                    420:                done();
                    421:            }
                    422: #          ifdef DEBUG
                    423:                if ( debug & SAMPLEDEBUG ) {
                    424:                    printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
                    425:                            arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
                    426:                }
                    427: #          endif DEBUG
                    428:        }
                    429:     }
                    430:     fclose( sfile );
                    431: }
                    432: 
                    433: valcmp(p1, p2)
                    434:     nltype *p1, *p2;
                    435: {
                    436:     if ( p1 -> value < p2 -> value ) {
                    437:        return LESSTHAN;
                    438:     }
                    439:     if ( p1 -> value > p2 -> value ) {
                    440:        return GREATERTHAN;
                    441:     }
                    442:     return EQUALTO;
                    443: }
                    444: 
                    445: readsamples(pfile)
                    446:     FILE       *pfile;
                    447: {
                    448:     register i;
                    449:     unsigned UNIT      sample;
                    450:     
                    451:     if (samples == 0) {
                    452:        samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
                    453:        if (samples == 0) {
                    454:            fprintf( stderr , "%s: No room for %d sample pc's\n", 
                    455:                whoami , sampbytes / sizeof (unsigned UNIT));
                    456:            done();
                    457:        }
                    458:     }
                    459:     for (i = 0; i < nsamples; i++) {
                    460:        fread(&sample, sizeof (unsigned UNIT), 1, pfile);
                    461:        if (feof(pfile))
                    462:                break;
                    463:        samples[i] += sample;
                    464:     }
                    465:     if (i != nsamples) {
                    466:        fprintf(stderr,
                    467:            "%s: unexpected EOF after reading %d/%d samples\n",
                    468:                whoami , --i , nsamples );
                    469:        done();
                    470:     }
                    471: }
                    472: 
                    473: /*
                    474:  *     Assign samples to the procedures to which they belong.
                    475:  *
                    476:  *     There are three cases as to where pcl and pch can be
                    477:  *     with respect to the routine entry addresses svalue0 and svalue1
                    478:  *     as shown in the following diagram.  overlap computes the
                    479:  *     distance between the arrows, the fraction of the sample
                    480:  *     that is to be credited to the routine which starts at svalue0.
                    481:  *
                    482:  *         svalue0                                         svalue1
                    483:  *            |                                               |
                    484:  *            v                                               v
                    485:  *
                    486:  *            +-----------------------------------------------+
                    487:  *            |                                               |
                    488:  *       |  ->|    |<-         ->|         |<-         ->|    |<-  |
                    489:  *       |         |             |         |             |         |
                    490:  *       +---------+             +---------+             +---------+
                    491:  *
                    492:  *       ^         ^             ^         ^             ^         ^
                    493:  *       |         |             |         |             |         |
                    494:  *      pcl       pch           pcl       pch           pcl       pch
                    495:  *
                    496:  *     For the vax we assert that samples will never fall in the first
                    497:  *     two bytes of any routine, since that is the entry mask,
                    498:  *     thus we give call alignentries() to adjust the entry points if
                    499:  *     the entry mask falls in one bucket but the code for the routine
                    500:  *     doesn't start until the next bucket.  In conjunction with the
                    501:  *     alignment of routine addresses, this should allow us to have
                    502:  *     only one sample for every four bytes of text space and never
                    503:  *     have any overlap (the two end cases, above).
                    504:  */
                    505: asgnsamples()
                    506: {
                    507:     register int       j;
                    508:     unsigned UNIT      ccnt;
                    509:     double             time;
                    510:     unsigned long      pcl, pch;
                    511:     register int       i;
                    512:     unsigned long      overlap;
                    513:     unsigned long      svalue0, svalue1;
                    514: 
                    515:     /* read samples and assign to namelist symbols */
                    516:     scale = highpc - lowpc;
1.1.1.2 ! root      517:    /*  scale /= nsamples;      */
        !           518:     scale = (int)((scale/nsamples)+0.9);
1.1       root      519:     alignentries();
                    520:     for (i = 0, j = 1; i < nsamples; i++) {
                    521:        ccnt = samples[i];
                    522:        if (ccnt == 0)
                    523:                continue;
                    524:        pcl = lowpc + scale * i;
                    525:        pch = lowpc + scale * (i + 1);
                    526:        time = ccnt;
                    527: #      ifdef DEBUG
                    528:            if ( debug & SAMPLEDEBUG ) {
                    529:                printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
                    530:                        pcl , pch , ccnt );
                    531:            }
                    532: #      endif DEBUG
                    533:        totime += time;
                    534:        for (j = j - 1; j < nname; j++) {
                    535:            svalue0 = nl[j].svalue;
                    536:            svalue1 = nl[j+1].svalue;
                    537:                /*
                    538:                 *      if high end of tick is below entry address, 
                    539:                 *      go for next tick.
                    540:                 */
                    541:            if (pch < svalue0)
                    542:                    break;
                    543:                /*
                    544:                 *      if low end of tick into next routine,
                    545:                 *      go for next routine.
                    546:                 */
                    547:            if (pcl >= svalue1)
                    548:                    continue;
                    549:            overlap = min(pch, svalue1) - max(pcl, svalue0);
                    550:            if (overlap > 0) {
                    551: #              ifdef DEBUG
                    552:                    if (debug & SAMPLEDEBUG) {
                    553:                        printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
                    554:                                nl[j].value/sizeof(UNIT), svalue0, svalue1,
                    555:                                nl[j].name, 
                    556:                                overlap * time / scale, overlap);
                    557:                    }
                    558: #              endif DEBUG
                    559:                nl[j].time += overlap * time / scale;
                    560:            }
                    561:        }
                    562:     }
                    563: #   ifdef DEBUG
                    564:        if (debug & SAMPLEDEBUG) {
                    565:            printf("[asgnsamples] totime %f\n", totime);
                    566:        }
                    567: #   endif DEBUG
                    568: }
                    569: 
                    570: 
                    571: unsigned long
                    572: min(a, b)
                    573:     unsigned long a,b;
                    574: {
                    575:     if (a<b)
                    576:        return(a);
                    577:     return(b);
                    578: }
                    579: 
                    580: unsigned long
                    581: max(a, b)
                    582:     unsigned long a,b;
                    583: {
                    584:     if (a>b)
                    585:        return(a);
                    586:     return(b);
                    587: }
                    588: 
                    589:     /*
                    590:      * calculate scaled entry point addresses (to save time in asgnsamples),
                    591:      * and possibly push the scaled entry points over the entry mask,
                    592:      * if it turns out that the entry point is in one bucket and the code
                    593:      * for a routine is in the next bucket.
                    594:      */
                    595: alignentries()
                    596: {
                    597:     register struct nl *nlp;
                    598:     unsigned long      bucket_of_entry;
                    599:     unsigned long      bucket_of_code;
                    600: 
                    601:     for (nlp = nl; nlp < npe; nlp++) {
                    602:        nlp -> svalue = nlp -> value / sizeof(UNIT);
                    603:        bucket_of_entry = (nlp->svalue - lowpc) / scale;
                    604:        bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
                    605:        if (bucket_of_entry < bucket_of_code) {
                    606: #          ifdef DEBUG
                    607:                if (debug & SAMPLEDEBUG) {
                    608:                    printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
                    609:                            nlp->svalue, nlp->svalue + UNITS_TO_CODE);
                    610:                }
                    611: #          endif DEBUG
                    612:            nlp->svalue += UNITS_TO_CODE;
                    613:        }
                    614:     }
                    615: }
                    616: 
                    617: bool
                    618: funcsymbol( nlistp )
                    619:     struct nlist       *nlistp;
                    620: {
                    621:     extern char        *strtab;        /* string table from a.out */
                    622:     extern int aflag;          /* if static functions aren't desired */
                    623:     char       *name;
                    624: 
                    625:        /*
                    626:         *      must be a text symbol,
                    627:         *      and static text symbols don't qualify if aflag set.
                    628:         */
                    629:     if ( ! (  ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
                    630:           || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
                    631:        return FALSE;
                    632:     }
                    633:        /*
                    634:         *      can't have any `funny' characters in name,
                    635:         *      where `funny' includes  `.', .o file names
                    636:         *                      and     `$', pascal labels.
                    637:         */
                    638:     for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
                    639:        if ( *name == '.' || *name == '$' ) {
                    640:            return FALSE;
                    641:        }
                    642:     }
                    643:     return TRUE;
                    644: }
                    645: 
                    646: done()
                    647: {
                    648: 
                    649:     exit(0);
                    650: }

unix.superglobalmegacorp.com

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