home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / dirutl / new17.arc / NEW.C next >
Encoding:
C/C++ Source or Header  |  1989-02-17  |  16.8 KB  |  617 lines

  1. /* NEW.C (V1.7) -- Written by Scott R. Houck   17 Feb 89
  2.  *
  3.  * Directory listing of files since or before a certain number of days.
  4.  *
  5.  * Modelled after Jay Jervey's utility.  My version lists the file
  6.  * information in the standard DOS directory listing format (except that
  7.  * I am also showing the seconds in the file time), adds some features
  8.  * (/p, /s and /e), and corrects some errors in Jervey's utility.  Julian
  9.  * date calculations were adapted from James Seed's c_dates library.
  10.  *
  11.  * Compiled with MSC version 5.1.  Uses PforCe functions drfullpath() and
  12.  * vidcsrtyp().
  13.  *
  14.  * The syntax is:  NEW [filespec [filespec...]] [options]
  15.  *
  16.  * Options and filespec can be in any order.  Valid options are:
  17.  *
  18.  *      /h     Show help screen
  19.  *      /?     Same as /h
  20.  *      /n     Show files SINCE the number of days specified by n
  21.  *      /-n    Show files BEFORE the number of days specified by n
  22.  *      /p     Pause when screen display is full
  23.  *      /s     Search specified directory and its subdirectories
  24.  *      /e     Search entire disk
  25.  *      /d     Include directories in listing
  26.  *      /do    Include directories ONLY in listing
  27.  *      /j     Junk option -- include files with corrupted dates
  28.  *      /i     Ignore the environment variable NEW if it is defined
  29.  *
  30.  * If filespec is omitted, *.* is assumed.  Also, a "day" in this program
  31.  * starts at 6:00 am and ends at 5:59 am the following day.
  32.  *
  33.  * Compile with:   cl -AL new.c pfms3l.lib /link /st:40000 /e
  34.  *
  35.  * Version 1.3 handles file dates where year > 99 (corrupted filestamps).
  36.  * Version 1.4 will not display files whose date and time are greater than
  37.  *   the current date and time unless the /J (junk) option is chosen.
  38.  *   Also added /D to include directories in listing.
  39.  * Version 1.5 checks the number of text rows available so that the pause
  40.  *   option (/P) pauses at the correct place.
  41.  * Version 1.6 allows multiple filespecs and is handy for specifying
  42.  *   multiple drives to be searched with the /e option.  For example,
  43.  *   NEW c: d: /e.
  44.  * Version 1.7 checks for an environment variable named NEW to find
  45.  *   default options and/or filespecs.  If it is defined, but you want
  46.  *   NEW to ignore the environment variable, you may specify /I (for
  47.  *   Ignore) on the command line.  Request for NEW environment variable
  48.  *   came from Richard Hallowell.  Also added /DO option to include
  49.  *   directories ONLY in the listing (no regular files are included).
  50.  */
  51.  
  52. #include <stdio.h>
  53. #include <string.h>
  54. #include <stdlib.h>
  55. #include <conio.h>
  56. #include <ctype.h>
  57. #include <dos.h>
  58. #include <io.h>
  59. #include "pdefs.h"
  60.  
  61. struct packed_date {
  62.    unsigned da : 5;
  63.    unsigned mo : 4;
  64.    unsigned yr : 7;
  65. };
  66.  
  67. struct packed_time {
  68.    unsigned ss : 5;
  69.    unsigned mm : 6;
  70.    unsigned hh : 5;
  71. };
  72.  
  73. #define PACKED_DATE(d) (*(struct packed_date *)(&(d)))
  74. #define PACKED_TIME(t) (*(struct packed_time *)(&(t)))
  75.  
  76. typedef struct node   NODE, *NODEPTR;
  77.  
  78. struct node {
  79.    struct find_t   finfo;
  80.    char            path[80];
  81.    NODEPTR         next;
  82. };
  83.  
  84. /* "modes" for parse() function */
  85.  
  86. #define CMDLINE 0
  87. #define ENVIRON 1
  88.  
  89. char *syntax[] = {
  90.    "The syntax is:  NEW [filespec [filespec...]] [options]\n",
  91.    "Options and filespec can be in any order.  Valid options are:\n",
  92.    "    /h     Show this help screen",
  93.    "    /?     Same as /h",
  94.    "    /n     Show files SINCE the number of days specified by n",
  95.    "    /-n    Show files BEFORE the number of days specified by n",
  96.    "    /p     Pause when screen display is full",
  97.    "    /s     Search specified directory and its subdirectories",
  98.    "    /e     Search entire disk",
  99.    "    /d     Include directories in listing",
  100.    "    /do    Include directories ONLY in listing",
  101.    "    /j     Junk option -- include files with corrupted dates",
  102.    "    /i     Ignore the environment variable NEW if it is defined\n",
  103.    "If filespec is omitted, *.* is assumed.  Also, a \"day\" in this "
  104.       "program",
  105.    "starts at 6:00 am and ends at 5:59 am the following day.", 0
  106. };
  107.  
  108. char *cdow[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
  109.    "Friday", "Saturday" };
  110.  
  111.  
  112. /* global variables */
  113.  
  114. int before   = NO;
  115. int pausing  = NO;
  116. int entire   = NO;
  117. int subdirs  = NO;
  118. int junk     = NO;
  119. int dirs     = NO;
  120. int ignore   = NO;
  121. int dirsonly = NO;
  122. size_t hits  = 0;
  123. int lines    = 3;
  124. long since   = 1L;
  125. long jul, tjul;      /* jul = date to check for, tjul = today's date */
  126. NODEPTR filehead = NULL;
  127. NODEPTR filetail = NULL;
  128. NODEPTR spechead = NULL;
  129. NODEPTR spectail = NULL;
  130. NODEPTR *larray;
  131. char hitfile[256];
  132. char findspec[256];
  133. int numrows;         /* number of text rows */
  134.  
  135.  
  136. /* function prototypes */
  137.  
  138. void parse(char *, int, int);
  139. void print_syntax(void);
  140. long gtoj(int, int, int);
  141. void jtog(long, int *, int *, int *);
  142. int dow(long);
  143. NODEPTR addlist(struct find_t, char *, NODEPTR *, NODEPTR *);
  144. int compare();
  145. void display(void);
  146. void check_pause(void);
  147. void search(char *, char *);
  148.  
  149.  
  150. main(int argc, char **argv)
  151. {
  152.    int month, day, year, hours, i, option, len;
  153.    char *ptr, *p, *q, fullpath[128], basepath[128], filespec[13];
  154.    char environ[128], envarg[128];
  155.    struct dosdate_t date;
  156.    struct dostime_t time;
  157.    NODEPTR n;
  158.    struct find_t dummy;
  159.  
  160.    /* Determine the number of text rows by looking at 0040:0084h */
  161.    numrows = (int)(*(char far *)0x00400084);
  162.    if (numrows == 0)
  163.       numrows = 24;
  164.  
  165.    /* Could also have used INT 10h, function 1130h, which returns the
  166.     * number of rows (minus 1) in DL
  167.     */
  168.  
  169.    fprintf(stderr, "NEW V1.7 by Scott R. Houck\n");
  170.  
  171.    while (--argc)
  172.       {
  173.       option = (**++argv == '/');
  174.       ptr = strtok(*argv, "/");
  175.       parse(ptr, option, CMDLINE);
  176.       while (ptr = strtok(NULL, "/"))
  177.          parse(ptr, 1, CMDLINE);
  178.       }
  179.  
  180.    /* Check the environment for NEW options/filespecs */
  181.    if (!ignore && (p = getenv("NEW")) != NULL)
  182.       {
  183.       strcpy(environ, p);
  184.       p = environ;
  185.       while (*p)
  186.          {
  187.          /* strip off whitespace */
  188.          while (isspace(*p))
  189.             p++;
  190.          /* scan for whitespace */
  191.          for (q = p; *q && !isspace(*q); q++)
  192.             ;
  193.          if (*q)
  194.             {
  195.             strncpy(envarg, p, q-p);
  196.             *q = EOS;
  197.             p = q + 1;
  198.             }
  199.          else
  200.             {
  201.             strcpy(envarg, p);
  202.             p = q;
  203.             }
  204.          option = (*envarg == '/');
  205.          ptr = strtok(envarg, "/");
  206.          parse(ptr, option, ENVIRON);
  207.          while (ptr = strtok(NULL, "/"))
  208.             parse(ptr, 1, ENVIRON);
  209.          }
  210.       }
  211.  
  212.    if (!spechead)
  213.       addlist(dummy, "*.*", &spechead, &spectail);
  214.  
  215.    _dos_getdate(&date);
  216.    _dos_gettime(&time);
  217.    if (time.hour >= 6)
  218.       --since;
  219.    tjul = gtoj(date.month, date.day, date.year);
  220.    jul = tjul - since;
  221.    jtog(jul, &month, &day, &year);
  222.  
  223.    printf("Directory %s 6 am %s, %d-%02d-%02d\n\n",
  224.       before ? "before" : "since",
  225.       cdow[dow(jul)], month, day, year % 100);
  226.  
  227.    if (subdirs || entire)
  228.       if (!isatty(fileno(stdout)))
  229.          fprintf(stderr, "\n");
  230.  
  231.    for (n = spechead; n; n = n->next)
  232.       {
  233.       strupr(strcpy(filespec, n->path));
  234.       drfullpath(fullpath, 0, filespec);     /* PforCe */
  235.  
  236.       if (strchr(fullpath, '*') == NULL && strchr(fullpath, '?') == NULL)
  237.          {
  238.          if (fullpath[strlen(fullpath)-1] == '\\')
  239.             strcat(fullpath, "*.*");
  240.          else
  241.             strcat(fullpath, "\\*.*");
  242.          }
  243.  
  244.       p = strrchr(fullpath, '\\');
  245.       len = p - fullpath + 1;
  246.       strncpy(basepath, fullpath, len);
  247.       basepath[len] = EOS;
  248.       strcpy(filespec, p+1);
  249.  
  250.       if (entire)
  251.          {
  252.          subdirs = YES;
  253.          basepath[3] = EOS;
  254.          fullpath[2] = EOS;
  255.          strcat(fullpath, filespec);
  256.          }
  257.  
  258.       if (subdirs)
  259.          vidcsrtyp(CSR_HIDDEN);  /* PforCe */
  260.  
  261.       search(basepath, filespec);
  262.  
  263.       if (subdirs)
  264.          {
  265.          fprintf(stderr, "%-79s\r", "");
  266.          vidcsrtyp(CSR_NORMAL);  /* PforCe */
  267.          }
  268.       }
  269.  
  270.    if (filehead)
  271.       display();
  272.  
  273.    if (hits)
  274.       {
  275.       ++lines;
  276.       printf("\n");
  277.       check_pause();
  278.       }
  279.  
  280.    ++lines;
  281.  
  282.    if (dirsonly)
  283.       printf("%d director%s found\n", hits, hits == 1 ? "y" : "ies");
  284.    else if (dirs)
  285.       printf("%d file%s/director%s found\n", hits,
  286.          hits == 1 ? "" : "s", hits == 1 ? "y" : "ies");
  287.    else
  288.       printf("%d file%s found\n", hits, hits == 1 ? "" : "s");
  289.  
  290.    check_pause();
  291. }
  292.  
  293.  
  294. void parse(char *p, int option, int mode)
  295. {
  296.    char *q;
  297.    struct find_t dummy;
  298.    static int specifiedSince = NO;
  299.  
  300.    if (option)
  301.       switch (toupper(*p))
  302.          {
  303.          case 'H':
  304.          case '?':
  305.             if (mode == CMDLINE)
  306.                {
  307.                print_syntax();
  308.                exit(0);
  309.                }
  310.             else
  311.                {
  312.                fprintf(stderr,
  313.                   "/H or /? option in environment variable NEW "
  314.                   "is invalid\n");
  315.                exit(1);
  316.                }
  317.             break;
  318.  
  319.          case 'P':
  320.             pausing = YES;
  321.             break;
  322.  
  323.          case 'E':
  324.             entire = YES;
  325.             break;
  326.  
  327.          case 'S':
  328.             subdirs = YES;
  329.             break;
  330.  
  331.          case 'D':
  332.             if (toupper(*(p+1)) == 'O')
  333.                dirsonly = YES;
  334.             else
  335.                dirs = YES;
  336.             if (dirs && dirsonly)
  337.                {
  338.                fprintf(stderr,
  339.                   "/D and /DO options are mutually exclusive\n");
  340.                exit(1);
  341.                }
  342.             break;
  343.  
  344.          case 'J':
  345.             junk = YES;
  346.             break;
  347.  
  348.          case 'I':
  349.             if (mode == CMDLINE)
  350.                ignore = YES;
  351.             else
  352.                {
  353.                fprintf(stderr,
  354.                   "/I option in environment variable NEW is invalid\n");
  355.                exit(1);
  356.                }
  357.             break;
  358.  
  359.          case '-':
  360.             if (!before)
  361.                {
  362.                before  = YES;
  363.                parse(p+1, 1, mode);
  364.                }
  365.             else
  366.                {
  367.                fprintf(stderr, "\"-\" can only be specified once\n");
  368.                exit(1);
  369.                }
  370.             break;
  371.  
  372.          default:
  373.             if (!specifiedSince)
  374.                {
  375.                for (q = p; *q; q++)
  376.                   if (!isdigit(*q))
  377.                      {
  378.                      fprintf(stderr, "Invalid option \"/%s\"\n\n", p);
  379.                      print_syntax();
  380.                      exit(1);
  381.                      }
  382.                since = atol(p);
  383.                specifiedSince = YES;
  384.                }
  385.             else
  386.                {
  387.                fprintf(stderr,
  388.                   "The number of days cannot be specified more than once\n");
  389.                exit(1);
  390.                }
  391.             break;
  392.          }
  393.    else
  394.       addlist(dummy, p, &spechead, &spectail);
  395. }
  396.  
  397.  
  398. void print_syntax()
  399. {
  400.    char **p;
  401.  
  402.    for (p = syntax; *p; p++)
  403.       fprintf(stderr, "%s\n", *p);
  404. }
  405.  
  406.  
  407. /* Gregorian date to Julian date conversion
  408.  *
  409.  * Valid input ranges:
  410.  *   month = 1 to 12
  411.  *   day   = 1 to 31
  412.  *   year  = 0 to 9999
  413.  *
  414.  * Note:  Julian date 1 = 1st day A.D.
  415.  */
  416.  
  417. long gtoj(int m, int d, int y)
  418. {
  419.    y += (m += 9)/12 + 399;
  420.    m %= 12;
  421.    return (long)y*365 + y/4 - y/100 + y/400 + (153*m+2)/5 + d - 146037;
  422. }
  423.  
  424.  
  425. /* Julian date to Gregorian date conversion */
  426.  
  427. void jtog(long jul, int *m, int *d, int *y)
  428. {
  429.    *y = (jul += 146037) * 400 / 146097;
  430.    jul -= (long) *y*365 + *y/4 - *y/100 + *y/400;
  431.    if (!jul) jul = 365 + !(*y % 4), --*y;
  432.    *y += (*m = (*d = (int)jul * 5 - 3) / 153 + 2) / 12 - 400;
  433.    *m = *m % 12 + 1;
  434.    *d = *d % 153 / 5 + 1;
  435. }
  436.  
  437.  
  438. /* Day-of-week calculation for Julian date input
  439.  *
  440.  * Returns 0-6 corresponding to Sunday through Saturday
  441.  */
  442.  
  443. int dow(long jul)
  444. {
  445.    return (int) ((jul + 5) % 7);
  446. }
  447.  
  448.  
  449. NODEPTR addlist(struct find_t info, char *path, NODEPTR *head, NODEPTR *tail)
  450. {
  451.    NODEPTR newnode;
  452.    char *p;
  453.  
  454.    newnode = (NODEPTR) malloc(sizeof(NODE));
  455.    if (newnode)
  456.       {
  457.       newnode->finfo = info;
  458.       newnode->next = NULL;
  459.       strcpy(newnode->path, path);
  460.       if (*head == NULL)
  461.          *head = *tail = newnode;
  462.       else
  463.          *tail = (*tail)->next = newnode;
  464.       }
  465.    return newnode;
  466. }
  467.  
  468.  
  469. int compare(NODEPTR *arg1, NODEPTR *arg2)    /* used by qsort */
  470. {
  471.    unsigned date1, date2, time1, time2;
  472.  
  473.    date1 = (*arg1)->finfo.wr_date;
  474.    date2 = (*arg2)->finfo.wr_date;
  475.  
  476.    if (date1 > date2)
  477.       return -1;           /* for descending sort */
  478.    else if (date1 < date2)
  479.       return 1;
  480.  
  481.    /* same date, so check the time */
  482.  
  483.    time1 = (*arg1)->finfo.wr_time;
  484.    time2 = (*arg2)->finfo.wr_time;
  485.  
  486.    if (time1 > time2)
  487.       return -1;
  488.    else if (time1 < time2)
  489.       return 1;
  490.  
  491.    /* if same date and time, sort by filename (ascending) */
  492.  
  493.    return strcmp((*arg1)->finfo.name, (*arg2)->finfo.name);
  494. }
  495.  
  496.  
  497. void display()
  498. {
  499.    NODEPTR lp;
  500.    struct find_t *p;
  501.    int i, month, day, year, hours, mins, secs, pos;
  502.    char ampm, dispname[128], *format;
  503.    char *format1  = "%2d-%02d-%02d  %2d:%02d:%02d %cm %8ld  %s\n";
  504.    char *format1d = "%2d-%02d-%02d  %2d:%02d:%02d %cm <Dir>     %s\n";
  505.    char *format2  = "%2d-%02d-%03d %2d:%02d:%02d %cm %8ld  %s\n";
  506.    char *format2d = "%2d-%02d-%03d %2d:%02d:%02d %cm <Dir>     %s\n";
  507.  
  508.    /* create an array of pointers to the nodes in the linked list,
  509.     * sort the array using qsort, and display the directory listing
  510.     */
  511.    larray = calloc(hits, sizeof(NODEPTR));
  512.    for (i = 0, lp = filehead; i < hits; i++, lp = lp->next)
  513.       larray[i] = lp;
  514.    qsort(larray, hits, sizeof(NODEPTR), compare);
  515.  
  516.    for (i = 0; i < hits; i++) /* go through the pointers in larray */
  517.       {
  518.       ++lines;
  519.       p = &larray[i]->finfo;
  520.       month  = PACKED_DATE(p->wr_date).mo;
  521.       day    = PACKED_DATE(p->wr_date).da;
  522.       year   = PACKED_DATE(p->wr_date).yr + 80;
  523.       hours  = PACKED_TIME(p->wr_time).hh;
  524.       mins   = PACKED_TIME(p->wr_time).mm;
  525.       secs   = PACKED_TIME(p->wr_time).ss * 2;
  526.       ampm   = hours < 12 ? 'a' : 'p';
  527.       hours  = (hours + 11) % 12 + 1;
  528.       if (year < 100)
  529.          format = p->attrib & _A_SUBDIR ? format1d : format1;
  530.       else
  531.          format = p->attrib & _A_SUBDIR ? format2d : format2;
  532.  
  533.       sprintf(dispname, "%s%s", strlwr(larray[i]->path), p->name);
  534.       if (strlen(dispname) > 47)
  535.          {
  536.          pos = strchr(&dispname[3], '\\') - dispname + 1;
  537.          strncpy(&dispname[pos], "...", 3);
  538.          pos += 3;
  539.          memmove(&dispname[pos], strchr(dispname, EOS)-(47-pos), 48-pos);
  540.          }
  541.       if (p->attrib & _A_SUBDIR)
  542.          printf(format, month, day, year, hours, mins, secs, ampm,
  543.             strlwr(dispname));
  544.       else
  545.          printf(format, month, day, year, hours, mins, secs, ampm,
  546.             p->size, dispname);
  547.  
  548.       check_pause();
  549.       }
  550. }
  551.  
  552.  
  553. void check_pause()
  554. {
  555.    int i;
  556.  
  557.    if (pausing && lines % numrows == 0)
  558.       {
  559.       printf("Strike any key to continue...");
  560.       getch();
  561.       for (i = 0; i < 29; i++)
  562.          printf("\b \b");
  563.       }
  564. }
  565.  
  566.  
  567. void search(char *basepath, char *filespec)
  568. {
  569.    struct find_t file;
  570.    char nextpath[128];
  571.    int done, month, day, year, hours, isadir;
  572.    long fjul;
  573.  
  574.    /* search the current basepath for the given filespec */
  575.    strcat(strcpy(findspec, basepath), filespec);
  576.    done = _dos_findfirst(findspec, _A_SUBDIR, &file);
  577.    while (!done)
  578.       {
  579.       hours  = PACKED_TIME(file.wr_time).hh;
  580.       month  = PACKED_DATE(file.wr_date).mo;
  581.       day    = PACKED_DATE(file.wr_date).da;
  582.       year   = PACKED_DATE(file.wr_date).yr + 1980;
  583.       fjul   = gtoj(month, day, year);
  584.       isadir = file.attrib & _A_SUBDIR;
  585.       if ((!before && (fjul > jul || (fjul == jul && hours > 5))) ||
  586.           ( before && (fjul < jul || (fjul == jul && hours < 6))))
  587.          {
  588.          if ( (junk || fjul <= tjul) &&
  589.               (file.name[0] != '.')  &&
  590.               (dirs || (dirsonly && isadir) ||
  591.                  (!dirs && !dirsonly && !isadir)) )
  592.             {
  593.             ++hits;
  594.             addlist(file, basepath, &filehead, &filetail);
  595.             }
  596.          }
  597.       done = _dos_findnext(&file);
  598.       }
  599.  
  600.    if (subdirs)
  601.       {
  602.       fprintf(stderr, "%-79s\r", basepath);
  603.       /* search for more directories */
  604.       strcat(strcpy(findspec, basepath), "*.*");
  605.       done = _dos_findfirst(findspec, _A_SUBDIR, &file);
  606.       while (!done)
  607.          {
  608.          if ((file.attrib & _A_SUBDIR) && file.name[0] != '.')
  609.             {
  610.             sprintf(nextpath, "%s%s\\", basepath, file.name);
  611.             search(nextpath, filespec);
  612.             }
  613.          done = _dos_findnext(&file);
  614.          }
  615.       }
  616. }
  617.