home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / dirutl / tk_ls.arc / LS.C next >
Text File  |  1989-01-14  |  17KB  |  687 lines

  1. static char title[] = "Ls.com, file list/find program, version 1.00, (14 January 1988)";
  2. static char copyright[] = "Copyright 1989 Timothy L. Kay -- non-commercial use permitted";
  3. static char permission[] = "Permission is hereby granted to distribute freely for non-commercial use only.";
  4. static char me[] = "Timothy L. Kay\nCaltech, 256-80\nPasadena, CA  91125\ntim@csvax.caltech.edu";
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <fcntl.h>
  9. #include <alloc.h>
  10. #include <string.h>
  11. #include <dir.h>
  12. #include <dos.h>
  13. #include <ctype.h>
  14.  
  15. #define STDERR fprintf(stderr,
  16.  
  17. int multi;
  18.  
  19. int flag_1 = 0;
  20. int flag_F = 0;
  21. int flag_R = 0;
  22. int flag_a = 0;
  23. int flag_d = 0;
  24. int flag_f = 0;
  25. int flag_l = 0;
  26. int flag_t = 0;
  27. int flag_v = 0;
  28.  
  29. int value_b = -1;
  30. int value_f = 0;
  31. #define vf_archive 0x01
  32. #define vf_ascii   0x02
  33. #define vf_size    0x04
  34. #define vf_bak  0x08
  35.  
  36. long param_size;
  37. #define PARAM_SIZE_DEFAULT 10000L
  38. long param_percent;
  39. #define PARAM_PERCENT_DEFAULT 90
  40.  
  41. typedef struct {
  42.     char                                                     ff_reserved[21];
  43.     char                                                     ff_attrib;
  44.   struct { unsigned x:5; unsigned m:6; unsigned h:5; } ff_ftime;
  45.   struct { unsigned d:5; unsigned m:4; unsigned y:7; } ff_fdate;
  46.     long                                                     ff_fsize;
  47.     char                                                     ff_name[13];
  48. } FF;
  49. #define SFF sizeof(FF)
  50.  
  51. int    ffirst(char *p, FF *f, int m) {
  52.   return findfirst(p, (struct ffblk *)f, m);
  53. }
  54. int    fnext(FF *f) {
  55.   return findnext((struct ffblk *)f);
  56. }
  57.  
  58. void help() {
  59.     printf("Usage: ls [-c] [?] [--] [-?] [-1FRabltv] [-f[abis[#]]] [file ...]\n");
  60.   printf("   where\n");
  61.     printf("     -,? print this message      c print copyright message\n");
  62.   printf("     1   print files in single column with path prepended\n");
  63.     printf("     F   enable inverse video for directories (or SET TERM=ansi)\n");
  64.   printf("     R   recursively list contents of subdirectories\n");
  65.   printf("     a   list all (including hidden and system) files\n");
  66.   printf("     b#  print files in single column preceded with %%i, i=1..#\n");
  67.   printf("     f   find files that match particular criteria\n");
  68.   printf("         a#  find files that contain > #%% ASCII text (default %d%%)\n", PARAM_PERCENT_DEFAULT);
  69.   printf("         b   find files with extension .bak\n");
  70.   printf("         i   find files with archive bit on\n");
  71.   printf("         s#  find files smaller than # bytes (default %ld bytes)\n", PARAM_SIZE_DEFAULT);
  72.   printf("     l   long format includes file date, time, size, attributes\n");
  73.   printf("     t   list files in time order rather than alphabetic\n");
  74.   printf("     v   verbose details of find decisions\n");
  75.   printf("\n");
  76.   printf("  examples\n");
  77.   printf("     ls                list files in current directory\n");
  78.     printf("     ls -Rfas1000 /    lists all ASCII files smaller than 1000 bytes\n");
  79.   printf("     ls -vRfas1000 /   same but explains why some files do not qualify\n");
  80.     printf("     ls -Rfas / | zoo aI /backup   backs up all ASCII files of reasonable size\n");
  81.   printf("     ls -b2 *.c > temp.bat ; temp cc -DMSDOS   compile all .c files\n");
  82.   exit(0);
  83. }
  84.  
  85. void copyr()
  86. {
  87.     printf("%s\n", title);
  88.     printf("%s\n", copyright);
  89.     printf("%s\n", permission);
  90.     printf("\n");
  91.     printf("%s\n", me);
  92.     exit(0);
  93. }
  94.  
  95. /*
  96.  *  int cmp(char *s, char *t)
  97.  *
  98.  *  Compares strings s and t, and returns an int whose value is
  99.  *
  100.  *    < 0   if   s < t,
  101.  *      0        s == t, or
  102.  *    > 0        s > t.
  103.  *
  104.  *  The comparison is more complex than the one performed by strcmp().
  105.  *  Any sequences of digits are treated as separate fields.  For
  106.  *  example, the string "a100-x" is treated as three fields:  the
  107.  *  string "a", the number 100, and the string "-x".  This way, the
  108.  *  string "a30" is considered less than the string "a100".
  109.  */
  110.  
  111. int cmp(char *s, char *t) {
  112.   char *s1, *t1;
  113.   int s0, t0;
  114.   for (s1 = s, t1 = t; *s1 || *t1; s = s1, t = t1) {
  115.     while (*s1 && 0 == isdigit(*s1)) {
  116.       ++s1;
  117.     }
  118.     while (*t1 && 0 == isdigit(*t1)) {
  119.       ++t1;
  120.     }
  121.     s0 = s1 - s;
  122.     t0 = t1 - t;
  123.     if (s0 < t0) {
  124.       int d = strncmp(s, t, s0);
  125.       if (d) {
  126.         return d;
  127.       }
  128.       return -1;
  129.     } else if (s0 > t0) {
  130.       int d = strncmp(s, t, t0);
  131.       if (d) {
  132.         return d;
  133.       }
  134.       return 1;
  135.     } else {
  136.       int d = strncmp(s, t, s0);
  137.       if (d) {
  138.         return d;
  139.       }
  140.     }
  141.     while (*s1 && isdigit(*s1)) {
  142.       ++s1;
  143.     }
  144.     while (*t1 && isdigit(*t1)) {
  145.       ++t1;
  146.     }
  147.     s0 = s1 - s;
  148.     t0 = t1 - t;
  149.     if (s0 != t0) {
  150.       return s0 - t0;
  151.     } else {
  152.       int d = strncmp(s, t, s0);
  153.       if (d) {
  154.         return d;
  155.       }
  156.     }
  157.   }
  158.   return 0;
  159. }
  160.  
  161. int ncmp(FF *a, FF *b) {
  162.   return strcmp(a->ff_name, b->ff_name);
  163. }
  164.  
  165. int tcmp(FF *a, FF *b) {
  166.   if (a->ff_fdate.y != b->ff_fdate.y) {
  167.     return b->ff_fdate.y - a->ff_fdate.y;
  168.   }
  169.   if (a->ff_fdate.m != b->ff_fdate.m) {
  170.     return b->ff_fdate.m - a->ff_fdate.m;
  171.   }
  172.   if (a->ff_fdate.d != b->ff_fdate.d) {
  173.     return b->ff_fdate.d - a->ff_fdate.d;
  174.   }
  175.   if (a->ff_ftime.h != b->ff_ftime.h) {
  176.     return b->ff_ftime.h - a->ff_ftime.h;
  177.   }
  178.   if (a->ff_ftime.m != b->ff_ftime.m) {
  179.     return b->ff_ftime.m - a->ff_ftime.m;
  180.   }
  181.   if (a->ff_ftime.x != b->ff_ftime.x) {
  182.     return b->ff_ftime.x - a->ff_ftime.x;
  183.   }
  184.   return 0;
  185. }
  186.  
  187. /*
  188.  *  FF *dir(char *s, int m)
  189.  *
  190.  *  Returns a pointer to an array of FF structures consisting of the
  191.  *  filenames which match pattern s along with their attributes.  The
  192.  *  mask m determines what types of files (directories, system, hidden,
  193.  *  etc.) are eligible to be matched.  The last entry of the array has
  194.  *  an empty file name.  If an error occurs, 0 is returned.
  195.  */
  196.  
  197. FF *dir(char *s, int m) {
  198.   int i, n;
  199.   FF *x, *xp;
  200.   FF f;
  201.  
  202.   /*  make a first pass to count files  */
  203.  
  204.   i = ffirst(s, &f, m);
  205.   while (0 == i && 0 == flag_a && '.' == *f.ff_name) {
  206.     i = fnext(&f);
  207.   }
  208.   if (i != 0) {
  209.     return 0;
  210.   }
  211.   for (n = 0; i == 0; ++n) {
  212.     do {
  213.       i = fnext(&f);
  214.     } while (0 == i && 0 == flag_a && '.' == *f.ff_name);
  215.   }
  216.  
  217.   /*  allocate array  */
  218.  
  219.   xp = x = malloc(SFF * (n + 1));
  220.   if (x == 0) {
  221.     return 0;
  222.   }
  223.  
  224.   /*  collect data  */
  225.  
  226.   ffirst(s, &f, m);
  227.   while (0 == flag_a && '.' == *f.ff_name) {
  228.     fnext(&f);
  229.   }
  230.   for (i = 0; i < n; ++i) {
  231.     *xp = f;
  232.     strlwr(xp->ff_name);
  233.     ++xp;
  234.     do {
  235.       fnext(&f);
  236.     } while (0 == flag_a && '.' == *f.ff_name);
  237.   }
  238.   *xp->ff_name = 0;
  239.   /*  sort data  */
  240.  
  241.   if (flag_t) {
  242.     qsort(x, n, SFF, tcmp);
  243.   } else {
  244.     qsort(x, n, SFF, ncmp);
  245.   }
  246.  
  247.   return x;
  248. }
  249.  
  250. void flags(char *s) {
  251.     for (; *s; ++s) {
  252.     switch (*s) {
  253.       case '-':
  254.       case '?': help();
  255.       case '1': flag_1 = 1; flag_l = 0; break;
  256.       case 'C': flag_1 = 0; flag_l = 0; break;
  257.       case 'F': flag_F = 1; break;
  258.       case 'R': flag_R = 1; break;
  259.       case 'a': flag_a = 1; break;
  260.       case 'b':
  261.         flag_1 = 1;
  262.         flag_l = 0;
  263.         if (s[1] && isdigit(s[1])) {
  264.           value_b = s[1] - '0';
  265.           ++s;
  266.         } else {
  267.           value_b = 1;
  268.         }
  269.                 break;
  270.             case 'c': copyr();
  271.       case 'd': flag_d = 1; break;
  272.       case 'f':
  273.         flag_f = 1;
  274.         if (0 == flag_1 && 0 == flag_l) {
  275.           flag_1 = 1;
  276.         }
  277.         for (++s; *s; ++s) {
  278.           switch (*s) {
  279.             case 'a':
  280.               value_f |= vf_ascii;
  281.               param_percent = 0;
  282.               while (isdigit(s[1])) {
  283.                 param_size = 10 * param_percent + *++s - '0';
  284.               }
  285.               if (0 == param_percent) {
  286.                 param_percent = PARAM_PERCENT_DEFAULT;
  287.               }
  288.               break;
  289.             case 'b': value_f |= vf_bak; break;
  290.             case 'i': value_f |= vf_archive; break;
  291.             case 's':
  292.               value_f |= vf_size;
  293.               param_size = 0;
  294.               while (isdigit(s[1])) {
  295.                 param_size = 10 * param_size + *++s - '0';
  296.               }
  297.               if (0 == param_size) {
  298.                 param_size = PARAM_SIZE_DEFAULT;
  299.               }
  300.               break;
  301.             default:
  302.               STDERR "Unknown switch -f%c\n", *s);
  303.               exit(1);
  304.           }
  305.         }
  306.         --s;
  307.         break;
  308.       case 'l': flag_1 = 0; flag_l = 1; break;
  309.       case 't': flag_t = 1; break;
  310.       case 'v': flag_v = 1; break;
  311.       default:
  312.         STDERR "Unknown switch -%c\n", *s);
  313.         exit(1);
  314.     }
  315.   }
  316. }
  317.  
  318. void massage(char *s) {
  319.   if (0 == *s) {
  320.     return;
  321.   }
  322.   for (; *s; ++s) {
  323.     if ('\\' == *s) {
  324.       *s = '/';
  325.     } else if (isupper(*s)) {
  326.       *s = tolower(*s);
  327.     }
  328.   }
  329.   if (*--s == '/') {
  330.     *s = 0;
  331.   }
  332. }
  333.  
  334. void path(char *p, char *s) {
  335.   char *pp;
  336.   strcpy(p, s);
  337.   pp = strrchr(p, '/');
  338.   if (0 == pp) {
  339.     *p = 0;
  340.   } else  {
  341.     pp[1] = 0;
  342.   }
  343. }
  344.  
  345. char month[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  346.  
  347. void outputLong_1(FF *f) {
  348.   if (f->ff_attrib & (FA_DIREC | FA_LABEL)) {
  349.     printf("%c%c%c%c%c%c%c%c   %d %.3s %2d   %2d:%02d           %s\n",
  350.       (f->ff_attrib & 0x80) ? '8' : ' ',
  351.       (f->ff_attrib & 0x40) ? '4' : ' ',
  352.       (f->ff_attrib & FA_ARCH) ? 'a' : '-',
  353.       (f->ff_attrib & FA_DIREC) ? 'd' : '-',
  354.       (f->ff_attrib & FA_LABEL) ? 'v' : '-',
  355.       (f->ff_attrib & FA_SYSTEM) ? 's' : '-',
  356.       (f->ff_attrib & FA_HIDDEN) ? 'h' : '-',
  357.       (f->ff_attrib & FA_RDONLY) ? 'r' : '-',
  358.       f->ff_fdate.y + 1980, month + 3 * (f->ff_fdate.m - 1), f->ff_fdate.d,
  359.       f->ff_ftime.h, f->ff_ftime.m,
  360.       f->ff_name);
  361.   } else {
  362.     printf("%c%c%c%c%c%c%c%c   %d %.3s %2d   %2d:%02d   %6ld  %s\n",
  363.       (f->ff_attrib & 0x80) ? '8' : ' ',
  364.       (f->ff_attrib & 0x40) ? '4' : ' ',
  365.       (f->ff_attrib & FA_ARCH) ? 'a' : '-',
  366.       (f->ff_attrib & FA_DIREC) ? 'd' : '-',
  367.       (f->ff_attrib & FA_LABEL) ? 'v' : '-',
  368.       (f->ff_attrib & FA_SYSTEM) ? 's' : '-',
  369.       (f->ff_attrib & FA_HIDDEN) ? 'h' : '-',
  370.       (f->ff_attrib & FA_RDONLY) ? 'r' : '-',
  371.       f->ff_fdate.y + 1980, month + 3 * (f->ff_fdate.m - 1), f->ff_fdate.d,
  372.       f->ff_ftime.h, f->ff_ftime.m,
  373.       f->ff_fsize, f->ff_name);
  374.   }
  375. }
  376.  
  377. void reverse(char *q, char *p) {
  378.   while (*p) {
  379.     if ('/' == *p) {
  380.       *q++ = '\\';
  381.     } else {
  382.       *q++ = *p;
  383.     }
  384.     ++p;
  385.   }
  386.   *q = 0;
  387. }
  388.  
  389. int qualifies(char *p, FF *f) {
  390.   char fn[MAXPATH];
  391.   sprintf(fn, "%s%s", p, f->ff_name);
  392.   if (0 == (value_f & vf_bak)
  393.       && 0 == strcmp(".bak", f->ff_name + strlen(f->ff_name) - 4)) {
  394.     if (flag_v) {
  395.       STDERR "%s -- skipped (.bak)\n", fn);
  396.     }
  397.     return 0;
  398.   }
  399.   if (f->ff_attrib & FA_DIREC) {
  400.     return 0;
  401.   }
  402.   if ((value_f & vf_archive) && 0 == (f->ff_attrib & FA_ARCH)) {
  403.     if (flag_v) {
  404.       STDERR "%s -- skipped (archive bit off)\n", fn);
  405.     }
  406.     return 0;
  407.   }
  408.   if ((value_f & vf_size) && (param_size < f->ff_fsize)) {
  409.     if (flag_v) {
  410.       STDERR "%s -- skipped (%ld bytes)\n", fn, f->ff_fsize);
  411.     }
  412.     return 0;
  413.   }
  414.   if ((value_f & vf_ascii)) {
  415.     int fd, i, j, c;
  416.     char buf[512];
  417.     fd = open(fn, O_RDONLY | O_BINARY);
  418.     if (fd < 0) {
  419.       perror(fn);
  420.       return 0;
  421.     }
  422.     i = read(fd, buf, sizeof buf);
  423.     if (i < 512 && i < f->ff_fsize) {
  424.       STDERR "1 Cannot read %s\n", fn);
  425.       close(fd);
  426.       return 0;
  427.     }
  428.     for (c = 0, j = 0; j < i; ++j) {
  429.       c += isprint(buf[j]) || isspace(buf[j]);
  430.     }
  431.     if (100L * c < param_percent * i) {
  432.       if (flag_v) {
  433.         STDERR "%s -- skipped (%d%% printable)\n", fn, 100L * c / i);
  434.       }
  435.       close(fd);
  436.       return 0;
  437.     }
  438.     if (512 < f->ff_fsize) {
  439.       lseek(fd, -512L, 2);
  440.       i = read(fd, buf, sizeof buf);
  441.       if (i < 512 && i < f->ff_fsize) {
  442.         STDERR "2 Cannot read %s\n", fn);
  443.         close(fd);
  444.         return 0;
  445.       }
  446.       for (c = 0, j = 0; j < i; ++j) {
  447.         c += isprint(buf[j]) || isspace(buf[j]);
  448.       }
  449.       if (100L * c < param_percent * i) {
  450.         if (flag_v) {
  451.           STDERR "%s -- skipped (%d%% printable)\n", fn, 100L * c / i);
  452.         }
  453.         close(fd);
  454.         return 0;
  455.       }
  456.     }
  457.     if (3 * 512 < f->ff_fsize) {
  458.       lseek(fd, f->ff_fsize / 2L - 256L, 0);
  459.       i = read(fd, buf, sizeof buf);
  460.       if (i < 512 && i < f->ff_fsize) {
  461.         STDERR "3 Cannot read %s\n", fn);
  462.         close(fd);
  463.         return 0;
  464.       }
  465.       for (c = 0, j = 0; j < i; ++j) {
  466.         c += isprint(buf[j]) || isspace(buf[j]);
  467.       }
  468.       if (100L * c < param_percent * i) {
  469.         if (flag_v) {
  470.           STDERR "%s -- skipped (%d%% printable)\n", fn, 100L * c / i);
  471.         }
  472.         close(fd);
  473.         return 0;
  474.       }
  475.     }
  476.     close(fd);
  477.   }
  478.   return 1;
  479. }
  480.  
  481. void outputLong(char *p, FF *f) {
  482.   char q[MAXPATH];
  483.   reverse(q, p);
  484.   for (; *f->ff_name; ++f) {
  485.     if (0 == flag_f || qualifies(p, f)) {
  486.       outputLong_1(f);
  487.     }
  488.   }
  489. }
  490.  
  491. void outputOne(char *p, FF *f) {
  492.   char q[MAXPATH];
  493.   reverse(q, p);
  494.   for (; *f->ff_name; ++f) {
  495.     if (0 == flag_f || qualifies(p, f)) {
  496.       if (0 <= value_b) {
  497.         int i, k;
  498.         for (i = 1; i <= value_b; ++i) {
  499.           printf("%%%d ", i);
  500.         }
  501.         k = 45 - strlen(q);
  502.         if (k < 0) {
  503.           k = 0;
  504.         }
  505.         printf("%s%-*s", q, k, f->ff_name);
  506.         for (; i <= 9; ++i) {
  507.           printf(" %%%d", i);
  508.         }
  509.         printf("\n");
  510.       } else {
  511.         printf("%s%s\n", p, f->ff_name);
  512.       }
  513.     }
  514.   }
  515. }
  516.  
  517. #define SCREENWIDTH 80
  518.  
  519. void outputColumn(FF *f) {
  520.   FF *fp;
  521.   int i, j, n, on_a_line, number_of_lines;
  522.   for (n = 0, fp = f; *fp->ff_name; ++n, ++fp)
  523.     ;
  524.   on_a_line = SCREENWIDTH / 13;
  525.   number_of_lines = (n + on_a_line - 1) / on_a_line;
  526.   for (i = 0; i < number_of_lines; ++i) {
  527.     for (j = 0; j < on_a_line; ++j) {
  528.       int k = j * number_of_lines + i;
  529.       if (k < n) {
  530.                 if (flag_F && (f[k].ff_attrib & FA_DIREC) && isatty(1)) {
  531.           printf(" \033[7m%s\033[0m%s", f[k].ff_name,
  532.                  "            " + strlen(f[k].ff_name));
  533.         } else {
  534.           printf(" %-12.12s", f[k].ff_name);
  535.         }
  536.       }
  537.     }
  538.         printf("\n");
  539.     }
  540. }
  541.  
  542. /*  -d causes the arguments themselves to be output.  This
  543.  *  mode isn't very useful unless some globbing code is
  544.  *  added to c0?.c
  545.  */
  546.  
  547. void list_d(char *s) {
  548.   if (flag_1) {
  549.     printf("%s\n", s);
  550.   } else if (flag_l) {
  551. /*
  552.     outputLong_1(s);
  553. */
  554.   } else {
  555.     printf("%s\n", s);
  556.   }
  557. }
  558.  
  559. /*  -R lists the entire directory tree.  */
  560.  
  561. void list_R(char *s) {
  562.   FF *f, *fp;
  563.   char p[MAXPATH];
  564.  
  565.   path(p, s);
  566.   f = dir(s, flag_a ? 0xef : 0x00);
  567.   if (0 == flag_1) {
  568.     printf("%s:\n", p);
  569.   }
  570.   if (f) {
  571.     if (flag_1) {
  572.       outputOne(p, f);
  573.     } else if (flag_l) {
  574.       outputLong(p, f);
  575.     } else {
  576.       outputColumn(f);
  577.     }
  578.   }
  579.   free(f);
  580.   f = dir(s, flag_a ? 0xff : FA_DIREC);
  581.   if (0 == f) {
  582.     return;
  583.   }
  584.   for (fp = f; *fp->ff_name; ++fp) {
  585.     char r[MAXPATH];
  586.     if ((fp->ff_attrib & FA_DIREC) && '.' != *fp->ff_name) {
  587.       sprintf(r, "%s%s/*.*", p, fp->ff_name);
  588.       list_R(r);
  589.     }
  590.   }
  591.   free(f);
  592. }
  593.  
  594. /*  Without -d and -R, files are listed, and directory contents
  595.     are listed.
  596. */
  597.  
  598. void list(char *s) {
  599.   FF *f;
  600.   char p[MAXPATH];
  601.   f = dir(s, flag_a ? 0xff : FA_DIREC);
  602.   if (0 == f) {
  603.     return;
  604.   }
  605.   path(p, s);
  606.   if (flag_1) {
  607.     outputOne(p, f);
  608.   } else if (flag_l) {
  609.     outputLong(p, f);
  610.   } else {
  611.     outputColumn(f);
  612.   }
  613.   free(f);
  614. }
  615.  
  616. /*  The dir function is called twice.  The first time, we add
  617.  *  "/*.*" to the end of the pattern.  If this fails, we try
  618.  *  without.  We can't just stat it to see if it is a directory
  619.  *  because it may have wildcards, and we'd get its expansion.
  620.  *  We can't compare the names because a directory could
  621.  *  contain a file of the same name.
  622.  */
  623.  
  624. void select(char *s) {
  625.   char fn[MAXPATH];
  626.   FF f;
  627.  
  628.   massage(s);
  629.   sprintf(fn, "%s/*.*", s);
  630.   if (ffirst(fn, &f, 0xff)) {
  631.     strcpy(fn, s);
  632.     if (ffirst(fn, &f, 0xff)) {
  633.       return;
  634.     }
  635.   } else if (multi && 0 == flag_R) {
  636.     printf("%s:\n", s);
  637.   }
  638.  
  639.   if (flag_d) {
  640.     list_d(fn);
  641.   } else if (flag_R) {
  642.     list_R(fn);
  643.   } else {
  644.     list(fn);
  645.   }
  646. }
  647.  
  648. void set_flag_F()
  649. {
  650.     char *ep = getenv("TERM");
  651.     if (ep) {
  652.         flag_F = !strcmp(ep, "ansi") || !strcmp(ep, "vt100");
  653.     }
  654. }
  655.  
  656. void main(int argc, char *argv[]) {
  657.   int i, j, named = 0;
  658.  
  659.     if (argc == 2 && !strcmp(argv[1], "?")) {
  660.         help();
  661.     }
  662.  
  663.     set_flag_F();
  664.  
  665.     for (j = 0, i = 1; i < argc; ++i) {
  666.     if (argv[i][0] != '-') {
  667.       ++j;
  668.     }
  669.   }
  670.   if (j < 2) {
  671.     multi = 0;
  672.   } else {
  673.     multi = 1;
  674.   }
  675.   for (i = 1; i < argc; ++i) {
  676.     if (argv[i][0] == '-') {
  677.       flags(argv[i] + 1);
  678.     } else {
  679.       named = 1;
  680.       select(argv[i]);
  681.     }
  682.   }
  683.   if (0 == named) {
  684.     select("*.*");
  685.   }
  686. }
  687.