home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / S12442.ZIP / LS.C < prev    next >
C/C++ Source or Header  |  1989-07-31  |  17KB  |  534 lines

  1. /* ls.c RHS 4/6/85 rev. 10/10/85, rev. again 7/10/88, rev. again 7/89
  2.  * this module contains ls(), like the UNIX ls
  3.  *
  4.  * modified for OS/2 7/10/88
  5.  * modified for OS/2 directory server 7/15/89
  6.  *
  7.  *
  8.  
  9.     LS is a directory utility patterned after the UNIX counterpart by the
  10.     same name. Run it with:
  11.  
  12.    LS [-flscpternda<rhsad>?] [<list of files>]
  13.  
  14.     The options are explained by running:
  15.  
  16.     LS -?
  17.  
  18.     The list of files are any filespecs (with paths if not in default dir).
  19.  
  20.  */
  21.  
  22.  
  23.  
  24. #define INCL_SUB
  25. #define INCL_DOS
  26. #include<os2.h>
  27. #include<stdio.h>
  28. #include<string.h>
  29. #include<ctype.h>
  30. #include<stdlib.h>
  31. #include<stddef.h>
  32. #include<malloc.h>
  33. #include<conio.h>
  34. #include"di.h"
  35.  
  36. #define A_NORMAL        0x0000
  37. #define A_READONLY      0x0001
  38. #define A_HIDDEN        0x0002
  39. #define A_SYSTEM        0x0004
  40. #define A_VOLLABEL      0x0008
  41.  
  42. #define A_DIRECTORY     0x0010
  43. #define A_ARCHIVE       0x0020
  44. #define A_UNUSED0       0x0040
  45. #define A_UNUSED1       0x0080
  46.  
  47. #define A_UNUSED2       0x0100
  48. #define A_UNUSED3       0x0200
  49. #define A_UNUSED4       0x0400
  50. #define A_UNUSED5       0x0800
  51.  
  52. #define A_UNUSED6       0x1000
  53. #define A_UNUSED7       0x2000
  54. #define A_UNUSED8       0x4000
  55. #define A_UNUSED9       0x8000
  56.  
  57.  
  58. #define MAXENTRIES    2000
  59. #define MAXPATH        66
  60. #define MAXDIRS        60
  61. #define PAGELEN        23
  62. #define NUMCOLS        5
  63. #define EXTSIZE        4
  64.  
  65.  
  66. #define ERROR -1
  67.  
  68. #define newline()            printf("\n")
  69. #define opposite(val)   (Options.reverse_order ? -val : val)
  70.  
  71. unsigned Pagelen;
  72. unsigned entries = 0;                                    /* offset into entryptrs    */
  73. PFILEFINDBUF entryptrs[MAXENTRIES];                    /* ptrs to entries            */
  74. unsigned dirdrive = 0;
  75.  
  76. char *wild_arg = "*.*";
  77. char *blanks = "   ";
  78.  
  79. struct _options
  80.     {
  81.     USHORT ext_sort;
  82.     USHORT long_format;
  83.     USHORT time_sort;
  84.     USHORT reverse_order;
  85.     USHORT dir_format;
  86.     USHORT column_format;
  87.     USHORT file_format;
  88.     USHORT paging;
  89.     USHORT single_column;
  90.     USHORT no_sort;
  91.     USHORT attrval;
  92.     } Options;
  93.  
  94. long totalspace = 0L;
  95. long availspace = 0L;
  96.  
  97. void        main(int argc,char **argv);
  98. void        ls(int argc, char **argv);
  99. void        get_freespace(unsigned drive, long *totalspace, long *availspace);
  100. void        print_entries(void);
  101. int        qscmp(PFILEFINDBUF *p1, PFILEFINDBUF *p2);
  102. int        set_options(char *opt);
  103. void        dopage(USHORT c);
  104. void        usage(void);
  105. int        haswild(char *str);
  106. void        makedirname(char *to,char *from);
  107. void        set_attribute_values(char *str, unsigned attribute);
  108. unsigned    get_attrval(char *c);
  109. int        column_lines(int num);
  110. BOOL        read_options(int *argc, char ***argv);
  111.  
  112. void main(int argc,char **argv)
  113.     {
  114.     ls(argc,argv);
  115.     }
  116.  
  117. void ls(int argc, char **argv)
  118.    {
  119.     VIOMODEINFO v;
  120.     PVOID    header = NULL, resulthdl;
  121.     USHORT i, j, numresults, numrequests;
  122.     PCH    curdir;
  123.  
  124.     if(!read_options(&argc, &argv))                    /* read/set the options        */
  125.         return;
  126.  
  127.     for( i = 1; i < argc; i++)                            /* get each filespec         */
  128.         DiMakeRequest(&header, argv[i], Options.attrval);
  129.  
  130.     DiSendRequest(header);                                /* send the request            */
  131.  
  132.     DiGetNumResults(header, &numresults, &numrequests);
  133.  
  134.     for( i = 0; i < numrequests; i++)                /* for each request            */
  135.         {
  136.         DiGetResultHdl(header, i, &numresults, &resulthdl);
  137.  
  138.         if(!i)
  139.             {
  140.             curdir = DiGetResultDir(resulthdl);
  141.             get_freespace((*curdir-'A'+1), &totalspace, &availspace);
  142.             }
  143.  
  144.         for( j = 0; j < numresults; j++)                /* get each filename in req.*/
  145.             if(!j)
  146.                 DiGetFirstResultPtr(resulthdl,&entryptrs[entries++]);
  147.             else
  148.                 DiGetNextResultPtr(resulthdl,&entryptrs[entries++]);
  149.         }
  150.  
  151.     if(!Options.no_sort)                                    /* if sort required, do it    */
  152.         qsort(entryptrs, entries, sizeof(PFILEFINDBUF), qscmp);
  153.  
  154.    if(!Options.column_format && !Options.single_column)
  155.       Options.long_format = TRUE;
  156.  
  157.    if(Options.paging)                                    /* if paging required        */
  158.       {
  159.       v.cb = sizeof(v);
  160.       VioGetMode(&v,0);
  161.       Pagelen = v.row-2;                                /* set page length            */
  162.       }
  163.  
  164.    print_entries();                                        /* print the results            */
  165.  
  166.     DiDestroyRequest(&header);                            /* throw out results            */
  167.  
  168.     DosExit(EXIT_PROCESS,0);                            /* I'm outta here                */
  169.     }
  170.  
  171.  
  172. BOOL read_options(int *argc, char ***argv)
  173.     {
  174.     int nargc;
  175.     char **nargv;
  176.     static char *wargv[3];
  177.  
  178.    memset(&Options,FALSE,sizeof(Options));    /* init options to FALSE         */
  179.  
  180.     nargv = *argv;
  181.     nargc = *argc;
  182.  
  183.     if(nargc > 1 && *nargv[1] == '-')            /* if options present            */
  184.         {
  185.         if(!set_options(nargv[1]))                    /* if only usage message        */
  186.             return FALSE;
  187.                                                             /* shift pointers down one        */
  188.         memmove(&nargv[1],&nargv[2],(nargc-2)*sizeof(char *));
  189.         nargc--;                                            /* adjust nargc                    */
  190.         nargv[nargc] = NULL;
  191.         }
  192.  
  193.     if(nargc == 1)                                        /* if only the programname        */
  194.         {
  195.         wargv[0] = *argv[0];                            /* set up new argv array        */
  196.         wargv[1] = wild_arg;
  197.         wargv[2] = NULL;
  198.         nargv = wargv;                                    /* set nargv and narc            */
  199.         nargc = 2;
  200.         }
  201.     *argc = nargc;                                        /* now set the originals        */
  202.     *argv = nargv;
  203.     }
  204.  
  205. int set_options(char *opt)
  206.     {
  207.     for( ; *opt ; opt++)
  208.         switch(tolower(*opt))
  209.             {
  210.             case 'f':
  211.                 Options.file_format = TRUE;
  212.                 break;
  213.             case 'l':
  214.                 Options.long_format = TRUE;
  215.                 break;
  216.             case 't':
  217.                 Options.time_sort = TRUE;
  218.                 break;
  219.             case 'r':
  220.                 Options.reverse_order = TRUE;
  221.                 break;
  222.             case 's':
  223.                 Options.long_format = FALSE;
  224.                 Options.single_column = TRUE;
  225.                 break;
  226.             case 'c':
  227.                 Options.column_format = TRUE;
  228.                 break;
  229.             case 'd':
  230.                 Options.dir_format = TRUE;
  231.                 break;
  232.             case 'p':
  233.                 Options.paging = TRUE;
  234.                 break;
  235.             case 'e':
  236.                 Options.ext_sort = TRUE;
  237.                 break;
  238.             case 'n':
  239.                 Options.no_sort = TRUE;
  240.                 break;
  241.             case 'a':
  242.                 Options.attrval = get_attrval(++opt);
  243.                 Options.dir_format = Options.file_format = FALSE;
  244.                 return TRUE;
  245.                 break;
  246.             case '?':
  247.                 usage();
  248.                 return FALSE;
  249.                 break;
  250.             }
  251.     return TRUE;
  252.     }
  253.  
  254. void usage(void)
  255.     {
  256.     printf("Usage: ls [-flscpternda<rhsad>?] [<list of files>]\n");
  257.     printf("<list of files> := <file> | <file> <list of files>\n");
  258.     printf("     -f: files (non-directories) only\n");
  259.     printf("     -l: long listing (default)\n");
  260.     printf("     -s: single column listing\n");
  261.     printf("     -c: columnar format\n");
  262.     printf("     -p: pause at the end of every screen page\n");
  263.     printf("     -t: time sort\n");
  264.     printf("     -e: extension sort\n");
  265.     printf("     -r: reverse sort order\n");
  266.     printf("     -n: no sort listing\n");
  267.     printf("     -d: directory entries only\n");
  268.     printf("     -a: attributes: only files with <attr>\n");
  269.     printf("     -?: this message\n");
  270.     printf("     [by R.H.Shaw 07/29/89]\n");
  271.     }
  272.  
  273. void get_freespace(unsigned drive, long *totalspace, long *availspace)
  274.     {
  275.     int flag = FALSE;
  276.     FSALLOCATE fs;
  277.  
  278.     DosQFSInfo(drive, 1, (PBYTE)&fs, sizeof(fs));
  279.     *totalspace = (fs.cSectorUnit * fs.cUnit * fs.cbSector);
  280.     *availspace = (fs.cSectorUnit * fs.cUnitAvail * fs.cbSector);
  281.     }
  282.  
  283. int qscmp(PFILEFINDBUF *p1, PFILEFINDBUF *p2)
  284.     {
  285.     PFILEFINDBUF f1 = *p1;
  286.     PFILEFINDBUF f2 = *p2;
  287.     int cmp,val = 0,c2,c1,len,len1,len2;
  288.     char *ext1, *ext2, *name1, *name2;
  289.     register USHORT d, t;
  290.  
  291.     if(Options.time_sort)                                /* if time sort                */
  292.         {
  293.         d = MAKETYPE(f1->fdateLastWrite,USHORT);/* get date1                    */
  294.         t = MAKETYPE(f2->fdateLastWrite,USHORT);/* get date2                    */
  295.         if(d > t)                                            /* compare                        */
  296.             val = -1;
  297.         else if(d < t)
  298.             val = 1;
  299.         else                                                /* dates equal, check time    */
  300.             {
  301.             d = MAKETYPE(f1->ftimeLastWrite,USHORT);
  302.             t = MAKETYPE(f2->ftimeLastWrite,USHORT);
  303.             if(d > t)
  304.                val = -1;
  305.              else if(d < t)
  306.                val = 1;
  307.                 else
  308.                     val = 0;
  309.             }
  310.         return opposite(val);
  311.         }
  312.     else                                        /* name or extension sort   */
  313.         {
  314.         c2 = f2->attrFile & A_DIRECTORY;        /* see either is a directory*/
  315.         c1 = f1->attrFile & A_DIRECTORY;
  316.         if(cmp = (c2-c1))                       /* one is, but not the other*/
  317.             return opposite(cmp);               /* directories are lesser   */
  318.  
  319.         name1 = f1->achName;
  320.         name2 = f2->achName;
  321.         /* either both are directories or both are files to get here        */
  322.         if(Options.ext_sort)                    /* if extension sort        */
  323.             {
  324.             ext1 = strchr(name1,'.');           /* get the extension        */
  325.             ext2 = strchr(name2,'.');
  326.             if(ext1 && ext2)                    /* if both have extensions  */
  327.                 {
  328.                     /* get length of both: lesser length used in strncmp()  */
  329.                 len = ( ((len1 = strlen(ext1)) > (len2 = strlen(ext2))) ? len2 : len1);
  330.                 return opposite(strncmp(ext1, ext2, len));
  331.                 }
  332.             else                     /* at least one doesn't have extension */
  333.                 return (opposite((ext1 != NULL) ? -1 : 1));
  334.             }
  335.         else                                    /* boring old name sort     */
  336.             {
  337.                     /* get length of both: lesser length used               */
  338.             len = ( ((len1 = strlen(name1)) > (len2 = strlen(name2))) ? len2 : len1);
  339.             return opposite(strncmp(name1, name2, len));
  340.             }
  341.         }
  342.     }
  343.  
  344. void print_entries(void)
  345.     {
  346.     int reps, lines, max_lines, col_line, col, item, bal, pagelines;
  347.     char e_buf[100],short_format = FALSE;
  348.     long total_used = 0L, total_alloced = 0L;
  349.     char attrstr[9], ap;
  350.     FILEFINDBUF *p;
  351.     unsigned writehours, i;
  352.  
  353.     pagelines = max_lines = col_line = lines = reps = col = 0;
  354.  
  355.     if(Options.column_format)                  /* for column formatting */
  356.         {
  357.             /* if Options.paging and more than a pageful set for a pageful */
  358.         if(Options.paging && (entries>(Pagelen*NUMCOLS)) )
  359.             max_lines = Pagelen;
  360.         else        /* if not Options.paging, or if Options.paging and less than a pageful */
  361.             max_lines = column_lines(entries);
  362.         }
  363.     /*  printf("\nmax_lines=%d,entries/NUMCOLS=%d,entries%NUMCOLS=%d",max_lines,entries/NUMCOLS,entries%NUMCOLS); */
  364.                 /* main loop to print file info */
  365.     for(i = 0; i < entries; i++)
  366.         {
  367.         p = entryptrs[i];
  368.             /* if directory, put name in [] */
  369.         if(p->attrFile & A_DIRECTORY)
  370.             makedirname(e_buf,p->achName);
  371.         else
  372.             strcpy(e_buf,p->achName);
  373.  
  374.         if(Options.long_format)        /* vertical column, with full information */
  375.             {
  376.                 /* set attribute chars */
  377.             set_attribute_values(attrstr,p->attrFile);
  378.  
  379.             writehours = (p->ftimeLastWrite.hours > 12 ? p->ftimeLastWrite.hours - 12 : p->ftimeLastWrite.hours);
  380.             ap = (char)(p->ftimeLastWrite.hours > 12 ? 'p' : 'a');
  381.  
  382.             printf("\n"
  383.                 "%8s   "
  384.                 "%12ld   "
  385.                 /*         Create                   Last Access      */
  386. /*              "%02d-%02d-%02d %02d:%02d %02d-%02d-%02d %02d:%02d " */
  387.                 /*       Last Update          */
  388.                 "%2d-%02d-%02d  %2d:%02d%c  "
  389.  
  390.                 /* size name */
  391.                 "%s",
  392.  
  393.                 attrstr,
  394.                 p->cbFile,
  395. /*
  396.                 p->fdateCreation.month,p->fdateCreation.day,p->fdateCreation.year+80,
  397.                 p->ftimeCreation.hours,p->ftimeCreation.minutes,
  398.                 p->fdateLastAccess.month,p->fdateLastAccess.day,p->fdateLastAccess.year+80,
  399.                 p->ftimeLastAccess.hours,p->ftimeLastAccess.minutes,
  400.  */
  401.                 p->fdateLastWrite.month,p->fdateLastWrite.day,p->fdateLastWrite.year+80,
  402.                 writehours,p->ftimeLastWrite.minutes,ap,
  403.                 strlwr(e_buf));
  404.             }
  405.         else
  406.             {                      /* if !Options.long_format */
  407.             if(!Options.column_format)
  408.                 {         /* vertical format, filenames only */
  409.                 newline();
  410.                 printf("%-30.30s", strlwr(e_buf));
  411.                 }
  412.             else
  413.                 {                      /* column format */
  414.                 if(!i)                  /* initial newline */
  415.                     newline();
  416.     /* item is offset into array, col_line is actual line down screen in cols */
  417.     /* col is current screen column, max_lines is number of column lines to do */
  418.                 item = col_line + (max_lines * col);    /* item is offset */
  419.                     /*  printf("\nitem=%d,col_line=%d,col=%d ",item,col_line,col); */
  420.                 if(item < entries)
  421.                     {
  422.                     /* printf("%d    ",item); */
  423.                     if(entryptrs[item]->attrFile & A_DIRECTORY)
  424.                         makedirname(e_buf,entryptrs[item]->achName);
  425.                     else
  426.                         strcpy(e_buf,entryptrs[item]->achName);
  427.  
  428.                     printf("%-14.14s", strlwr(e_buf));
  429.                     }
  430.                 else
  431.                     i--;
  432.                 col++;
  433.                 if(col >= NUMCOLS)
  434.                     { /* if we're at last column on this line */
  435.                     newline();          /* write newline() */
  436.                     col = 0;            /* set for 1st column */
  437.                     pagelines++;
  438.                     col_line++;         /* go to next column line */
  439.                     }
  440.                 }
  441.             }
  442.             lines++;
  443.         if(Options.paging)
  444.             if(Options.column_format && pagelines == Pagelen)
  445.                 {
  446.                 pagelines = 0;
  447.                 col_line = item+1;
  448.                 bal = (entries-i);
  449.                 max_lines = column_lines( (bal > (Pagelen*NUMCOLS)) ? (Pagelen*NUMCOLS) : bal );
  450.                 /* printf("bal=%d,i=%d,max_lines=%d",bal,i,max_lines); */
  451.                 dopage(!Options.column_format);
  452.                 }
  453.             else if(lines == Pagelen && !Options.column_format)
  454.                 {
  455.                 dopage(!Options.column_format);
  456.                 lines = 0;
  457.                 }
  458.         total_alloced += p->cbFileAlloc;
  459.         total_used += p->cbFile;
  460.         }
  461.  
  462.     if(reps != 0)       /* only executed on short format (lc) */
  463.         newline();
  464.     if(!short_format)
  465.         newline();
  466.     printf("%u Files occupy %ld bytes(%ld Allocated), ", entries, total_used, total_alloced);
  467.     printf("%ld of %ld free on %c:", availspace, totalspace, dirdrive+'A'-1);
  468.     newline();
  469.     }
  470.  
  471.  
  472. void dopage(USHORT c)
  473.     {
  474.     if(c)
  475.         newline();
  476.     printf("\nPress any key to continue...");
  477.     getch();
  478.     newline();
  479.     }
  480.  
  481.     /* places from into to with [] if a directory */
  482. void makedirname(char *to,char *from)
  483.     {
  484.     strcpy(to,"[");
  485.     strcat(to,from);
  486.     strcat(to, "]");
  487.     }
  488.  
  489.  
  490. const char *attrs = "--advshr";
  491. unsigned attrvals[8] =
  492.     {
  493.     A_UNUSED1,  A_UNUSED0, A_ARCHIVE, A_DIRECTORY,
  494.     A_VOLLABEL, A_SYSTEM,  A_HIDDEN, A_READONLY
  495.     };
  496.  
  497.     /* sets the string to "-----" or "drhsa", etc. */
  498. void set_attribute_values(char *str, unsigned attribute)
  499.     {
  500.     unsigned i, attrvals = A_UNUSED1, len = strlen(attrs);
  501.  
  502.     memset(str,'-',len);      /* initialize attribute value string */
  503.     str[len] = 0;
  504.     for( i = 0; i < len; i++, attrvals >>= 1)
  505.         if(attrvals & attribute)
  506.             str[i] = attrs[i];
  507.     }
  508.  
  509. unsigned get_attrval(char *attrstr)
  510.     {
  511.     unsigned *i,newattr = 0;
  512.    const char *p;
  513.     char *q;
  514.  
  515.     for( q = attrstr; *q ; q++)
  516.         for( p = attrs, i = attrvals; *p ; p++, i++)
  517.             if(*q == *p)
  518.                 newattr |= *i;
  519.     return newattr;
  520.     }
  521.  
  522. int column_lines(int num)
  523.     {
  524.     int max_lines;
  525.  
  526.     max_lines = num/NUMCOLS;                        /* set the maximum lines         */
  527.     if(num%NUMCOLS)                                 /* increment for leftovers        */
  528.         max_lines++;
  529.  
  530.     return max_lines;
  531.     }
  532.  
  533.     /************ end of ls.c *********************/
  534.