1: #define UCB         /* Controls output format for -F */
   2: #define UCB_PWHASH  /* If have hashed password file */
   3: 
   4: static char *sccsid "@(#)ls.c	2.5";
   5: 
   6: /*
   7:  * ls - list file or directory
   8:  *
   9:  * Modified by Bill Joy UCB May/August 1977
  10:  * Modified by Dave Presotto BTL Feb/80
  11:  * Modified by Bill Joy and Mark Horton Summer 1980
  12:  *
  13:  * this version of ls is designed for graphic terminals and to
  14:  * list directories with lots of files in them compactly.
  15:  * It supports three variants for listings:
  16:  *
  17:  *      1) Columnar output.
  18:  *      2) Stream output.
  19:  *      3) Old one per line format.
  20:  *
  21:  * Columnar output is the default.
  22:  * If, however, the standard output is not a teletype, the default
  23:  * is one-per-line.
  24:  *
  25:  * With columnar output, the items are sorted down the columns.
  26:  * We use columns only for a directory we are interpreting.
  27:  * Thus, in particular, we do not use columns for
  28:  *
  29:  *      ls /usr/bin/p*
  30:  *
  31:  * This version of ls also prints non-printing characters as '?' if
  32:  * the standard output is a teletype.
  33:  *
  34:  * Flags relating to these and other new features are:
  35:  *
  36:  *      -m      force stream output.
  37:  *
  38:  *      -1      force one entry per line, e.g. to a teletype
  39:  *
  40:  *      -q      force non-printings to be '?'s, e.g. to a file
  41:  *
  42:  *      -C      force columnar output, e.g. into a file
  43:  *
  44:  *      -n      like -l, but user/group id's in decimal rather than
  45:  *              looking in /etc/passwd to save time
  46:  *
  47:  *      -F      turns on the "flagging" of executables and directories
  48:  *
  49:  *      -R      causes ls to recurse through the branches of the subtree
  50:  *              ala find
  51:  */
  52: 
  53: #include <sys/param.h>
  54: #include <sys/stat.h>
  55: #include <sys/dir.h>
  56: #include <stdio.h>
  57: #include <ctype.h>
  58: #include <pwd.h>
  59: #include <grp.h>
  60: #include <utmp.h>
  61: 
  62: struct  utmp    utmp;
  63: #define NMAX    (sizeof utmp.ut_name)
  64: 
  65: #define MAXFILEWIDTH 14
  66: #define NFILES  1024
  67: FILE    *pwdf, *dirf;
  68: 
  69: struct lbuf {
  70:         union {
  71:                 char    lname[15];
  72:                 char    *namep;
  73:         } ln;
  74:         char    ltype;
  75:         ino_t   lnum;
  76:         short   lflags;
  77:         short   lnl;
  78:         short   luid;
  79:         short   lgid;
  80:         long    lsize;
  81:         long    lmtime;
  82: };
  83: 
  84: struct dchain {
  85:         char *dc_name;          /* the path name */
  86:         struct dchain *dc_next; /* the next directory on the chain */
  87: };
  88: 
  89: struct dchain *dfirst;          /* the start of the directory chain */
  90: struct dchain *cdfirst;         /* the start of the current directory chain */
  91: struct dchain *dtemp;           /* temporary used when linking */
  92: char *curdir;                   /* the current directory */
  93: 
  94: int     aflg, bflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg;
  95: int     Aflg, nflg, qflg, Fflg, Rflg, across, Cflg;
  96: int     nopad;
  97: int     tabflg;
  98: int     rflg    = 1;
  99: long    year;
 100: int     flags;
 101: long    tblocks;
 102: int     statreq;
 103: int     xtraent;                /* for those switches which print out a total */
 104: struct  lbuf    *flist[NFILES];
 105: struct  lbuf    **lastp = flist;
 106: struct  lbuf    **firstp = flist;
 107: char    *dotp   = ".";
 108: 
 109: char    *makename();
 110: struct  lbuf *gstat();
 111: char    *ctime();
 112: long    nblock();
 113: char    *getname();
 114: 
 115: #define ISARG   0100000
 116: int     colwidth;
 117: int     filewidth;
 118: int     fixedwidth;
 119: int     outcol;
 120: 
 121: char    obuf[BUFSIZ];
 122: 
 123: main(argc, argv)
 124: int argc;
 125: char *argv[];
 126: {
 127: #include <sgtty.h>
 128: 
 129:         int i, width;
 130:         register struct lbuf *ep;
 131:         register struct lbuf **slastp;
 132:         struct lbuf **epp;
 133:         struct lbuf lb;
 134:         char *t;
 135:         char *cp;
 136:         int compar();
 137:         struct sgttyb sgbuf;
 138: 
 139:         Fflg = 0;
 140:         tabflg = 0;
 141:         Aflg = getuid() == 0;
 142:         setbuf(stdout, obuf);
 143:         lb.lmtime = time((long *) 0);
 144:         year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */
 145:         qflg = gtty(1, &sgbuf) == 0;
 146: 
 147:         /* guarantee at least on column width */
 148:         fixedwidth = 2;
 149: 
 150:         /*
 151:          * If the standard output is not a teletype,
 152:          * then we default to one-per-line format
 153:          * otherwise decide between stream and
 154:          * columnar based on our name.
 155:          */
 156:         if (qflg) {
 157:                 Cflg = 1;
 158:                 if ((sgbuf.sg_flags & XTABS) == 0)
 159:                         tabflg++;
 160:                 for (cp = argv[0]; cp[0] && cp[1]; cp++)
 161:                         continue;
 162:         /*
 163: 		 * Certain kinds of links (l, ll, lr, lf, lx) cause some
 164: 		 * various options to be turned on.
 165: 		 */
 166:         switch (cp[0]) {
 167:         case 'l':
 168:             if (cp[-1] == 'l') {
 169:                 /* ll => -l */
 170:                 lflg = 1;
 171:                 statreq++;
 172:                 xtraent++;
 173:             } else {
 174:                 /* l => -m */
 175:                 nopad = 1;
 176:                 Cflg = 0;
 177:             }
 178:             break;
 179:         case 'x':   /* lx => -x */
 180:             across = 1;
 181:             break;
 182:         case 'f':   /* lf => -F */
 183:             Fflg = 1;
 184:             break;
 185:         case 'r':   /* lr => -R */
 186:             Rflg = 1;
 187:             break;
 188:         }
 189:         } else {
 190:         tabflg++;
 191:     }
 192: 
 193:         while (--argc > 0 && *argv[1] == '-') {
 194:                 argv++;
 195:                 while (*++*argv) switch (**argv) {
 196:                 /*
 197:                  * C - force columnar output
 198:                  */
 199:                 case 'C':
 200:                         Cflg = 1;
 201:                         nopad = 0;
 202:                         continue;
 203:                 /*
 204:                  * m - force stream output
 205:                  */
 206:                 case 'm':
 207:                         Cflg = 0;
 208:                         nopad = 1;
 209:                         continue;
 210:                 /*
 211:                  * x - force sort across
 212:                  */
 213:                 case 'x':
 214:                         across = 1;
 215:                         nopad = 0;
 216:                         Cflg = 1;
 217:                         continue;
 218:                 /*
 219:                  * q - force ?'s in output
 220:                  */
 221:                 case 'q':
 222:                         qflg = 1;
 223:             bflg = 0;
 224:                         continue;
 225:         /*
 226: 		 * b - force octal value in output
 227: 		 */
 228:         case 'b':
 229:             bflg = 1;
 230:             qflg = 0;
 231:             continue;
 232:                 /*
 233:                  * 1 - force 1/line in output
 234:                  */
 235:                 case '1':
 236:                         Cflg = 0;
 237:                         nopad = 0;
 238:                         continue;
 239:                 /* STANDARD FLAGS */
 240:                 case 'a':
 241:                         aflg++;
 242:                         continue;
 243: 
 244:                 case 'A':
 245:                         Aflg = !Aflg;
 246:                         continue;
 247: 
 248:                 case 'c':
 249:                         cflg++;
 250:                         continue;
 251: 
 252:                 case 's':
 253:                         fixedwidth += 5;
 254:                         sflg++;
 255:                         statreq++;
 256:                         xtraent++;
 257:                         continue;
 258: 
 259:                 case 'd':
 260:                         dflg++;
 261:                         continue;
 262: 
 263:                 /*
 264:                  * n - don't look in password file
 265:                  */
 266:                 case 'n':
 267:                         nflg++;
 268:                 case 'l':
 269:                         lflg++;
 270:                         statreq++;
 271:                         xtraent++;
 272:                         continue;
 273: 
 274:                 case 'r':
 275:                         rflg = -1;
 276:                         continue;
 277: 
 278:                 case 't':
 279:                         tflg++;
 280:                         statreq++;
 281:                         continue;
 282: 
 283:                 case 'u':
 284:                         uflg++;
 285:                         continue;
 286: 
 287:                 case 'i':
 288:                         fixedwidth += 5;
 289:                         iflg++;
 290:                         continue;
 291: 
 292:                 case 'f':
 293:                         fflg++;
 294:                         continue;
 295: 
 296:                 case 'g':
 297:                         gflg++;
 298:                         continue;
 299: 
 300:                 case 'F':
 301:                         Fflg++;
 302:                         continue;
 303: 
 304:                 case 'R':
 305:                         Rflg++;
 306:                         continue;
 307: 
 308:                 default:
 309:                         fprintf (stderr, "usage: ls [-1ACFRabcdfgilmnqrstux] [files]\n");
 310:                         exit(1);
 311:                 }
 312:         }
 313:         if (Fflg)
 314: #ifdef UCB
 315:                 fixedwidth++;
 316: #else
 317:                 fixedwidth += 2;
 318: #endif
 319:         if (fflg) {
 320:                 aflg++;
 321:                 lflg = 0;
 322:                 sflg = 0;
 323:                 tflg = 0;
 324:                 statreq = 0;
 325:                 xtraent = 0;
 326:         }
 327:         if(lflg) {
 328:                 Cflg = 0;
 329:                 t = "/etc/passwd";
 330:                 if (gflg)
 331:                         t = "/etc/group";
 332:                 nopad = 0;
 333:                 fixedwidth = 70;
 334:                 pwdf = fopen(t, "r");
 335:         }
 336:         if (argc==0) {
 337:                 argc++;
 338:                 argv = &dotp - 1;
 339:         }
 340:         for (i=0; i < argc; i++) {
 341:                 argv++;
 342:                 if (Cflg) {
 343:                         width = strlen (*argv);
 344:                         if (width > filewidth)
 345:                                 filewidth = width;
 346:                 }
 347:                 if ((ep = gstat(*argv, 1))==NULL)
 348:                         continue;
 349:                 ep->ln.namep = *argv;
 350:                 ep->lflags |= ISARG;
 351:         }
 352:         if (!Cflg)
 353:                 filewidth = MAXFILEWIDTH;
 354:         else
 355:         colwidth = fixedwidth + filewidth;
 356:         qsort(firstp, lastp - firstp, sizeof *lastp, compar);
 357:         slastp = lastp;
 358:     /* For each argument user typed */
 359:         for (epp=firstp; epp<slastp; epp++) {
 360:                 ep = *epp;
 361:                 if (ep->ltype=='d' && dflg==0 || fflg)
 362:                         pdirectory(ep->ln.namep, (argc>1), slastp);
 363:                 else
 364:                         pentry(ep);
 365: 
 366:         /* -R: print subdirectories found */
 367:         while (dfirst || cdfirst) {
 368:             /* Place direct subdirs on front in right order */
 369:             while (cdfirst) {
 370:                 /* reverse cdfirst onto front of dfirst */
 371:                 dtemp = cdfirst;
 372:                 cdfirst = cdfirst -> dc_next;
 373:                 dtemp -> dc_next = dfirst;
 374:                 dfirst = dtemp;
 375:             }
 376:             /* take off first dir on dfirst & print it */
 377:             dtemp = dfirst;
 378:             dfirst = dfirst->dc_next;
 379:             pdirectory (dtemp->dc_name, 1, firstp);
 380:             cfree (dtemp->dc_name);
 381:             cfree (dtemp);
 382:         }
 383:         }
 384:         if (outcol)
 385:                 putc('\n', stdout);
 386:         fflush(stdout);
 387: }
 388: 
 389: /*
 390:  * pdirectory: print the directory name, labelling it if title is
 391:  * nonzero, using lp as the place to start reading in the dir.
 392:  */
 393: pdirectory (name, title, lp)
 394: char *name;
 395: int title;
 396: struct lbuf **lp;
 397: {
 398:         register struct dchain *dp;
 399:     register struct lbuf *ap;
 400:     register char *pname;
 401:     struct lbuf **app;
 402: 
 403:         filewidth = 0;
 404:         curdir = name;
 405:         if (title)
 406:                 printf("\n%s:\n", name);
 407:         lastp = lp;
 408:         readdir(name);
 409:         if (!Cflg)
 410:                 filewidth = MAXFILEWIDTH;
 411:         colwidth = fixedwidth + filewidth;
 412: #ifdef notdef
 413:     /* Taken out because it appears this is done below in pem. */
 414:         if (tabflg) {
 415:                 if (colwidth <= 8)
 416:                         colwidth = 8;
 417:                 else
 418:                         if (colwidth <= 16)
 419:                                 colwidth = 16;
 420:         }
 421: #endif
 422:         if (fflg==0)
 423:                 qsort(lp,lastp - lp,sizeof *lastp,compar);
 424:     if (Rflg) for (app=lastp-1; app>=lp; app--) {
 425:         ap = *app;
 426:         if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") &&
 427:                 strcmp(ap->ln.lname, "..")) {
 428:             dp = (struct dchain *) calloc(1, sizeof(struct dchain));
 429:             pname = makename (curdir, ap->ln.lname);
 430:             dp->dc_name = (char *) calloc(1, strlen(pname)+1);
 431:             strcpy(dp->dc_name, pname);
 432:             dp -> dc_next = dfirst;
 433:             dfirst = dp;
 434:         }
 435:     }
 436:         if (lflg || sflg)
 437:                 printf("total %D", tblocks);
 438:         pem(lp, lastp);
 439:         newline();
 440: }
 441: 
 442: /*
 443:  * pem: print 'em.  Print a list of files (e.g. a directory) bounded
 444:  * by slp and lp.
 445:  */
 446: pem(slp, lp)
 447:         register struct lbuf **slp, **lp;
 448: {
 449:         int ncols, nrows, row, col;
 450:         register struct lbuf **ep;
 451: 
 452:         if (tabflg) {
 453:                 if (colwidth <= 9)
 454:                         colwidth = 8;
 455:                 else
 456:                         if (colwidth <= 17)
 457:                                 colwidth = 16;
 458:         }
 459:         ncols = 80 / colwidth;
 460:         if (ncols == 1 || Cflg == 0) {
 461:                 for (ep = slp; ep < lp; ep++)
 462:                         pentry(*ep);
 463:                 return;
 464:         }
 465:         if (across) {
 466:                 for (ep = slp; ep < lp; ep++)
 467:                         pentry(*ep);
 468:                 return;
 469:         }
 470:         if (xtraent)
 471:                 slp--;
 472:         nrows = (lp - slp - 1) / ncols + 1;
 473:         for (row = 0; row < nrows; row++) {
 474:                 col = row == 0 && xtraent;
 475:                 for (; col < ncols; col++) {
 476:                         ep = slp + (nrows * col) + row;
 477:                         if (ep < lp)
 478:                                 pentry(*ep);
 479:                 }
 480:                 if (outcol)
 481:                         printf("\n");
 482:         }
 483: }
 484: 
 485: /*
 486:  * pputchar: like putchar but knows how to handle control chars.
 487:  * CAUTION: if you make ctrl chars print in ^x notation, or any
 488:  * other notation which is wider than one character, the column
 489:  * nature of things (such as files with 14 letter names) will be
 490:  * messed up.  Weigh this carefully!
 491:  */
 492: pputchar(c)
 493:         char c;
 494: {
 495:     char cc;
 496: 
 497:         switch (c) {
 498:                 case '\t':
 499:                         outcol = (outcol + 8) &~ 7;
 500:                         break;
 501:                 case '\n':
 502:                         outcol = 0;
 503:                         break;
 504:                 default:
 505:                         if (c < ' ' || c >= 0177) {
 506:                 if (qflg)
 507:                     c = '?';
 508:                 else if (bflg) {
 509:                     outcol += 3;
 510:                     putc ('\\', stdout);
 511:                     cc = '0' + (c>>6 & 07);
 512:                     putc (cc, stdout);
 513:                     cc = '0' + (c>>3 & 07);
 514:                     putc (cc, stdout);
 515:                     c = '0' + (c & 07);
 516:                 }
 517:             }
 518:                         outcol++;
 519:                         break;
 520:         }
 521:         putc(c, stdout);
 522: }
 523: 
 524: newline()
 525: {
 526:         if (outcol)
 527:                 putc('\n', stdout);
 528:         outcol = 0;
 529: }
 530: 
 531: /*
 532:  * column: get to the beginning of the next column.
 533:  */
 534: column()
 535: {
 536: 
 537:         if (outcol == 0)
 538:                 return;
 539:         if (nopad) {
 540:                 putc(',', stdout);
 541:                 outcol++;
 542:                 if (outcol + colwidth + 2 > 80) {
 543:                         putc('\n', stdout);
 544:                         outcol = 0;
 545:                         return;
 546:                 }
 547:                 putc(' ', stdout);
 548:                 outcol++;
 549:                 return;
 550:         }
 551:         if (Cflg == 0) {
 552:                 putc('\n', stdout);
 553:                 return;
 554:         }
 555:         if ((outcol / colwidth + 2) * colwidth > 80) {
 556:                 putc('\n', stdout);
 557:                 outcol = 0;
 558:                 return;
 559:         }
 560:         if (tabflg && (colwidth <= 16)) {
 561:                 if (colwidth > 8)
 562:                         if ((outcol % 16) < 8) {
 563:                                 outcol += 8 - (outcol % 8);
 564:                                 putc ('\t', stdout);
 565:                         }
 566:                 outcol += 8 - (outcol % 8);
 567:                 putc ('\t', stdout);
 568:                 return;
 569:         }
 570:         do {
 571:                 outcol++;
 572:                 putc(' ', stdout);
 573:         } while (outcol % colwidth);
 574: }
 575: 
 576: 
 577: /*
 578:  * nblock: the number of 512 byte blocks a size byte file takes up.
 579:  * (Note: the number stays 512 no matter what BUFSIZ or the filesystem uses.)
 580:  */
 581: long
 582: nblock(size)
 583: long size;
 584: {
 585:         return((size+511)>>9);
 586: }
 587: 
 588: /*
 589:  * This code handles the rwx- business.
 590:  * You figure it out.
 591:  */
 592: int     m1[] = { 1, S_IREAD>>0, 'r', '-' };
 593: int     m2[] = { 1, S_IWRITE>>0, 'w', '-' };
 594: int     m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' };
 595: int     m4[] = { 1, S_IREAD>>3, 'r', '-' };
 596: int     m5[] = { 1, S_IWRITE>>3, 'w', '-' };
 597: int     m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' };
 598: int     m7[] = { 1, S_IREAD>>6, 'r', '-' };
 599: int     m8[] = { 1, S_IWRITE>>6, 'w', '-' };
 600: int     m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' };
 601: 
 602: int     *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
 603: 
 604: pmode(aflag)
 605: {
 606:         register int **mp;
 607: 
 608:         flags = aflag;
 609:         for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];)
 610:                 select(*mp++);
 611: }
 612: 
 613: select(pairp)
 614: register int *pairp;
 615: {
 616:         register int n;
 617: 
 618:         n = *pairp++;
 619:         while (--n>=0 && (flags&*pairp++)==0)
 620:                 pairp++;
 621:         pputchar(*pairp);
 622: }
 623: 
 624: /*
 625:  * returns cat(dir, "/", file), unless dir ends in /, when it doesn't //
 626:  */
 627: char *
 628: makename(dir, file)
 629: char *dir, *file;
 630: {
 631:         static char dfile[100];
 632:         register char *dp, *fp;
 633:         register int i;
 634: 
 635:         dp = dfile;
 636:         fp = dir;
 637:         while (*fp)
 638:                 *dp++ = *fp++;
 639:         if (*(dp-1) != '/')
 640:         *dp++ = '/';
 641:         fp = file;
 642:         for (i=0; i<DIRSIZ; i++)
 643:                 *dp++ = *fp++;
 644:         *dp = 0;
 645:         return(dfile);
 646: }
 647: 
 648: /*
 649:  * readdir: read in the directory whose name is dir,
 650:  * starting at lastp.
 651:  */
 652: readdir(dir)
 653: char *dir;
 654: {
 655:         static struct direct dentry;
 656:         register int j, width;
 657:         register struct lbuf *ep;
 658: 
 659:         if ((dirf = fopen(dir, "r")) == NULL) {
 660:                 printf("%s unreadable\n", dir);
 661:                 return;
 662:         }
 663:         tblocks = 0;
 664:         for(;;) {
 665:                 if (fread(&dentry, sizeof(dentry), 1, dirf) != 1)
 666:                         break;
 667:                 if (dentry.d_ino==0 ||
 668:                         aflg==0 && dentry.d_name[0]=='.' && (
 669:                         !Aflg ||
 670:                         dentry.d_name[1]=='\0'
 671:                         || dentry.d_name[1]=='.' && dentry.d_name[2]=='\0'))
 672:                         continue;
 673:                 if (Cflg) {
 674:                         width = strlen (dentry.d_name);
 675:                         if (width > filewidth)
 676:                                 filewidth = width;
 677:                 }
 678:                 ep = gstat(makename(dir, dentry.d_name), Fflg || Rflg);
 679:                 if (ep==NULL)
 680:                         continue;
 681:                 if (ep->lnum != -1)
 682:                         ep->lnum = dentry.d_ino;
 683:                 for (j=0; j<DIRSIZ; j++)
 684:                         ep->ln.lname[j] = dentry.d_name[j];
 685:         }
 686:         fclose(dirf);
 687: }
 688: 
 689: /*
 690:  * stat the given file and return an lbuf containing it.
 691:  * argfl is nonzero if a stat is required because the file is
 692:  * an argument, rather than having been found in a directory.
 693:  */
 694: struct lbuf *
 695: gstat(file, argfl)
 696: char *file;
 697: {
 698:         struct stat statb;
 699:         register struct lbuf *rep;
 700:         static int nomocore;
 701: 
 702:         if (nomocore)
 703:                 return(NULL);
 704:         rep = (struct lbuf *)malloc(sizeof(struct lbuf));
 705:         if (rep==NULL) {
 706:                 fprintf(stderr, "ls: out of memory\n");
 707:                 nomocore = 1;
 708:                 return(NULL);
 709:         }
 710:         if (lastp >= &flist[NFILES]) {
 711:                 static int msg;
 712:                 lastp--;
 713:                 if (msg==0) {
 714:                         fprintf(stderr, "ls: too many files\n");
 715:                         msg++;
 716:                 }
 717:         }
 718:         *lastp++ = rep;
 719:         rep->lflags = 0;
 720:         rep->lnum = 0;
 721:         rep->ltype = '-';
 722:         if (argfl || statreq) {
 723:                 if (stat(file, &statb)<0) {
 724:                         printf("%s not found\n", file);
 725:                         statb.st_ino = -1;
 726:                         statb.st_size = 0;
 727:                         statb.st_mode = 0;
 728:                         if (argfl) {
 729:                                 lastp--;
 730:                                 return(0);
 731:                         }
 732:                 }
 733:                 rep->lnum = statb.st_ino;
 734:                 rep->lsize = statb.st_size;
 735:                 switch(statb.st_mode&S_IFMT) {
 736: 
 737:                 case S_IFDIR:
 738:                         rep->ltype = 'd';
 739:                         break;
 740: 
 741:                 case S_IFBLK:
 742:                         rep->ltype = 'b';
 743:                         rep->lsize = statb.st_rdev;
 744:                         break;
 745: 
 746:                 case S_IFCHR:
 747:                         rep->ltype = 'c';
 748:                         rep->lsize = statb.st_rdev;
 749:                         break;
 750:                 }
 751:                 rep->lflags = statb.st_mode & ~S_IFMT;
 752:                 rep->luid = statb.st_uid;
 753:                 rep->lgid = statb.st_gid;
 754:                 rep->lnl = statb.st_nlink;
 755:                 if(uflg)
 756:                         rep->lmtime = statb.st_atime;
 757:                 else if (cflg)
 758:                         rep->lmtime = statb.st_ctime;
 759:                 else
 760:                         rep->lmtime = statb.st_mtime;
 761:                 tblocks += nblock(statb.st_size);
 762:         }
 763:         return(rep);
 764: }
 765: 
 766: /*
 767:  * decide whether to print pp1 before or after pp2, based on their
 768:  * names, various times, and the r flag.
 769:  */
 770: compar(pp1, pp2)
 771: struct lbuf **pp1, **pp2;
 772: {
 773:         register struct lbuf *p1, *p2;
 774: 
 775:         p1 = *pp1;
 776:         p2 = *pp2;
 777:         if (dflg==0) {
 778:                 if (p1->lflags&ISARG && p1->ltype=='d') {
 779:                         if (!(p2->lflags&ISARG && p2->ltype=='d'))
 780:                                 return(1);
 781:                 } else {
 782:                         if (p2->lflags&ISARG && p2->ltype=='d')
 783:                                 return(-1);
 784:                 }
 785:         }
 786:         if (tflg) {
 787:                 if(p2->lmtime == p1->lmtime)
 788:                         return(0);
 789:                 if(p2->lmtime > p1->lmtime)
 790:                         return(rflg);
 791:                 return(-rflg);
 792:         }
 793:         return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname,
 794:                                 p2->lflags&ISARG? p2->ln.namep: p2->ln.lname));
 795: }
 796: 
 797: /*
 798:  * print the entry pointed at by ap
 799:  */
 800: pentry(ap)
 801: struct lbuf *ap;
 802: {
 803:         struct { char dminor, dmajor;};
 804:         register struct lbuf *p;
 805:         register char *cp;
 806:         char fname[100];
 807:         char *pname;
 808:         struct passwd *getpwuid();
 809:         struct passwd *pwptr;
 810:         struct group *getgrgid();
 811:         struct group *grptr;
 812: 
 813:         fname[0] = 0;
 814:         p = ap;
 815:         if (p->lnum == -1)
 816:                 return;
 817:         column();
 818:         if (iflg)
 819:                 if (nopad && !lflg)
 820:                         printf("%d ", p->lnum);
 821:                 else
 822:                         printf("%5d ", p->lnum);
 823:         if (sflg)
 824:                 if (nopad && !lflg)
 825:                         printf("%D ", nblock(p->lsize));
 826:                 else
 827:                         printf("%4D ", nblock(p->lsize));
 828:         if (lflg) {
 829:                 pputchar(p->ltype);
 830:                 pmode(p->lflags);
 831:                 printf("%2d ", p->lnl);
 832:                 if(gflg) {
 833:                         grptr = getgrgid(p->lgid);
 834:                         if (nflg == 0 && grptr != 0)
 835:                                 printf("%-8.8s", grptr->gr_name);
 836:                         else
 837:                                 printf("%-8d", p->lgid);
 838:                 } else {
 839: #ifndef UCB_PWHASH
 840:             char *name;
 841:                         if (nflg == 0 && (name = getname(p->luid))) {
 842:                                 printf("%-8.8s", name);
 843:             }
 844: #else
 845:                         pwptr = getpwuid(p->luid);
 846:                         if (nflg == 0 && pwptr != 0)
 847:                                 printf("%-8.8s", pwptr->pw_name);
 848: #endif
 849:                         else
 850:                                 printf("%-8d", p->luid);
 851:                 }
 852:                 if (p->ltype=='b' || p->ltype=='c')
 853:                         printf("%3d,%3d", major((int)p->lsize), minor((int)p->lsize));
 854:                 else
 855:                         printf("%7ld", p->lsize);
 856:                 cp = ctime(&p->lmtime);
 857:                 if(p->lmtime < year)
 858:                         printf(" %-7.7s %-4.4s ", cp+4, cp+20); else
 859:                         printf(" %-12.12s ", cp+4);
 860:         }
 861: #ifndef UCB
 862:         if (Fflg) {
 863:             if (p->ltype == 'd')
 864:                 strcat (fname, "[");
 865:             else if (p->lflags & 0111)
 866:                 strcat (fname, "*");
 867:             else if (!nopad)
 868:                 strcat (fname, " ");
 869:         }
 870: #endif
 871:         if (p->lflags & ISARG)
 872:             strncat (fname, p->ln.namep, 98);
 873:         else
 874:             strncat (fname, p->ln.lname, 14);
 875: #ifndef UCB
 876:         if (Fflg) {
 877:             if (p->ltype == 'd')
 878:                 strcat (fname, "]");
 879:             else if (!nopad)
 880:                 strcat (fname, " ");
 881:         }
 882: #else
 883:         if (Fflg) {
 884:             if (p->ltype == 'd')
 885:                 strcat (fname, "/");
 886:             else if (p->lflags & 0111)
 887:                 strcat (fname, "*");
 888:             else if (!nopad)
 889:                 strcat (fname, " ");
 890:         }
 891: #endif
 892:         printf ("%s", fname);
 893:         free(ap);
 894: }
 895: 
 896: /* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/
 897: 
 898: #include "varargs.h"
 899: 
 900: /*
 901:  * This version of printf is compatible with the Version 7 C
 902:  * printf. The differences are only minor except that this
 903:  * printf assumes it is to print through pputchar. Version 7
 904:  * printf is more general (and is much larger) and includes
 905:  * provisions for floating point.
 906:  */
 907: 
 908: #define MAXOCT  11          /* Maximum octal digits in a long */
 909: #define MAXINT  32767       /* largest normal length positive integer */
 910: #define BIG     1000000000  /* largest power of 10 less than an unsigned long */
 911: #define MAXDIGS 10          /* number of digits in BIG */
 912: 
 913: static int width, sign, fill;
 914: 
 915: char *b_dconv();
 916: 
 917: printf(va_alist)
 918:         va_dcl
 919: {
 920:         va_list ap;
 921:         register char *fmt;
 922:         char fcode;
 923:         int prec;
 924:         int length,mask1,nbits,n;
 925:         long int mask2, num;
 926:         register char *bptr;
 927:         char *ptr;
 928:         char buf[134];
 929: 
 930:         va_start(ap);
 931:         fmt = va_arg(ap,char *);
 932:         for (;;) {
 933:                 /* process format string first */
 934:                 while ((fcode = *fmt++)!='%') {
 935:                         /* ordinary (non-%) character */
 936:                         if (fcode=='\0')
 937:                                 return;
 938:                         pputchar(fcode);
 939:                 }
 940:                 /* length modifier: -1 for h, 1 for l, 0 for none */
 941:                 length = 0;
 942:                 /* check for a leading - sign */
 943:                 sign = 0;
 944:                 if (*fmt == '-') {
 945:                         sign++;
 946:                         fmt++;
 947:                 }
 948:                 /* a '0' may follow the - sign */
 949:                 /* this is the requested fill character */
 950:                 fill = 1;
 951:                 if (*fmt == '0') {
 952:                         fill--;
 953:                         fmt++;
 954:                 }
 955: 
 956:                 /* Now comes a digit string which may be a '*' */
 957:                 if (*fmt == '*') {
 958:                         width = va_arg(ap, int);
 959:                         if (width < 0) {
 960:                                 width = -width;
 961:                                 sign = !sign;
 962:                         }
 963:                         fmt++;
 964:                 }
 965:                 else {
 966:                         width = 0;
 967:                         while (*fmt>='0' && *fmt<='9')
 968:                                 width = width * 10 + (*fmt++ - '0');
 969:                 }
 970: 
 971:                 /* maybe a decimal point followed by more digits (or '*') */
 972:                 if (*fmt=='.') {
 973:                         if (*++fmt == '*') {
 974:                                 prec = va_arg(ap, int);
 975:                                 fmt++;
 976:                         }
 977:                         else {
 978:                                 prec = 0;
 979:                                 while (*fmt>='0' && *fmt<='9')
 980:                                         prec = prec * 10 + (*fmt++ - '0');
 981:                         }
 982:                 }
 983:                 else
 984:                         prec = -1;
 985: 
 986:                 /*
 987:                  * At this point, "sign" is nonzero if there was
 988:                  * a sign, "fill" is 0 if there was a leading
 989:                  * zero and 1 otherwise, "width" and "prec"
 990:                  * contain numbers corresponding to the digit
 991:                  * strings before and after the decimal point,
 992:                  * respectively, and "fmt" addresses the next
 993:                  * character after the whole mess. If there was
 994:                  * no decimal point, "prec" will be -1.
 995:                  */
 996:                 switch (*fmt) {
 997:                         case 'L':
 998:                         case 'l':
 999:                                 length = 2;
1000:                                 /* no break!! */
1001:                         case 'h':
1002:                         case 'H':
1003:                                 length--;
1004:                                 fmt++;
1005:                                 break;
1006:                 }
1007: 
1008:                 /*
1009:                  * At exit from the following switch, we will
1010:                  * emit the characters starting at "bptr" and
1011:                  * ending at "ptr"-1, unless fcode is '\0'.
1012:                  */
1013:                 switch (fcode = *fmt++) {
1014:                         /* process characters and strings first */
1015:                         case 'c':
1016:                                 buf[0] = va_arg(ap, int);
1017:                                 ptr = bptr = &buf[0];
1018:                                 if (buf[0] != '\0')
1019:                                         ptr++;
1020:                                 break;
1021:                         case 's':
1022:                                 bptr = va_arg(ap,char *);
1023:                                 if (bptr==0)
1024:                                         bptr = "(null pointer)";
1025:                                 if (prec < 0)
1026:                                         prec = MAXINT;
1027:                                 for (n=0; *bptr++ && n < prec; n++) ;
1028:                                 ptr = --bptr;
1029:                                 bptr -= n;
1030:                                 break;
1031:                         case 'O':
1032:                                 length = 1;
1033:                                 fcode = 'o';
1034:                                 /* no break */
1035:                         case 'o':
1036:                         case 'X':
1037:                         case 'x':
1038:                                 if (length > 0)
1039:                                         num = va_arg(ap,long);
1040:                                 else
1041:                                         num = (unsigned)va_arg(ap,int);
1042:                                 if (fcode=='o') {
1043:                                         mask1 = 0x7;
1044:                                         mask2 = 0x1fffffffL;
1045:                                         nbits = 3;
1046:                                 }
1047:                                 else {
1048:                                         mask1 = 0xf;
1049:                                         mask2 = 0x0fffffffL;
1050:                                         nbits = 4;
1051:                                 }
1052:                                 n = (num!=0);
1053:                                 bptr = buf + MAXOCT + 3;
1054:                                 /* shift and mask for speed */
1055:                                 do
1056:                                     if (((int) num & mask1) < 10)
1057:                                         *--bptr = ((int) num & mask1) + 060;
1058:                                     else
1059:                                         *--bptr = ((int) num & mask1) + 0127;
1060:                                 while (num = (num >> nbits) & mask2);
1061: 
1062:                                 if (fcode=='o') {
1063:                                         if (n)
1064:                                                 *--bptr = '0';
1065:                                 }
1066:                                 else
1067:                                         if (!sign && fill <= 0) {
1068:                                                 pputchar('0');
1069:                                                 pputchar(fcode);
1070:                                                 width -= 2;
1071:                                         }
1072:                                         else {
1073:                                                 *--bptr = fcode;
1074:                                                 *--bptr = '0';
1075:                                         }
1076:                                 ptr = buf + MAXOCT + 3;
1077:                                 break;
1078:                         case 'D':
1079:                         case 'U':
1080:                         case 'I':
1081:                                 length = 1;
1082: 
1083:                       fcode = fcode + 'a' - 'A';
1084:                                 /* no break */
1085:                         case 'd':
1086:                         case 'i':
1087:                         case 'u':
1088:                                 if (length > 0)
1089:                                         num = va_arg(ap,long);
1090:                                 else {
1091:                                         n = va_arg(ap,int);
1092:                                         if (fcode=='u')
1093:                                                 num = (unsigned) n;
1094:                                         else
1095:                                                 num = (long) n;
1096:                                 }
1097:                                 if (n = (fcode != 'u' && num < 0))
1098:                                         num = -num;
1099:                                 /* now convert to digits */
1100:                                 bptr = b_dconv(num, buf);
1101:                                 if (n)
1102:                                         *--bptr = '-';
1103:                                 if (fill == 0)
1104:                                         fill = -1;
1105:                                 ptr = buf + MAXDIGS + 1;
1106:                                 break;
1107:                         default:
1108:                                 /* not a control character,
1109:                                  * print it.
1110:                                  */
1111:                                 ptr = bptr = &fcode;
1112:                                 ptr++;
1113:                                 break;
1114:                         }
1115:                         if (fcode != '\0')
1116:                                 b_emit(bptr,ptr);
1117:         }
1118:         va_end(ap);
1119: }
1120: 
1121: /* b_dconv converts the unsigned long integer "value" to
1122:  * printable decimal and places it in "buffer", right-justified.
1123:  * The value returned is the address of the first non-zero character,
1124:  * or the address of the last character if all are zero.
1125:  * The result is NOT null terminated, and is MAXDIGS characters long,
1126:  * starting at buffer[1] (to allow for insertion of a sign).
1127:  *
1128:  * This program assumes it is running on 2's complement machine
1129:  * with reasonable overflow treatment.
1130:  */
1131: char *
1132: b_dconv(value, buffer)
1133:         long value;
1134:         char *buffer;
1135: {
1136:         register char *bp;
1137:         register int svalue;
1138:         int n;
1139:         long lval;
1140: 
1141:         bp = buffer;
1142: 
1143:         /* zero is a special case */
1144:         if (value == 0) {
1145:                 bp += MAXDIGS;
1146:                 *bp = '0';
1147:                 return(bp);
1148:         }
1149: 
1150:         /* develop the leading digit of the value in "n" */
1151:         n = 0;
1152:         while (value < 0) {
1153:                 value -= BIG;   /* will eventually underflow */
1154:                 n++;
1155:         }
1156:         while ((lval = value - BIG) >= 0) {
1157:                 value = lval;
1158:                 n++;
1159:         }
1160: 
1161:         /* stash it in buffer[1] to allow for a sign */
1162:         bp[1] = n + '0';
1163:         /*
1164:          * Now develop the rest of the digits. Since speed counts here,
1165:          * we do it in two loops. The first gets "value" down until it
1166:          * is no larger than MAXINT. The second one uses integer divides
1167:          * rather than long divides to speed it up.
1168:          */
1169:         bp += MAXDIGS + 1;
1170:         while (value > MAXINT) {
1171:                 *--bp = (int)(value % 10) + '0';
1172:                 value /= 10;
1173:         }
1174: 
1175:         /* cannot lose precision */
1176:         svalue = value;
1177:         while (svalue > 0) {
1178:                 *--bp = (svalue % 10) + '0';
1179:                 svalue /= 10;
1180:         }
1181: 
1182:         /* fill in intermediate zeroes if needed */
1183:         if (buffer[1] != '0') {
1184:                 while (bp > buffer + 2)
1185:                         *--bp = '0';
1186:                 --bp;
1187:         }
1188:         return(bp);
1189: }
1190: 
1191: /*
1192:  * This program sends string "s" to pputchar. The character after
1193:  * the end of "s" is given by "send". This allows the size of the
1194:  * field to be computed; it is stored in "alen". "width" contains the
1195:  * user specified length. If width<alen, the width will be taken to
1196:  * be alen. "sign" is zero if the string is to be right-justified
1197:  * in the field, nonzero if it is to be left-justified. "fill" is
1198:  * 0 if the string is to be padded with '0', positive if it is to be
1199:  * padded with ' ', and negative if an initial '-' should appear before
1200:  * any padding in right-justification (to avoid printing "-3" as
1201:  * "000-3" where "-0003" was intended).
1202:  */
1203: b_emit(s, send)
1204:         register char *s;
1205:         char *send;
1206: {
1207:         char cfill;
1208:         register int alen;
1209:         int npad;
1210: 
1211:         alen = send - s;
1212:         if (alen > width)
1213:                 width = alen;
1214:         cfill = fill>0? ' ': '0';
1215: 
1216:         /* we may want to print a leading '-' before anything */
1217:         if (*s == '-' && fill < 0) {
1218:                 pputchar(*s++);
1219:                 alen--;
1220:                 width--;
1221:         }
1222:         npad = width - alen;
1223: 
1224:         /* emit any leading pad characters */
1225:         if (!sign)
1226:                 while (--npad >= 0)
1227:                         pputchar(cfill);
1228: 
1229:         /* emit the string itself */
1230:         while (--alen >= 0)
1231:                 pputchar(*s++);
1232: 
1233:         /* emit trailing pad characters */
1234:         if (sign)
1235:                 while (--npad >= 0)
1236:                         pputchar(cfill);
1237: }
1238: 
1239: #ifndef UCB_PWHASH
1240: #define NUID    2048
1241: 
1242: char    names[NUID][NMAX+1];
1243: 
1244: char *
1245: getname(uid)
1246: {
1247:     register struct passwd *pw;
1248:     static init;
1249:     struct passwd *getpwent();
1250: 
1251:     if (names[uid][0])
1252:         return (&names[uid][0]);
1253:     if (init == 2)
1254:         return (0);
1255:     if (init == 0)
1256:         setpwent(), init = 1;
1257:     while (pw = getpwent()) {
1258:         if (pw->pw_uid >= NUID)
1259:             continue;
1260:         if (names[pw->pw_uid][0])
1261:             continue;
1262:         strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
1263:         if (pw->pw_uid == uid)
1264:             return (&names[uid][0]);
1265:     }
1266:     init = 2;
1267:     endpwent();
1268:     return (0);
1269: }
1270: #endif

