home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / 2bsd.tar.gz / 2bsd.tar / upgrade / src / ls.c < prev    next >
C/C++ Source or Header  |  1979-04-22  |  12KB  |  694 lines

  1. #
  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. struct {
  44.     int    fdes;
  45.     int    nleft;
  46.     char    *nextc;
  47.     char    buff[512];
  48. } inf, obuf;
  49.  
  50. struct ibuf {
  51.     int    idev;
  52.     int    inum;
  53.     int    iflags;
  54.     char    inl;
  55.     char    iuid;
  56.     char    igid;
  57.     char    isize0;
  58.     int    isize;
  59.     int    iaddr[8];
  60.     char    *iatime[2];
  61.     char    *imtime[2];
  62. };
  63.  
  64. struct lbuf {
  65.     char    lname[15];
  66.     int    lnum;
  67.     int    lflags;
  68.     char    lnl;
  69.     char    luid;
  70.     char    lgid;
  71.     char    lsize0;
  72.     int    lsize;
  73.     char    *lmtime[2];
  74.     unsigned int lquot[2];
  75. };
  76.  
  77. struct lbufx {
  78.     char    *namep;
  79. };
  80.  
  81. int    aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, nflg, Aflg;
  82. int    cflg, qflg, across;
  83. int    nopad;
  84. int    rflg    1;
  85. char    *year;
  86. int    flags;
  87. int    uidfil    -1;
  88. int    lastuid    -1;
  89. char    tbuf[16];
  90. int    tblocks;
  91. int    statreq;
  92. extern    end;
  93. struct    lbuf    *lastp    &end;
  94. struct    lbuf    *rlastp    &end;
  95. char    *dotp    ".";
  96.  
  97. #define    IFMT    060000
  98. #define    DIR    0100000
  99. #define    CHR    020000
  100. #define    BLK    040000
  101. #define    ISARG    01000
  102. #define    LARGE    010000
  103. #define    STXT    010000
  104. #define    SUID    04000
  105. #define    SGID    02000
  106. #define    ROWN    0400
  107. #define    WOWN    0200
  108. #define    XOWN    0100
  109. #define    RGRP    040
  110. #define    WGRP    020
  111. #define    XGRP    010
  112. #define    ROTH    04
  113. #define    WOTH    02
  114. #define    XOTH    01
  115. #define    RSTXT    01000
  116.  
  117. int    colwidth 16;
  118. int    outcol;
  119.  
  120. main(argc, argv)
  121.     int argc;
  122.     char **argv;
  123. {
  124.     char *cp;
  125.     int i, j;
  126.     register struct lbuf *ep;
  127.     register struct lbuf *slastp;
  128.     struct lbuf lb;
  129.     int t;
  130.     int compar();
  131.  
  132.     obuf.fdes = 1;
  133.     qflg = gtty(1, &obuf.buff) == 0;
  134.     /*
  135.      * If the standard output is not a teletype,
  136.      * then we default to one-per-line format
  137.      * otherwise decide between stream and
  138.      * columnar based on our name.
  139.      */
  140.     if (qflg) {
  141.         cflg = 1;
  142.         for (cp = argv[0]; cp[0] && cp[1]; cp++)
  143.             continue;
  144.         /*
  145.          * Name ends in l => stream
  146.          */
  147.         if (cp[0] == 'l')
  148.             nopad = 1, cflg = 0;
  149.         /*
  150.          * ... if doesn't end in l or s ==> columns sorted across
  151.          */
  152.         else if (cp[0] != 's')
  153.             across = 1;
  154.     }
  155.     time(lb.lmtime);
  156.     year = lb.lmtime[0] - 245; /* 6 months ago */
  157.     while (--argc > 0 && *argv[1] == '-') {
  158.         argv++;
  159.         while (*++*argv) switch (**argv) {
  160.         /*
  161.          * c - force columnar output
  162.          */
  163.         case 'c':
  164.             cflg = 1;
  165.             nopad = 0;
  166.             continue;
  167.         /*
  168.          * m - force stream output
  169.          */
  170.         case 'm':
  171.             cflg = 0;
  172.             nopad = 1;
  173.             continue;
  174.         /*
  175.          * x - force sort across
  176.          */
  177.         case 'x':
  178.             across = 1;
  179.             nopad = 0;
  180.             cflg = 1;
  181.             continue;
  182.         /*
  183.          * q - force ?'s in output
  184.          */
  185.         case 'q':
  186.             qflg = 1;
  187.             continue;
  188.         /*
  189.          * 1 - force 1/line in output
  190.          */
  191.         case '1':
  192.             cflg = 0;
  193.             nopad = 0;
  194.             continue;
  195.         /* STANDARD FLAGS */
  196.         case 'a':
  197.             aflg++;
  198.             continue;
  199.         case 'A':
  200.             Aflg++;
  201.             continue;
  202.  
  203.         case 's':
  204.             colwidth = 24;
  205.             sflg++;
  206.             statreq++;
  207.             continue;
  208.  
  209.         case 'd':
  210.             dflg++;
  211.             continue;
  212.  
  213.         /*
  214.          * n - don't look in password file
  215.          */
  216.         case 'n':
  217.             nflg++;
  218.         case 'l':
  219.             lflg++;
  220.             statreq++;
  221.             continue;
  222.  
  223.         case 'r':
  224.             rflg = -1;
  225.             continue;
  226.  
  227.         case 't':
  228.             tflg++;
  229.             statreq++;
  230.             continue;
  231.  
  232.         case 'u':
  233.             uflg++;
  234.             continue;
  235.  
  236.         case 'i':
  237.             colwidth = 24;
  238.             iflg++;
  239.             continue;
  240.  
  241.         case 'f':
  242.             fflg++;
  243.             continue;
  244.  
  245.         default:
  246.             continue;
  247.         }
  248.     }
  249.     if (fflg) {
  250.         aflg++;
  251.         lflg = 0;
  252.         sflg = 0;
  253.         tflg = 0;
  254.         statreq = 0;
  255.     }
  256.     if(lflg) {
  257.         cflg = 0;
  258.         t = "/etc/passwd";
  259.         nopad = 0;
  260.         colwidth = 70;
  261.         uidfil = open(t, 0);
  262.     }
  263.     if (argc==0) {
  264.         argc++;
  265.         argv = &dotp - 1;
  266.     }
  267.     for (i=0; i < argc; i++) {
  268.         if ((ep = gstat(*++argv, 1))==0)
  269.             continue;
  270.         ep->namep = *argv;
  271.         ep->lflags =| ISARG;
  272.     }
  273.     qsort(&end, lastp - &end, sizeof *lastp, compar);
  274.     slastp = lastp;
  275.     for (ep = &end; ep<slastp; ep++) {
  276.         if (ep->lflags&DIR && dflg==0 || fflg) {
  277.             if (argc>1) {
  278.                 printf("\n%s:\n", ep->namep);
  279.             }
  280.             lastp = slastp;
  281.             readdir(ep->namep);
  282.             if (fflg==0)
  283.                 qsort(slastp,lastp - slastp,sizeof *lastp,compar);
  284.             if (statreq) {
  285.                 printf("total %s", locv(0, tblocks));
  286.             }
  287.             pem(slastp, lastp);
  288.             newline();
  289.         } else 
  290.             pentry(ep);
  291.     }
  292.     if (outcol)
  293.         putc('\n', &obuf);
  294.     fflush(&obuf);
  295.     exit(0);
  296. }
  297.  
  298. pem(slp, lp)
  299.     register struct lbuf *slp, *lp;
  300. {
  301.     int ncols, nrows, row, col;
  302.     register struct lbuf *ep;
  303.  
  304.     ncols = 80 / colwidth;
  305.     if (ncols == 1 || cflg == 0) {
  306.         for (ep = slp; ep < lp; ep++)
  307.             pentry(ep);
  308.         return;
  309.     }
  310.     if (across) {
  311.         for (ep = slp; ep < lp; ep++)
  312.             pentry(ep);
  313.         return;
  314.     }
  315.     if (statreq)
  316.         slp--;
  317.     nrows = (lp - slp - 1) / ncols + 1;
  318.     for (row = 0; row < nrows; row++) {
  319.         col = row == 0 && statreq;
  320.         for (; col < ncols; col++) {
  321.             ep = slp + (nrows * col) + row;
  322.             if (ep < lp)
  323.                 pentry(ep);
  324.         }
  325.         if (outcol)
  326.             printf("\n");
  327.     }
  328. }
  329.  
  330. putchar(c)
  331.     char c;
  332. {
  333.  
  334.     switch (c) {
  335.         case '\t':
  336.             outcol = (outcol + 8) &~ 7;
  337.             break;
  338.         case '\n':
  339.             outcol = 0;
  340.             break;
  341.         default:
  342.             if (qflg && (c < ' ' || c >= 0177))
  343.                 c = '?';
  344.             outcol++;
  345.             break;
  346.     }
  347.     putc(c, &obuf);
  348. }
  349.  
  350. newline()
  351. {
  352.     if (outcol)
  353.         putc('\n', &obuf);
  354.     outcol = 0;
  355. }
  356.  
  357. column()
  358. {
  359.     register int i, j;
  360.  
  361.     if (outcol == 0)
  362.         return;
  363.     if (nopad) {
  364.         putc(',', &obuf);
  365.         outcol++;
  366.         if (outcol + colwidth + 2 > 80) {
  367.             putc('\n', &obuf);
  368.             outcol = 0;
  369.             return;
  370.         }
  371.         putc(' ', &obuf);
  372.         outcol++;
  373.         return;
  374.     }
  375.     if (cflg == 0) {
  376.         putc('\n', &obuf);
  377.         return;
  378.     }
  379.     if ((outcol / colwidth + 2) * colwidth > 80) {
  380.         putc('\n', &obuf);
  381.         outcol = 0;
  382.         return;
  383.     }
  384.     do {
  385.         i = colwidth - outcol % colwidth;
  386.         j = (outcol + 8) &~ 7;
  387.         if (j - outcol > i)
  388.             break;
  389.         putc('\t', &obuf);
  390.         outcol = j;
  391.     } while (outcol % colwidth);
  392.     while (outcol % colwidth) {
  393.         outcol++;
  394.         putc(' ', &obuf);
  395.     }
  396. }
  397.  
  398. pentry(ap)
  399. struct lbuf *ap;
  400. {
  401.     struct { char dminor, dmajor;};
  402.     register t;
  403.     register struct lbuf *p;
  404.     register char *cp;
  405.  
  406.     p = ap;
  407.     if (p->lnum == -1)
  408.         return;
  409.     column();
  410.     if (iflg)
  411.         if (nopad && !lflg)
  412.             printf("%d ", p->lnum);
  413.         else
  414.             printf("%4d ", p->lnum);
  415.     if (lflg) {
  416.         pmode(p);
  417.         printf("%3d ", p->lnl&0377);
  418.         t = /* p->lgid<<8 | */ (p->luid&0377);
  419.         if (nflg == 0 && getpw(t, tbuf)==0) {
  420.             char *cp = tbuf;
  421.             while (*cp && *cp != ':') cp++; *cp = 0;
  422.             printf("%-8.8s", tbuf);
  423.         } else
  424.             printf("%8d", t);
  425.         if (p->lflags & (BLK|CHR)) {
  426.             if (p->lflags&CHR && p->lsize == -1)
  427.                 if (p->lquot[0] < 10000 && p->lquot[1] < 10000)
  428.                     printf("%4d/%4d",
  429.                         p->lquot[0], p->lquot[1]);
  430.                 else
  431.                     printf("%u/%u",
  432.                         p->lquot[0], p->lquot[1]);
  433.             else
  434.                 printf("%4d,%4d", p->lsize.dmajor&0477,
  435.                     p->lsize.dminor&0377);
  436.         } else
  437.             printf("%9s", locv(p->lsize0&0377, p->lsize));
  438.  
  439.     }
  440.     if (sflg) {
  441.         t = nblock(p->lsize0&0377, p->lsize);
  442.         if (nopad && !lflg)
  443.             printf("%s ", locv(0, t));
  444.         else
  445.             printf("%4s ", locv(0, t));
  446.     }
  447.     if (lflg) {
  448.         if (!sflg)
  449.             putchar(' ');
  450.         cp = ctime(p->lmtime);
  451.         if(p->lmtime[0] < year)
  452.             printf("%-7.7s %-4.4s ", cp+4, cp+20); else
  453.             printf("%-12.12s ", cp+4);
  454.     }
  455.     if (p->lflags&ISARG)
  456.         printf("%s", p->namep);
  457.     else
  458.         printf("%.14s", p->lname);
  459. }
  460.  
  461. nblock(size0, size)
  462. int size0, size;
  463. {
  464.     register int n;
  465.  
  466.     n = ldiv(size0&0377, size, 512);
  467.     if (size&0777)
  468.         n++;
  469.     if (n>8)
  470.         n =+ (n+255)/256;
  471.     return(n);
  472. }
  473.  
  474. int    m0[] { 3, DIR, 'd', BLK, 'b', CHR, 'c', '-'};
  475. int    m1[] { 1, ROWN, 'r', '-' };
  476. int    m2[] { 1, WOWN, 'w', '-' };
  477. int    m3[] { 2, SUID, 's', XOWN, 'x', '-' };
  478. int    m1a[] { 1, RGRP, 'r', '-' };
  479. int    m1b[] { 1, WGRP, 'w', '-' };
  480. int    m1c[] { 2, SGID, 's', XGRP, 'x', '-' };
  481. int    m4[] { 1, ROTH, 'r', '-' };
  482. int    m5[] { 1, WOTH, 'w', '-' };
  483. int    m6[] { 2, STXT, 't', XOTH, 'x', '-' };
  484.  
  485. int    *m[] { m0, m1, m2, m3, m1a, m1b, m1c, m4, m5, m6};
  486.  
  487. pmode(ptr)
  488. char *ptr;
  489. {
  490.     register int **mp;
  491.     register struct lbuf *p;
  492.  
  493.     p = ptr;
  494.     flags = p->lflags;
  495.     if (flags&CHR && p->lsize == -1)
  496.         putchar('q');
  497.     else
  498.         select(m[0]);
  499.     for (mp = &m[1]; mp < &m[10];)
  500.         select(*mp++);
  501. }
  502.  
  503. select(pairp)
  504. int *pairp;
  505. {
  506.     register int n, *ap;
  507.  
  508.     ap = pairp;
  509.     n = *ap++;
  510.     while (--n>=0 && (flags&*ap++)==0)
  511.         ap++;
  512.     putchar(*ap);
  513. }
  514.  
  515. makename(dir, file)
  516. char *dir, *file;
  517. {
  518.     static char dfile[100];
  519.     register char *dp, *fp;
  520.     register int i;
  521.  
  522.     dp = dfile;
  523.     fp = dir;
  524.     while (*fp)
  525.         *dp++ = *fp++;
  526.     *dp++ = '/';
  527.     fp = file;
  528.     for (i=0; i<14; i++)
  529.         *dp++ = *fp++;
  530.     *dp = 0;
  531.     return(dfile);
  532. }
  533.  
  534. readdir(dir)
  535. char *dir;
  536. {
  537.     static struct {
  538.         int    dinode;
  539.         char    dname[14];
  540.     } dentry;
  541.     register char *p;
  542.     register int j;
  543.     register struct lbuf *ep;
  544.  
  545.     if (fopen(dir, &inf) < 0) {
  546.         newline();
  547.         printf("%s unreadable\n", dir);
  548.         return;
  549.     }
  550.     tblocks = 0;
  551.     for(;;) {
  552.         p = &dentry;
  553.         for (j=0; j<16; j++)
  554.             *p++ = getc(&inf);
  555.         if (dentry.dinode==0
  556.          || aflg==0 && dentry.dname[0]=='.' && (
  557.             !Aflg ||
  558.            dentry.dname[1] == 0 || (dentry.dname[1] == '.'
  559.            && dentry.dname[2] == 0)))
  560.             continue;
  561.         if (dentry.dinode == -1)
  562.             break;
  563.         ep = gstat(makename(dir, dentry.dname), 0);
  564.         if (ep->lnum != -1)
  565.             ep->lnum = dentry.dinode;
  566.         for (j=0; j<14; j++)
  567.             ep->lname[j] = dentry.dname[j];
  568.     }
  569.     close(inf.fdes);
  570. }
  571.  
  572. gstat(file, argfl)
  573. char *file;
  574. {
  575.     struct ibuf statb;
  576.     register struct lbuf *rep;
  577.  
  578.     if (lastp+1 >= rlastp) {
  579.         sbrk(512);
  580.         rlastp.idev =+ 512;
  581.     }
  582.     rep = lastp;
  583.     lastp++;
  584.     rep->lflags = 0;
  585.     rep->lnum = 0;
  586.     if (argfl || statreq) {
  587.         if (stat(file, &statb)<0) {
  588.             newline();
  589.             printf("%s not found\n", file);
  590.             statb.inum = -1;
  591.             statb.isize0 = 0;
  592.             statb.isize = 0;
  593.             statb.iflags = 0;
  594.             if (argfl) {
  595.                 lastp--;
  596.                 return(0);
  597.             }
  598.         }
  599.         rep->lnum = statb.inum;
  600.         statb.iflags =& ~DIR;
  601.         if ((statb.iflags&IFMT) == 060000) {
  602.             statb.iflags =& ~020000;
  603.         } else if ((statb.iflags&IFMT)==040000) {
  604.             statb.iflags =& ~IFMT;
  605.             statb.iflags =| DIR;
  606.         }
  607.         statb.iflags =& ~ LARGE;
  608.         if (statb.iflags & RSTXT)
  609.             statb.iflags =| STXT;
  610.         statb.iflags =& ~ RSTXT;
  611.         rep->lflags = statb.iflags;
  612.         rep->luid = statb.iuid;
  613.         rep->lgid = statb.igid;
  614.         rep->lnl = statb.inl;
  615.         rep->lsize0 = statb.isize0;
  616.         rep->lsize = statb.isize;
  617.         if (rep->lflags & (BLK|CHR) && lflg) {
  618.             rep->lsize = statb.iaddr[0];
  619.             rep->lquot[0] = statb.iaddr[1];
  620.             rep->lquot[1] = statb.iaddr[2];
  621.         }
  622.         rep->lmtime[0] = statb.imtime[0];
  623.         rep->lmtime[1] = statb.imtime[1];
  624.         if(uflg) {
  625.             rep->lmtime[0] = statb.iatime[0];
  626.             rep->lmtime[1] = statb.iatime[1];
  627.         }
  628.         tblocks =+ nblock(statb.isize0, statb.isize);
  629.     }
  630.     return(rep);
  631. }
  632.  
  633. compar(ap1, ap2)
  634. struct lbuf *ap1, *ap2;
  635. {
  636.     register struct lbuf *p1, *p2;
  637.     register int i;
  638.     int j;
  639.     struct { char *charp;};
  640.  
  641.     p1 = ap1;
  642.     p2 = ap2;
  643.     if (dflg==0) {
  644.         if ((p1->lflags&(DIR|ISARG)) == (DIR|ISARG)) {
  645.             if ((p2->lflags&(DIR|ISARG)) != (DIR|ISARG))
  646.                 return(1);
  647.         } else {
  648.             if ((p2->lflags&(DIR|ISARG)) == (DIR|ISARG))
  649.                 return(-1);
  650.         }
  651.     }
  652.     if (tflg) {
  653.         i = 0;
  654.         if (p2->lmtime[0] > p1->lmtime[0])
  655.             i++;
  656.         else if (p2->lmtime[0] < p1->lmtime[0])
  657.             i--;
  658.         else if (p2->lmtime[1] > p1->lmtime[1])
  659.             i++;
  660.         else if (p2->lmtime[1] < p1->lmtime[1])
  661.             i--;
  662.         return(i*rflg);
  663.     }
  664.     if (p1->lflags&ISARG)
  665.         p1 = p1->namep;
  666.     else
  667.         p1 = p1->lname;
  668.     if (p2->lflags&ISARG)
  669.         p2 = p2->namep;
  670.     else
  671.         p2 = p2->lname;
  672.     for (;;)
  673.         if ((j = *p1.charp++ - *p2.charp++) || p1.charp[-1]==0)
  674.             return(rflg*j);
  675.     return(0);
  676. }
  677.  
  678. strcpy(to, from)
  679.     char *to, *from;
  680. {
  681.  
  682.     while (*to++ = *from++)
  683.         continue;
  684. }
  685.  
  686. strcat(to, from)
  687.     char *to, *from;
  688. {
  689.  
  690.     while (*to)
  691.         to++;
  692.     strcpy(to, from);
  693. }
  694.