home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / ls.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  12KB  |  662 lines

  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.  
  48. #define    NFILES    1024
  49. FILE    *pwdf, *dirf;
  50.  
  51. struct lbuf {
  52.     union {
  53.         char    lname[15];
  54.         char    *namep;
  55.     } ln;
  56.     char    ltype;
  57.     short    lnum;
  58.     short    lflags;
  59.     short    lnl;
  60.     short    luid;
  61.     short    lgid;
  62.     long    lsize;
  63.     long    lmtime;
  64. };
  65.  
  66. int    aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg;
  67. int    Aflg, nflg, qflg, across;
  68. int    nopad;
  69. char    buff[32];
  70. int    rflg    1;
  71. long    year;
  72. int    flags;
  73. int    lastuid    -1;
  74. char    tbuf[16];
  75. long    tblocks;
  76. int    statreq;
  77. struct    lbuf    *flist[NFILES];
  78. struct    lbuf    **lastp = flist;
  79. struct    lbuf    **firstp = flist;
  80. char    *dotp    ".";
  81.  
  82. char    *makename();
  83. struct    lbuf *gstat();
  84. char    *ctime();
  85. long    nblock();
  86.  
  87. #define    ISARG    0100000
  88. int    colwidth 15;
  89. int    outcol;
  90.  
  91. char    obuf[BUFSIZ];
  92.  
  93. main(argc, argv)
  94. char *argv[];
  95. {
  96.     int i;
  97.     register struct lbuf *ep, **ep1;
  98.     register struct lbuf **slastp;
  99.     struct lbuf **epp;
  100.     struct lbuf lb;
  101.     char *t;
  102.     char *cp;
  103.     int compar();
  104.  
  105.     Aflg = getuid() == 0;
  106.     setbuf(stdout, obuf);
  107.     time(&lb.lmtime);
  108.     year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */
  109.     qflg = gtty(1, buff) == 0;
  110.     /*
  111.      * If the standard output is not a teletype,
  112.      * then we default to one-per-line format
  113.      * otherwise decide between stream and
  114.      * columnar based on our name.
  115.      */
  116.     if (qflg) {
  117.         cflg = 1;
  118.         for (cp = argv[0]; cp[0] && cp[1]; cp++)
  119.             continue;
  120.         /*
  121.          * Name ends in l => stream
  122.          */
  123.         if (cp[0] == 'l')
  124.             nopad = 1, cflg = 0;
  125.         /*
  126.          * ... if doesn't end in l or s ==> columns sorted across
  127.          *
  128.         else if (cp[0] == 's')
  129.             across = 1;
  130.          */
  131.     }
  132.     if (--argc > 0 && *argv[1] == '-') {
  133.         argv++;
  134.         while (*++*argv) switch (**argv) {
  135.         /*
  136.          * c - force columnar output
  137.          */
  138.         case 'c':
  139.             cflg = 1;
  140.             nopad = 0;
  141.             continue;
  142.         /*
  143.          * m - force stream output
  144.          */
  145.         case 'm':
  146.             cflg = 0;
  147.             nopad = 1;
  148.             continue;
  149.         /*
  150.          * x - force sort across
  151.          */
  152.         case 'x':
  153.             across = 1;
  154.             nopad = 0;
  155.             cflg = 1;
  156.             continue;
  157.         /*
  158.          * q - force ?'s in output
  159.          */
  160.         case 'q':
  161.             qflg = 1;
  162.             continue;
  163.         /*
  164.          * 1 - force 1/line in output
  165.          */
  166.         case '1':
  167.             cflg = 0;
  168.             nopad = 0;
  169.             continue;
  170.         /* STANDARD FLAGS */
  171.         case 'a':
  172.             aflg++;
  173.             continue;
  174.  
  175.         case 'A':
  176.             Aflg = !Aflg;
  177.             continue;
  178.  
  179.         case 's':
  180.             colwidth =+ 5;
  181.             sflg++;
  182.             statreq++;
  183.             continue;
  184.  
  185.         case 'd':
  186.             dflg++;
  187.             continue;
  188.  
  189.         /*
  190.          * n - don't look in password file
  191.          */
  192.         case 'n':
  193.             nflg++;
  194.         case 'l':
  195.             lflg++;
  196.             statreq++;
  197.             continue;
  198.  
  199.         case 'r':
  200.             rflg = -1;
  201.             continue;
  202.  
  203.         case 't':
  204.             tflg++;
  205.             statreq++;
  206.             continue;
  207.  
  208.         case 'u':
  209.             uflg++;
  210.             continue;
  211.  
  212.         case 'i':
  213.             colwidth =+ 5;
  214.             iflg++;
  215.             continue;
  216.  
  217.         case 'f':
  218.             fflg++;
  219.             continue;
  220.  
  221.         case 'g':
  222.             gflg++;
  223.             continue;
  224.  
  225.         default:
  226.             continue;
  227.         }
  228.         argc--;
  229.     }
  230.     if (fflg) {
  231.         aflg++;
  232.         lflg = 0;
  233.         sflg = 0;
  234.         tflg = 0;
  235.         statreq = 0;
  236.     }
  237.     if(lflg) {
  238.         cflg = 0;
  239.         t = "/etc/passwd";
  240.         if (gflg)
  241.             t = "/etc/group";
  242.         nopad = 0;
  243.         colwidth = 70;
  244.         pwdf = fopen(t, "r");
  245.     }
  246.     if (argc==0) {
  247.         argc++;
  248.         argv = &dotp - 1;
  249.     }
  250.     for (i=0; i < argc; i++) {
  251.         if ((ep = gstat(*++argv, 1))==NULL)
  252.             continue;
  253.         ep->ln.namep = *argv;
  254.         ep->lflags =| ISARG;
  255.     }
  256.     qsort(firstp, lastp - firstp, sizeof *lastp, compar);
  257.     slastp = lastp;
  258.     for (epp=firstp; epp<slastp; epp++) {
  259.         ep = *epp;
  260.         if (ep->ltype=='d' && dflg==0 || fflg) {
  261.             if (argc>1)
  262.                 printf("\n%s:\n", ep->ln.namep);
  263.             lastp = slastp;
  264.             readdir(ep->ln.namep);
  265.             if (fflg==0)
  266.                 qsort(slastp,lastp - slastp,sizeof *lastp,compar);
  267.             if (lflg || sflg)
  268.                 printf("total %D", tblocks);
  269.             pem(slastp, lastp);
  270.             newline();
  271.         } else 
  272.             pentry(ep);
  273.     }
  274.     if (outcol)
  275.         putc('\n', stdout);
  276.     fflush(stdout);
  277. }
  278.  
  279. pem(slp, lp)
  280.     register struct lbuf **slp, **lp;
  281. {
  282.     int ncols, nrows, row, col;
  283.     register struct lbuf **ep;
  284.  
  285.     ncols = 80 / colwidth;
  286.     if (ncols == 1 || cflg == 0) {
  287.         for (ep = slp; ep < lp; ep++)
  288.             pentry(*ep);
  289.         return;
  290.     }
  291. /*
  292.     if (across) {
  293.         for (ep = slp; ep < lp; ep++)
  294.             pentry(*ep);
  295.         return;
  296.     }
  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.         putchar(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.  
  644. #include    <stdio.h>
  645.  
  646. _strout(count, string, adjust, file, fillch)
  647. register char *string;
  648. register count;
  649. register int adjust;
  650. register struct _iobuf *file;
  651. {
  652.     if (adjust < 0) {
  653.         if (*string=='-' && fillch=='0') {
  654.             pputchar(*string++, file); count--;
  655.         }
  656.         adjust= -adjust;
  657.         while (--adjust>=0) pputchar(fillch, file);
  658.     }
  659.     while (--count>=0) pputchar(*string++, file);
  660.     while (--adjust>=0) pputchar(fillch, file);
  661. }
  662.