Defined functions

b_dconv defined in line 1131; used 2 times
b_emit defined in line 1203; used 1 times
column defined in line 534; used 1 times
compar defined in line 770; used 3 times
getname defined in line 1244; used 2 times
gstat defined in line 694; used 3 times
main defined in line 123; never used
makename defined in line 627; used 3 times
nblock defined in line 581; used 4 times
newline defined in line 524; used 1 times
pdirectory defined in line 393; used 2 times
pem defined in line 446; used 1 times
pentry defined in line 800; used 4 times
pmode defined in line 604; used 1 times
pputchar defined in line 492; used 9 times
readdir defined in line 652; used 1 times
select defined in line 613; used 1 times

Defined variables

Aflg defined in line 95; used 4 times
Cflg defined in line 95; used 13 times
Fflg defined in line 95; used 8 times
Rflg defined in line 95; used 4 times
across defined in line 95; used 3 times
aflg defined in line 94; used 3 times
bflg defined in line 94; used 3 times
cdfirst defined in line 90; used 5 times
cflg defined in line 94; used 2 times
colwidth defined in line 116; used 17 times
curdir defined in line 92; used 2 times
dfirst defined in line 89; used 8 times
dflg defined in line 94; used 3 times
dotp defined in line 107; used 1 times
dtemp defined in line 91; used 7 times
fflg defined in line 94; used 4 times
filewidth defined in line 117; used 9 times
fill defined in line 913; used 7 times
firstp defined in line 106; used 4 times
fixedwidth defined in line 118; used 8 times
flags defined in line 100; used 2 times
flist defined in line 104; used 3 times
gflg defined in line 94; used 3 times
iflg defined in line 94; used 2 times
lastp defined in line 105; used 12 times
lflg defined in line 94; used 8 times
m defined in line 602; used 4 times
  • in line 609(4)
