Annotation of 3BSD/cmd/ls/ucbls.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) 1979 Regents of the University of California */
                      2: #
                      3: /*
                      4:  * ls - list file or directory
                      5:  *
                      6:  * Modified by Bill Joy UCB May/August 1977
                      7:  *
                      8:  * This version of ls is designed for graphic terminals and to
                      9:  * list directories with lots of files in them compactly.
                     10:  * It supports three variants for listings:
                     11:  *
                     12:  *     1) Columnar output.
                     13:  *     2) Stream output.
                     14:  *     3) Old one per line format.
                     15:  *
                     16:  * Columnar output is the default.
                     17:  * If, however, the standard output is not a teletype, the default
                     18:  * is one-per-line.
                     19:  *
                     20:  * With columnar output, the items are sorted down the columns.
                     21:  * We use columns only for a directory we are interpreting.
                     22:  * Thus, in particular, we do not use columns for
                     23:  *
                     24:  *     ls /usr/bin/p*
                     25:  *
                     26:  * This version of ls also prints non-printing characters as '?' if
                     27:  * the standard output is a teletype.
                     28:  *
                     29:  * Flags relating to these and other new features are:
                     30:  *
                     31:  *     -m      force stream output.
                     32:  *
                     33:  *     -1      force one entry per line, e.g. to a teletype
                     34:  *
                     35:  *     -q      force non-printings to be '?'s, e.g. to a file
                     36:  *
                     37:  *     -c      force columnar output, e.g. into a file
                     38:  *
                     39:  *     -n      like -l, but user/group id's in decimal rather than
                     40:  *             looking in /etc/passwd to save time
                     41:  */
                     42: 
                     43: #include <sys/param.h>
                     44: #include <sys/stat.h>
                     45: #include <sys/dir.h>
                     46: #include <stdio.h>
                     47: #include <ctype.h>
                     48: 
                     49: 
                     50: #define        NFILES  1024
                     51: FILE   *pwdf, *dirf;
                     52: 
                     53: struct lbuf {
                     54:        union {
                     55:                char    lname[15];
                     56:                char    *namep;
                     57:        } ln;
                     58:        char    ltype;
                     59:        short   lnum;
                     60:        short   lflags;
                     61:        short   lnl;
                     62:        short   luid;
                     63:        short   lgid;
                     64:        long    lsize;
                     65:        long    lmtime;
                     66: };
                     67: 
                     68: int    aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg;
                     69: int    Aflg, nflg, qflg, across;
                     70: int    nopad;
                     71: char   buff[32];
                     72: int    rflg    = 1;
                     73: long   year;
                     74: int    flags;
                     75: int    lastuid = -1;
                     76: char   tbuf[16];
                     77: long   tblocks;
                     78: int    statreq;
                     79: struct lbuf    *flist[NFILES];
                     80: struct lbuf    **lastp = flist;
                     81: struct lbuf    **firstp = flist;
                     82: char   *dotp   = ".";
                     83: 
                     84: char   *makename();
                     85: struct lbuf *gstat();
                     86: char   *ctime();
                     87: long   nblock();
                     88: 
                     89: #define        ISARG   0100000
                     90: int    colwidth = 15;
                     91: int    outcol;
                     92: 
                     93: char   obuf[BUFSIZ];
                     94: 
                     95: main(argc, argv)
                     96: char *argv[];
                     97: {
                     98:        int i;
                     99:        register struct lbuf *ep, **ep1;
                    100:        register struct lbuf **slastp;
                    101:        struct lbuf **epp;
                    102:        struct lbuf lb;
                    103:        char *t;
                    104:        char *cp;
                    105:        int compar();
                    106: 
                    107:        Aflg = getuid() == 0;
                    108:        setbuf(stdout, obuf);
                    109:        time(&lb.lmtime);
                    110:        year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */
                    111:        qflg = gtty(1, buff) == 0;
                    112:        /*
                    113:         * If the standard output is not a teletype,
                    114:         * then we default to one-per-line format
                    115:         * otherwise decide between stream and
                    116:         * columnar based on our name.
                    117:         */
                    118:        if (qflg) {
                    119:                cflg = 1;
                    120:                for (cp = argv[0]; cp[0] && cp[1]; cp++)
                    121:                        continue;
                    122:                /*
                    123:                 * Name ends in l => stream
                    124:                 */
                    125:                if (cp[0] == 'l')
                    126:                        nopad = 1, cflg = 0;
                    127:                /*
                    128:                 * ... if doesn't end in l or s ==> columns sorted across
                    129:                 *
                    130:                else if (cp[0] == 'x')
                    131:                        across = 1;
                    132:                 */
                    133:        }
                    134:        if (--argc > 0 && *argv[1] == '-') {
                    135:                argv++;
                    136:                while (*++*argv) switch (**argv) {
                    137:                /*
                    138:                 * c - force columnar output
                    139:                 */
                    140:                case 'c':
                    141:                        cflg = 1;
                    142:                        nopad = 0;
                    143:                        continue;
                    144:                /*
                    145:                 * m - force stream output
                    146:                 */
                    147:                case 'm':
                    148:                        cflg = 0;
                    149:                        nopad = 1;
                    150:                        continue;
                    151:                /*
                    152:                 * x - force sort across
                    153:                 */
                    154:                case 'x':
                    155:                        across = 1;
                    156:                        nopad = 0;
                    157:                        cflg = 1;
                    158:                        continue;
                    159:                /*
                    160:                 * q - force ?'s in output
                    161:                 */
                    162:                case 'q':
                    163:                        qflg = 1;
                    164:                        continue;
                    165:                /*
                    166:                 * 1 - force 1/line in output
                    167:                 */
                    168:                case '1':
                    169:                        cflg = 0;
                    170:                        nopad = 0;
                    171:                        continue;
                    172:                /* STANDARD FLAGS */
                    173:                case 'a':
                    174:                        aflg++;
                    175:                        continue;
                    176: 
                    177:                case 'A':
                    178:                        Aflg = !Aflg;
                    179:                        continue;
                    180: 
                    181:                case 's':
                    182:                        colwidth += 5;
                    183:                        sflg++;
                    184:                        statreq++;
                    185:                        continue;
                    186: 
                    187:                case 'd':
                    188:                        dflg++;
                    189:                        continue;
                    190: 
                    191:                /*
                    192:                 * n - don't look in password file
                    193:                 */
                    194:                case 'n':
                    195:                        nflg++;
                    196:                case 'l':
                    197:                        lflg++;
                    198:                        statreq++;
                    199:                        continue;
                    200: 
                    201:                case 'r':
                    202:                        rflg = -1;
                    203:                        continue;
                    204: 
                    205:                case 't':
                    206:                        tflg++;
                    207:                        statreq++;
                    208:                        continue;
                    209: 
                    210:                case 'u':
                    211:                        uflg++;
                    212:                        continue;
                    213: 
                    214:                case 'i':
                    215:                        colwidth += 5;
                    216:                        iflg++;
                    217:                        continue;
                    218: 
                    219:                case 'f':
                    220:                        fflg++;
                    221:                        continue;
                    222: 
                    223:                case 'g':
                    224:                        gflg++;
                    225:                        continue;
                    226: 
                    227:                default:
                    228:                        continue;
                    229:                }
                    230:                argc--;
                    231:        }
                    232:        if (fflg) {
                    233:                aflg++;
                    234:                lflg = 0;
                    235:                sflg = 0;
                    236:                tflg = 0;
                    237:                statreq = 0;
                    238:        }
                    239:        if(lflg) {
                    240:                cflg = 0;
                    241:                t = "/etc/passwd";
                    242:                if (gflg)
                    243:                        t = "/etc/group";
                    244:                nopad = 0;
                    245:                colwidth = 70;
                    246:                pwdf = fopen(t, "r");
                    247:        }
                    248:        if (argc==0) {
                    249:                argc++;
                    250:                argv = &dotp - 1;
                    251:        }
                    252:        for (i=0; i < argc; i++) {
                    253:                if ((ep = gstat(*++argv, 1))==NULL)
                    254:                        continue;
                    255:                ep->ln.namep = *argv;
                    256:                ep->lflags |= ISARG;
                    257:        }
                    258:        qsort(firstp, lastp - firstp, sizeof *lastp, compar);
                    259:        slastp = lastp;
                    260:        for (epp=firstp; epp<slastp; epp++) {
                    261:                ep = *epp;
                    262:                if (ep->ltype=='d' && dflg==0 || fflg) {
                    263:                        if (argc>1)
                    264:                                printf("\n%s:\n", ep->ln.namep);
                    265:                        lastp = slastp;
                    266:                        readdir(ep->ln.namep);
                    267:                        if (fflg==0)
                    268:                                qsort(slastp,lastp - slastp,sizeof *lastp,compar);
                    269:                        if (lflg || sflg)
                    270:                                printf("total %D", tblocks);
                    271:                        pem(slastp, lastp);
                    272:                        newline();
                    273:                } else 
                    274:                        pentry(ep);
                    275:        }
                    276:        if (outcol)
                    277:                putc('\n', stdout);
                    278:        fflush(stdout);
                    279: }
                    280: 
                    281: pem(slp, lp)
                    282:        register struct lbuf **slp, **lp;
                    283: {
                    284:        int ncols, nrows, row, col;
                    285:        register struct lbuf **ep;
                    286: 
                    287:        ncols = 80 / colwidth;
                    288:        if (ncols == 1 || cflg == 0) {
                    289:                for (ep = slp; ep < lp; ep++)
                    290:                        pentry(*ep);
                    291:                return;
                    292:        }
                    293:        if (across) {
                    294:                for (ep = slp; ep < lp; ep++)
                    295:                        pentry(*ep);
                    296:                return;
                    297:        }
                    298:        if (statreq)
                    299:                slp--;
                    300:        nrows = (lp - slp - 1) / ncols + 1;
                    301:        for (row = 0; row < nrows; row++) {
                    302:                col = row == 0 && statreq;
                    303:                for (; col < ncols; col++) {
                    304:                        ep = slp + (nrows * col) + row;
                    305:                        if (ep < lp)
                    306:                                pentry(*ep);
                    307:                }
                    308:                if (outcol)
                    309:                        printf("\n");
                    310:        }
                    311: }
                    312: 
                    313: pputchar(c)
                    314:        char c;
                    315: {
                    316: 
                    317:        switch (c) {
                    318:                case '\t':
                    319:                        outcol = (outcol + 8) &~ 7;
                    320:                        break;
                    321:                case '\n':
                    322:                        outcol = 0;
                    323:                        break;
                    324:                default:
                    325:                        if (qflg && (c < ' ' || c >= 0177))
                    326:                                c = '?';
                    327:                        outcol++;
                    328:                        break;
                    329:        }
                    330:        putc(c, stdout);
                    331: }
                    332: 
                    333: newline()
                    334: {
                    335:        if (outcol)
                    336:                putc('\n', stdout);
                    337:        outcol = 0;
                    338: }
                    339: 
                    340: column()
                    341: {
                    342: 
                    343:        if (outcol == 0)
                    344:                return;
                    345:        if (nopad) {
                    346:                putc(',', stdout);
                    347:                outcol++;
                    348:                if (outcol + colwidth + 2 > 80) {
                    349:                        putc('\n', stdout);
                    350:                        outcol = 0;
                    351:                        return;
                    352:                }
                    353:                putc(' ', stdout);
                    354:                outcol++;
                    355:                return;
                    356:        }
                    357:        if (cflg == 0) {
                    358:                putc('\n', stdout);
                    359:                return;
                    360:        }
                    361:        if ((outcol / colwidth + 2) * colwidth > 80) {
                    362:                putc('\n', stdout);
                    363:                outcol = 0;
                    364:                return;
                    365:        }
                    366:        do {
                    367:                outcol++;
                    368:                putc(' ', stdout);
                    369:        } while (outcol % colwidth);
                    370: }
                    371: 
                    372: 
                    373: getname(uid, buf)
                    374: int uid;
                    375: char buf[];
                    376: {
                    377:        int j, c, n, i;
                    378: 
                    379:        if (uid==lastuid)
                    380:                return(0);
                    381:        if(pwdf == NULL)
                    382:                return(-1);
                    383:        rewind(pwdf);
                    384:        lastuid = -1;
                    385:        do {
                    386:                i = 0;
                    387:                j = 0;
                    388:                n = 0;
                    389:                while((c=fgetc(pwdf)) != '\n') {
                    390:                        if (c==EOF)
                    391:                                return(-1);
                    392:                        if (c==':') {
                    393:                                j++;
                    394:                                c = '0';
                    395:                        }
                    396:                        if (j==0)
                    397:                                buf[i++] = c;
                    398:                        if (j==2)
                    399:                                n = n*10 + c - '0';
                    400:                }
                    401:        } while (n != uid);
                    402:        buf[i++] = '\0';
                    403:        lastuid = uid;
                    404:        return(0);
                    405: }
                    406: 
                    407: long
                    408: nblock(size)
                    409: long size;
                    410: {
                    411:        return((size+511)>>9);
                    412: }
                    413: 
                    414: int    m1[] = { 1, S_IREAD>>0, 'r', '-' };
                    415: int    m2[] = { 1, S_IWRITE>>0, 'w', '-' };
                    416: int    m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' };
                    417: int    m4[] = { 1, S_IREAD>>3, 'r', '-' };
                    418: int    m5[] = { 1, S_IWRITE>>3, 'w', '-' };
                    419: int    m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' };
                    420: int    m7[] = { 1, S_IREAD>>6, 'r', '-' };
                    421: int    m8[] = { 1, S_IWRITE>>6, 'w', '-' };
                    422: int    m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' };
                    423: 
                    424: int    *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
                    425: 
                    426: pmode(aflag)
                    427: {
                    428:        register int **mp;
                    429: 
                    430:        flags = aflag;
                    431:        for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];)
                    432:                select(*mp++);
                    433: }
                    434: 
                    435: select(pairp)
                    436: register int *pairp;
                    437: {
                    438:        register int n;
                    439: 
                    440:        n = *pairp++;
                    441:        while (--n>=0 && (flags&*pairp++)==0)
                    442:                pairp++;
                    443:        pputchar(*pairp);
                    444: }
                    445: 
                    446: char *
                    447: makename(dir, file)
                    448: char *dir, *file;
                    449: {
                    450:        static char dfile[100];
                    451:        register char *dp, *fp;
                    452:        register int i;
                    453: 
                    454:        dp = dfile;
                    455:        fp = dir;
                    456:        while (*fp)
                    457:                *dp++ = *fp++;
                    458:        *dp++ = '/';
                    459:        fp = file;
                    460:        for (i=0; i<DIRSIZ; i++)
                    461:                *dp++ = *fp++;
                    462:        *dp = 0;
                    463:        return(dfile);
                    464: }
                    465: 
                    466: readdir(dir)
                    467: char *dir;
                    468: {
                    469:        static struct direct dentry;
                    470:        register int j;
                    471:        register struct lbuf *ep;
                    472: 
                    473:        if ((dirf = fopen(dir, "r")) == NULL) {
                    474:                printf("%s unreadable\n", dir);
                    475:                return;
                    476:        }
                    477:        tblocks = 0;
                    478:        for(;;) {
                    479:                if (fread(&dentry, sizeof(dentry), 1, dirf) != 1)
                    480:                        break;
                    481:                if (dentry.d_ino==0 ||
                    482:                        aflg==0 && dentry.d_name[0]=='.' && (
                    483:                        !Aflg ||
                    484:                        dentry.d_name[1]=='\0'
                    485:                        || dentry.d_name[1]=='.' && dentry.d_name[2]=='\0'))
                    486:                        continue;
                    487:                ep = gstat(makename(dir, dentry.d_name), 0);
                    488:                if (ep==NULL)
                    489:                        continue;
                    490:                if (ep->lnum != -1)
                    491:                        ep->lnum = dentry.d_ino;
                    492:                for (j=0; j<DIRSIZ; j++)
                    493:                        ep->ln.lname[j] = dentry.d_name[j];
                    494:        }
                    495:        fclose(dirf);
                    496: }
                    497: 
                    498: struct lbuf *
                    499: gstat(file, argfl)
                    500: char *file;
                    501: {
                    502:        struct stat statb;
                    503:        register struct lbuf *rep;
                    504:        static int nomocore;
                    505: 
                    506:        if (nomocore)
                    507:                return(NULL);
                    508:        rep = (struct lbuf *)malloc(sizeof(struct lbuf));
                    509:        if (rep==NULL) {
                    510:                fprintf(stderr, "ls: out of memory\n");
                    511:                nomocore = 1;
                    512:                return(NULL);
                    513:        }
                    514:        if (lastp >= &flist[NFILES]) {
                    515:                static int msg;
                    516:                lastp--;
                    517:                if (msg==0) {
                    518:                        fprintf(stderr, "ls: too many files\n");
                    519:                        msg++;
                    520:                }
                    521:        }
                    522:        *lastp++ = rep;
                    523:        rep->lflags = 0;
                    524:        rep->lnum = 0;
                    525:        rep->ltype = '-';
                    526:        if (argfl || statreq) {
                    527:                if (stat(file, &statb)<0) {
                    528:                        printf("%s not found\n", file);
                    529:                        statb.st_ino = -1;
                    530:                        statb.st_size = 0;
                    531:                        statb.st_mode = 0;
                    532:                        if (argfl) {
                    533:                                lastp--;
                    534:                                return(0);
                    535:                        }
                    536:                }
                    537:                rep->lnum = statb.st_ino;
                    538:                rep->lsize = statb.st_size;
                    539:                switch(statb.st_mode&S_IFMT) {
                    540: 
                    541:                case S_IFDIR:
                    542:                        rep->ltype = 'd';
                    543:                        break;
                    544: 
                    545:                case S_IFBLK:
                    546:                        rep->ltype = 'b';
                    547:                        rep->lsize = statb.st_rdev;
                    548:                        break;
                    549: 
                    550:                case S_IFCHR:
                    551:                        rep->ltype = 'c';
                    552:                        rep->lsize = statb.st_rdev;
                    553:                        break;
                    554:                }
                    555:                rep->lflags = statb.st_mode & ~S_IFMT;
                    556:                rep->luid = statb.st_uid;
                    557:                rep->lgid = statb.st_gid;
                    558:                rep->lnl = statb.st_nlink;
                    559:                if(uflg)
                    560:                        rep->lmtime = statb.st_atime;
                    561:                else if (cflg)
                    562:                        rep->lmtime = statb.st_ctime;
                    563:                else
                    564:                        rep->lmtime = statb.st_mtime;
                    565:                tblocks += nblock(statb.st_size);
                    566:        }
                    567:        return(rep);
                    568: }
                    569: 
                    570: compar(pp1, pp2)
                    571: struct lbuf **pp1, **pp2;
                    572: {
                    573:        register struct lbuf *p1, *p2;
                    574: 
                    575:        p1 = *pp1;
                    576:        p2 = *pp2;
                    577:        if (dflg==0) {
                    578:                if (p1->lflags&ISARG && p1->ltype=='d') {
                    579:                        if (!(p2->lflags&ISARG && p2->ltype=='d'))
                    580:                                return(1);
                    581:                } else {
                    582:                        if (p2->lflags&ISARG && p2->ltype=='d')
                    583:                                return(-1);
                    584:                }
                    585:        }
                    586:        if (tflg) {
                    587:                if(p2->lmtime == p1->lmtime)
                    588:                        return(0);
                    589:                if(p2->lmtime > p1->lmtime)
                    590:                        return(rflg);
                    591:                return(-rflg);
                    592:        }
                    593:        return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname,
                    594:                                p2->lflags&ISARG? p2->ln.namep: p2->ln.lname));
                    595: }
                    596: pentry(ap)
                    597: struct lbuf *ap;
                    598: {
                    599:        struct { char dminor, dmajor;};
                    600:        register t;
                    601:        register struct lbuf *p;
                    602:        register char *cp;
                    603: 
                    604:        p = ap;
                    605:        if (p->lnum == -1)
                    606:                return;
                    607:        column();
                    608:        if (iflg)
                    609:                if (nopad && !lflg)
                    610:                        printf("%d ", p->lnum);
                    611:                else
                    612:                        printf("%5d ", p->lnum);
                    613:        if (sflg)
                    614:                if (nopad && !lflg)
                    615:                        printf("%D ", nblock(p->lsize));
                    616:                else
                    617:                        printf("%4D ", nblock(p->lsize));
                    618:        if (lflg) {
                    619:                pputchar(p->ltype);
                    620:                pmode(p->lflags);
                    621:                printf("%2d ", p->lnl);
                    622:                t = p->luid;
                    623:                if(gflg)
                    624:                        t = p->lgid;
                    625:                if (nflg == 0 && getname(t, tbuf)==0)
                    626:                        printf("%-8.8s", tbuf);
                    627:                else
                    628:                        printf("%-8d", t);
                    629:                if (p->ltype=='b' || p->ltype=='c')
                    630:                        printf("%3d,%3d", major((int)p->lsize), minor((int)p->lsize));
                    631:                else
                    632:                        printf("%7ld", p->lsize);
                    633:                cp = ctime(&p->lmtime);
                    634:                if(p->lmtime < year)
                    635:                        printf(" %-7.7s %-4.4s ", cp+4, cp+20); else
                    636:                        printf(" %-12.12s ", cp+4);
                    637:        }
                    638:        if (p->lflags&ISARG)
                    639:                printf("%s", p->ln.namep);
                    640:        else
                    641:                printf("%.14s", p->ln.lname);
                    642: }
                    643: /* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/
                    644: #include "varargs.h"
                    645: /* This version of printf is compatible with the Version 7 C
                    646:  * printf. The differences are only minor except that this
                    647:  * printf assumes it is to print through pputchar. Version 7
                    648:  * printf is more general (and is much larger) and includes
                    649:  * provisions for floating point.
                    650:  */
                    651:  
                    652: 
                    653: #define MAXOCT 11      /* Maximum octal digits in a long */
                    654: #define MAXINT 32767   /* largest normal length positive integer */
                    655: #define BIG    1000000000  /* largest power of 10 less than an unsigned long */
                    656: #define MAXDIGS 10     /* number of digits in BIG */
                    657: 
                    658: static int width, sign, fill;
                    659: 
                    660: char *b_dconv();
                    661: 
                    662: printf(va_alist)
                    663:        va_dcl
                    664: {
                    665:        va_list ap;
                    666:        register char *fmt;
                    667:        char fcode;
                    668:        int prec;
                    669:        int length,mask1,nbits,n;
                    670:        long int mask2, num;
                    671:        register char *bptr;
                    672:        char *ptr;
                    673:        char buf[134];
                    674: 
                    675:        va_start(ap);
                    676:        fmt = va_arg(ap,char *);
                    677:        for (;;) {
                    678:                /* process format string first */
                    679:                while ((fcode = *fmt++)!='%') {
                    680:                        /* ordinary (non-%) character */
                    681:                        if (fcode=='\0')
                    682:                                return;
                    683:                        pputchar(fcode);
                    684:                }
                    685:                /* length modifier: -1 for h, 1 for l, 0 for none */
                    686:                length = 0;
                    687:                /* check for a leading - sign */
                    688:                sign = 0;
                    689:                if (*fmt == '-') {
                    690:                        sign++;
                    691:                        fmt++;
                    692:                }
                    693:                /* a '0' may follow the - sign */
                    694:                /* this is the requested fill character */
                    695:                fill = 1;
                    696:                if (*fmt == '0') {
                    697:                        fill--;
                    698:                        fmt++;
                    699:                }
                    700:                
                    701:                /* Now comes a digit string which may be a '*' */
                    702:                if (*fmt == '*') {
                    703:                        width = va_arg(ap, int);
                    704:                        if (width < 0) {
                    705:                                width = -width;
                    706:                                sign = !sign;
                    707:                        }
                    708:                        fmt++;
                    709:                }
                    710:                else {
                    711:                        width = 0;
                    712:                        while (*fmt>='0' && *fmt<='9')
                    713:                                width = width * 10 + (*fmt++ - '0');
                    714:                }
                    715:                
                    716:                /* maybe a decimal point followed by more digits (or '*') */
                    717:                if (*fmt=='.') {
                    718:                        if (*++fmt == '*') {
                    719:                                prec = va_arg(ap, int);
                    720:                                fmt++;
                    721:                        }
                    722:                        else {
                    723:                                prec = 0;
                    724:                                while (*fmt>='0' && *fmt<='9')
                    725:                                        prec = prec * 10 + (*fmt++ - '0');
                    726:                        }
                    727:                }
                    728:                else
                    729:                        prec = -1;
                    730:                
                    731:                /*
                    732:                 * At this point, "sign" is nonzero if there was
                    733:                 * a sign, "fill" is 0 if there was a leading
                    734:                 * zero and 1 otherwise, "width" and "prec"
                    735:                 * contain numbers corresponding to the digit
                    736:                 * strings before and after the decimal point,
                    737:                 * respectively, and "fmt" addresses the next
                    738:                 * character after the whole mess. If there was
                    739:                 * no decimal point, "prec" will be -1.
                    740:                 */
                    741:                switch (*fmt) {
                    742:                        case 'L':
                    743:                        case 'l':
                    744:                                length = 2;
                    745:                                /* no break!! */
                    746:                        case 'h':
                    747:                        case 'H':
                    748:                                length--;
                    749:                                fmt++;
                    750:                                break;
                    751:                }
                    752:                
                    753:                /*
                    754:                 * At exit from the following switch, we will
                    755:                 * emit the characters starting at "bptr" and
                    756:                 * ending at "ptr"-1, unless fcode is '\0'.
                    757:                 */
                    758:                switch (fcode = *fmt++) {
                    759:                        /* process characters and strings first */
                    760:                        case 'c':
                    761:                                buf[0] = va_arg(ap, int);
                    762:                                ptr = bptr = &buf[0];
                    763:                                if (buf[0] != '\0')
                    764:                                        ptr++;
                    765:                                break;
                    766:                        case 's':
                    767:                                bptr = va_arg(ap,char *);
                    768:                                if (bptr==0)
                    769:                                        bptr = "(null pointer)";
                    770:                                if (prec < 0)
                    771:                                        prec = MAXINT;
                    772:                                for (n=0; *bptr++ && n < prec; n++) ;
                    773:                                ptr = --bptr;
                    774:                                bptr -= n;
                    775:                                break;
                    776:                        case 'O':
                    777:                                length = 1;
                    778:                                fcode = 'o';
                    779:                                /* no break */
                    780:                        case 'o':
                    781:                        case 'X':
                    782:                        case 'x':
                    783:                                if (length > 0)
                    784:                                        num = va_arg(ap,long);
                    785:                                else
                    786:                                        num = (unsigned)va_arg(ap,int);
                    787:                                if (fcode=='o') {
                    788:                                        mask1 = 0x7;
                    789:                                        mask2 = 0x1fffffffL;
                    790:                                        nbits = 3;
                    791:                                }
                    792:                                else {
                    793:                                        mask1 = 0xf;
                    794:                                        mask2 = 0x0fffffffL;
                    795:                                        nbits = 4;
                    796:                                }
                    797:                                n = (num!=0);
                    798:                                bptr = buf + MAXOCT + 3;
                    799:                                /* shift and mask for speed */
                    800:                                do
                    801:                                    if (((int) num & mask1) < 10)
                    802:                                        *--bptr = ((int) num & mask1) + 060;
                    803:                                    else
                    804:                                        *--bptr = ((int) num & mask1) + 0127;
                    805:                                while (num = (num >> nbits) & mask2);
                    806:                                
                    807:                                if (fcode=='o') {
                    808:                                        if (n)
                    809:                                                *--bptr = '0';
                    810:                                }
                    811:                                else
                    812:                                        if (!sign && fill <= 0) {
                    813:                                                pputchar('0');
                    814:                                                pputchar(fcode);
                    815:                                                width -= 2;
                    816:                                        }
                    817:                                        else {
                    818:                                                *--bptr = fcode;
                    819:                                                *--bptr = '0';
                    820:                                        }
                    821:                                ptr = buf + MAXOCT + 3;
                    822:                                break;
                    823:                        case 'D':
                    824:                        case 'U':
                    825:                        case 'I':
                    826:                                length = 1;
                    827:                                fcode = fcode + 'a' - 'A';
                    828:                                /* no break */
                    829:                        case 'd':
                    830:                        case 'i':
                    831:                        case 'u':
                    832:                                if (length > 0)
                    833:                                        num = va_arg(ap,long);
                    834:                                else {
                    835:                                        n = va_arg(ap,int);
                    836:                                        if (fcode=='u')
                    837:                                                num = (unsigned) n;
                    838:                                        else
                    839:                                                num = (long) n;
                    840:                                }
                    841:                                if (n = (fcode != 'u' && num < 0))
                    842:                                        num = -num;
                    843:                                /* now convert to digits */
                    844:                                bptr = b_dconv(num, buf);
                    845:                                if (n)
                    846:                                        *--bptr = '-';
                    847:                                if (fill == 0)
                    848:                                        fill = -1;
                    849:                                ptr = buf + MAXDIGS + 1;
                    850:                                break;
                    851:                        default:
                    852:                                /* not a control character, 
                    853:                                 * print it.
                    854:                                 */
                    855:                                ptr = bptr = &fcode;
                    856:                                ptr++;
                    857:                                break;
                    858:                        }
                    859:                        if (fcode != '\0')
                    860:                                b_emit(bptr,ptr);
                    861:        }
                    862:        va_end(ap);
                    863: }
                    864: 
                    865: /* b_dconv converts the unsigned long integer "value" to
                    866:  * printable decimal and places it in "buffer", right-justified.
                    867:  * The value returned is the address of the first non-zero character,
                    868:  * or the address of the last character if all are zero.
                    869:  * The result is NOT null terminated, and is MAXDIGS characters long,
                    870:  * starting at buffer[1] (to allow for insertion of a sign).
                    871:  *
                    872:  * This program assumes it is running on 2's complement machine
                    873:  * with reasonable overflow treatment.
                    874:  */
                    875: char *
                    876: b_dconv(value, buffer)
                    877:        long value;
                    878:        char *buffer;
                    879: {
                    880:        register char *bp;
                    881:        register int svalue;
                    882:        int n;
                    883:        long lval;
                    884:        
                    885:        bp = buffer;
                    886:        
                    887:        /* zero is a special case */
                    888:        if (value == 0) {
                    889:                bp += MAXDIGS;
                    890:                *bp = '0';
                    891:                return(bp);
                    892:        }
                    893:        
                    894:        /* develop the leading digit of the value in "n" */
                    895:        n = 0;
                    896:        while (value < 0) {
                    897:                value -= BIG;   /* will eventually underflow */
                    898:                n++;
                    899:        }
                    900:        while ((lval = value - BIG) >= 0) {
                    901:                value = lval;
                    902:                n++;
                    903:        }
                    904:        
                    905:        /* stash it in buffer[1] to allow for a sign */
                    906:        bp[1] = n + '0';
                    907:        /*
                    908:         * Now develop the rest of the digits. Since speed counts here,
                    909:         * we do it in two loops. The first gets "value" down until it
                    910:         * is no larger than MAXINT. The second one uses integer divides
                    911:         * rather than long divides to speed it up.
                    912:         */
                    913:        bp += MAXDIGS + 1;
                    914:        while (value > MAXINT) {
                    915:                *--bp = (int)(value % 10) + '0';
                    916:                value /= 10;
                    917:        }
                    918:        
                    919:        /* cannot lose precision */
                    920:        svalue = value;
                    921:        while (svalue > 0) {
                    922:                *--bp = (svalue % 10) + '0';
                    923:                svalue /= 10;
                    924:        }
                    925:        
                    926:        /* fill in intermediate zeroes if needed */
                    927:        if (buffer[1] != '0') {
                    928:                while (bp > buffer + 2)
                    929:                        *--bp = '0';
                    930:                --bp;
                    931:        }
                    932:        return(bp);
                    933: }
                    934: 
                    935: /*
                    936:  * This program sends string "s" to pputchar. The character after
                    937:  * the end of "s" is given by "send". This allows the size of the
                    938:  * field to be computed; it is stored in "alen". "width" contains the
                    939:  * user specified length. If width<alen, the width will be taken to
                    940:  * be alen. "sign" is zero if the string is to be right-justified
                    941:  * in the field, nonzero if it is to be left-justified. "fill" is
                    942:  * 0 if the string is to be padded with '0', positive if it is to be
                    943:  * padded with ' ', and negative if an initial '-' should appear before
                    944:  * any padding in right-justification (to avoid printing "-3" as
                    945:  * "000-3" where "-0003" was intended).
                    946:  */
                    947: b_emit(s, send)
                    948:        register char *s;
                    949:        char *send;
                    950: {
                    951:        char cfill;
                    952:        register int alen;
                    953:        int npad;
                    954:        
                    955:        alen = send - s;
                    956:        if (alen > width)
                    957:                width = alen;
                    958:        cfill = fill>0? ' ': '0';
                    959:        
                    960:        /* we may want to print a leading '-' before anything */
                    961:        if (*s == '-' && fill < 0) {
                    962:                pputchar(*s++);
                    963:                alen--;
                    964:                width--;
                    965:        }
                    966:        npad = width - alen;
                    967:        
                    968:        /* emit any leading pad characters */
                    969:        if (!sign)
                    970:                while (--npad >= 0)
                    971:                        pputchar(cfill);
                    972:                        
                    973:        /* emit the string itself */
                    974:        while (--alen >= 0)
                    975:                pputchar(*s++);
                    976:                
                    977:        /* emit trailing pad characters */
                    978:        if (sign)
                    979:                while (--npad >= 0)
                    980:                        pputchar(cfill);
                    981: }

unix.superglobalmegacorp.com

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