m1 defined in line 592; used 1 times
m2 defined in line 593; used 1 times
m3 defined in line 594; used 1 times
m4 defined in line 595; used 1 times
m5 defined in line 596; used 1 times
m6 defined in line 597; used 1 times
m7 defined in line 598; used 1 times
m8 defined in line 599; used 1 times
m9 defined in line 600; used 1 times
names defined in line 1242; used 5 times
nflg defined in line 95; used 4 times
nopad defined in line 96; used 12 times
obuf defined in line 121; used 1 times
outcol defined in line 119; used 23 times
qflg defined in line 95; used 5 times
rflg defined in line 98; used 4 times
sccsid defined in line 4; never used
sflg defined in line 94; used 4 times
sign defined in line 913; used 7 times
statreq defined in line 102; used 6 times
tabflg defined in line 97; used 6 times
tblocks defined in line 101; used 3 times
tflg defined in line 94; used 3 times
uflg defined in line 94; used 2 times
utmp defined in line 62; used 1 times
  • in line 63
width defined in line 913; used 20 times
xtraent defined in line 103; used 6 times
year defined in line 99; used 2 times

Defined struct's

dchain defined in line 84; used 14 times
lbuf defined in line 69; used 44 times

Defined macros

BIG defined in line 910; used 2 times
ISARG defined in line 115; used 7 times
MAXDIGS defined in line 911; used 3 times
MAXFILEWIDTH defined in line 65; used 2 times
MAXINT defined in line 909; used 2 times
MAXOCT defined in line 908; used 2 times
NFILES defined in line 66; used 2 times
NMAX defined in line 63; used 2 times
NUID defined in line 1240; used 2 times
UCB defined in line 1; used 3 times
UCB_PWHASH defined in line 2; used 2 times
Last modified: 1981-01-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3488
Valid CSS Valid XHTML 1.0 Strict