home *** CD-ROM | disk | FTP | other *** search
- /* NEW.C (V1.7) -- Written by Scott R. Houck 17 Feb 89
- *
- * Directory listing of files since or before a certain number of days.
- *
- * Modelled after Jay Jervey's utility. My version lists the file
- * information in the standard DOS directory listing format (except that
- * I am also showing the seconds in the file time), adds some features
- * (/p, /s and /e), and corrects some errors in Jervey's utility. Julian
- * date calculations were adapted from James Seed's c_dates library.
- *
- * Compiled with MSC version 5.1. Uses PforCe functions drfullpath() and
- * vidcsrtyp().
- *
- * The syntax is: NEW [filespec [filespec...]] [options]
- *
- * Options and filespec can be in any order. Valid options are:
- *
- * /h Show help screen
- * /? Same as /h
- * /n Show files SINCE the number of days specified by n
- * /-n Show files BEFORE the number of days specified by n
- * /p Pause when screen display is full
- * /s Search specified directory and its subdirectories
- * /e Search entire disk
- * /d Include directories in listing
- * /do Include directories ONLY in listing
- * /j Junk option -- include files with corrupted dates
- * /i Ignore the environment variable NEW if it is defined
- *
- * If filespec is omitted, *.* is assumed. Also, a "day" in this program
- * starts at 6:00 am and ends at 5:59 am the following day.
- *
- * Compile with: cl -AL new.c pfms3l.lib /link /st:40000 /e
- *
- * Version 1.3 handles file dates where year > 99 (corrupted filestamps).
- * Version 1.4 will not display files whose date and time are greater than
- * the current date and time unless the /J (junk) option is chosen.
- * Also added /D to include directories in listing.
- * Version 1.5 checks the number of text rows available so that the pause
- * option (/P) pauses at the correct place.
- * Version 1.6 allows multiple filespecs and is handy for specifying
- * multiple drives to be searched with the /e option. For example,
- * NEW c: d: /e.
- * Version 1.7 checks for an environment variable named NEW to find
- * default options and/or filespecs. If it is defined, but you want
- * NEW to ignore the environment variable, you may specify /I (for
- * Ignore) on the command line. Request for NEW environment variable
- * came from Richard Hallowell. Also added /DO option to include
- * directories ONLY in the listing (no regular files are included).
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <ctype.h>
- #include <dos.h>
- #include <io.h>
- #include "pdefs.h"
-
- struct packed_date {
- unsigned da : 5;
- unsigned mo : 4;
- unsigned yr : 7;
- };
-
- struct packed_time {
- unsigned ss : 5;
- unsigned mm : 6;
- unsigned hh : 5;
- };
-
- #define PACKED_DATE(d) (*(struct packed_date *)(&(d)))
- #define PACKED_TIME(t) (*(struct packed_time *)(&(t)))
-
- typedef struct node NODE, *NODEPTR;
-
- struct node {
- struct find_t finfo;
- char path[80];
- NODEPTR next;
- };
-
- /* "modes" for parse() function */
-
- #define CMDLINE 0
- #define ENVIRON 1
-
- char *syntax[] = {
- "The syntax is: NEW [filespec [filespec...]] [options]\n",
- "Options and filespec can be in any order. Valid options are:\n",
- " /h Show this help screen",
- " /? Same as /h",
- " /n Show files SINCE the number of days specified by n",
- " /-n Show files BEFORE the number of days specified by n",
- " /p Pause when screen display is full",
- " /s Search specified directory and its subdirectories",
- " /e Search entire disk",
- " /d Include directories in listing",
- " /do Include directories ONLY in listing",
- " /j Junk option -- include files with corrupted dates",
- " /i Ignore the environment variable NEW if it is defined\n",
- "If filespec is omitted, *.* is assumed. Also, a \"day\" in this "
- "program",
- "starts at 6:00 am and ends at 5:59 am the following day.", 0
- };
-
- char *cdow[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
- "Friday", "Saturday" };
-
-
- /* global variables */
-
- int before = NO;
- int pausing = NO;
- int entire = NO;
- int subdirs = NO;
- int junk = NO;
- int dirs = NO;
- int ignore = NO;
- int dirsonly = NO;
- size_t hits = 0;
- int lines = 3;
- long since = 1L;
- long jul, tjul; /* jul = date to check for, tjul = today's date */
- NODEPTR filehead = NULL;
- NODEPTR filetail = NULL;
- NODEPTR spechead = NULL;
- NODEPTR spectail = NULL;
- NODEPTR *larray;
- char hitfile[256];
- char findspec[256];
- int numrows; /* number of text rows */
-
-
- /* function prototypes */
-
- void parse(char *, int, int);
- void print_syntax(void);
- long gtoj(int, int, int);
- void jtog(long, int *, int *, int *);
- int dow(long);
- NODEPTR addlist(struct find_t, char *, NODEPTR *, NODEPTR *);
- int compare();
- void display(void);
- void check_pause(void);
- void search(char *, char *);
-
-
- main(int argc, char **argv)
- {
- int month, day, year, hours, i, option, len;
- char *ptr, *p, *q, fullpath[128], basepath[128], filespec[13];
- char environ[128], envarg[128];
- struct dosdate_t date;
- struct dostime_t time;
- NODEPTR n;
- struct find_t dummy;
-
- /* Determine the number of text rows by looking at 0040:0084h */
- numrows = (int)(*(char far *)0x00400084);
- if (numrows == 0)
- numrows = 24;
-
- /* Could also have used INT 10h, function 1130h, which returns the
- * number of rows (minus 1) in DL
- */
-
- fprintf(stderr, "NEW V1.7 by Scott R. Houck\n");
-
- while (--argc)
- {
- option = (**++argv == '/');
- ptr = strtok(*argv, "/");
- parse(ptr, option, CMDLINE);
- while (ptr = strtok(NULL, "/"))
- parse(ptr, 1, CMDLINE);
- }
-
- /* Check the environment for NEW options/filespecs */
- if (!ignore && (p = getenv("NEW")) != NULL)
- {
- strcpy(environ, p);
- p = environ;
- while (*p)
- {
- /* strip off whitespace */
- while (isspace(*p))
- p++;
- /* scan for whitespace */
- for (q = p; *q && !isspace(*q); q++)
- ;
- if (*q)
- {
- strncpy(envarg, p, q-p);
- *q = EOS;
- p = q + 1;
- }
- else
- {
- strcpy(envarg, p);
- p = q;
- }
- option = (*envarg == '/');
- ptr = strtok(envarg, "/");
- parse(ptr, option, ENVIRON);
- while (ptr = strtok(NULL, "/"))
- parse(ptr, 1, ENVIRON);
- }
- }
-
- if (!spechead)
- addlist(dummy, "*.*", &spechead, &spectail);
-
- _dos_getdate(&date);
- _dos_gettime(&time);
- if (time.hour >= 6)
- --since;
- tjul = gtoj(date.month, date.day, date.year);
- jul = tjul - since;
- jtog(jul, &month, &day, &year);
-
- printf("Directory %s 6 am %s, %d-%02d-%02d\n\n",
- before ? "before" : "since",
- cdow[dow(jul)], month, day, year % 100);
-
- if (subdirs || entire)
- if (!isatty(fileno(stdout)))
- fprintf(stderr, "\n");
-
- for (n = spechead; n; n = n->next)
- {
- strupr(strcpy(filespec, n->path));
- drfullpath(fullpath, 0, filespec); /* PforCe */
-
- if (strchr(fullpath, '*') == NULL && strchr(fullpath, '?') == NULL)
- {
- if (fullpath[strlen(fullpath)-1] == '\\')
- strcat(fullpath, "*.*");
- else
- strcat(fullpath, "\\*.*");
- }
-
- p = strrchr(fullpath, '\\');
- len = p - fullpath + 1;
- strncpy(basepath, fullpath, len);
- basepath[len] = EOS;
- strcpy(filespec, p+1);
-
- if (entire)
- {
- subdirs = YES;
- basepath[3] = EOS;
- fullpath[2] = EOS;
- strcat(fullpath, filespec);
- }
-
- if (subdirs)
- vidcsrtyp(CSR_HIDDEN); /* PforCe */
-
- search(basepath, filespec);
-
- if (subdirs)
- {
- fprintf(stderr, "%-79s\r", "");
- vidcsrtyp(CSR_NORMAL); /* PforCe */
- }
- }
-
- if (filehead)
- display();
-
- if (hits)
- {
- ++lines;
- printf("\n");
- check_pause();
- }
-
- ++lines;
-
- if (dirsonly)
- printf("%d director%s found\n", hits, hits == 1 ? "y" : "ies");
- else if (dirs)
- printf("%d file%s/director%s found\n", hits,
- hits == 1 ? "" : "s", hits == 1 ? "y" : "ies");
- else
- printf("%d file%s found\n", hits, hits == 1 ? "" : "s");
-
- check_pause();
- }
-
-
- void parse(char *p, int option, int mode)
- {
- char *q;
- struct find_t dummy;
- static int specifiedSince = NO;
-
- if (option)
- switch (toupper(*p))
- {
- case 'H':
- case '?':
- if (mode == CMDLINE)
- {
- print_syntax();
- exit(0);
- }
- else
- {
- fprintf(stderr,
- "/H or /? option in environment variable NEW "
- "is invalid\n");
- exit(1);
- }
- break;
-
- case 'P':
- pausing = YES;
- break;
-
- case 'E':
- entire = YES;
- break;
-
- case 'S':
- subdirs = YES;
- break;
-
- case 'D':
- if (toupper(*(p+1)) == 'O')
- dirsonly = YES;
- else
- dirs = YES;
- if (dirs && dirsonly)
- {
- fprintf(stderr,
- "/D and /DO options are mutually exclusive\n");
- exit(1);
- }
- break;
-
- case 'J':
- junk = YES;
- break;
-
- case 'I':
- if (mode == CMDLINE)
- ignore = YES;
- else
- {
- fprintf(stderr,
- "/I option in environment variable NEW is invalid\n");
- exit(1);
- }
- break;
-
- case '-':
- if (!before)
- {
- before = YES;
- parse(p+1, 1, mode);
- }
- else
- {
- fprintf(stderr, "\"-\" can only be specified once\n");
- exit(1);
- }
- break;
-
- default:
- if (!specifiedSince)
- {
- for (q = p; *q; q++)
- if (!isdigit(*q))
- {
- fprintf(stderr, "Invalid option \"/%s\"\n\n", p);
- print_syntax();
- exit(1);
- }
- since = atol(p);
- specifiedSince = YES;
- }
- else
- {
- fprintf(stderr,
- "The number of days cannot be specified more than once\n");
- exit(1);
- }
- break;
- }
- else
- addlist(dummy, p, &spechead, &spectail);
- }
-
-
- void print_syntax()
- {
- char **p;
-
- for (p = syntax; *p; p++)
- fprintf(stderr, "%s\n", *p);
- }
-
-
- /* Gregorian date to Julian date conversion
- *
- * Valid input ranges:
- * month = 1 to 12
- * day = 1 to 31
- * year = 0 to 9999
- *
- * Note: Julian date 1 = 1st day A.D.
- */
-
- long gtoj(int m, int d, int y)
- {
- y += (m += 9)/12 + 399;
- m %= 12;
- return (long)y*365 + y/4 - y/100 + y/400 + (153*m+2)/5 + d - 146037;
- }
-
-
- /* Julian date to Gregorian date conversion */
-
- void jtog(long jul, int *m, int *d, int *y)
- {
- *y = (jul += 146037) * 400 / 146097;
- jul -= (long) *y*365 + *y/4 - *y/100 + *y/400;
- if (!jul) jul = 365 + !(*y % 4), --*y;
- *y += (*m = (*d = (int)jul * 5 - 3) / 153 + 2) / 12 - 400;
- *m = *m % 12 + 1;
- *d = *d % 153 / 5 + 1;
- }
-
-
- /* Day-of-week calculation for Julian date input
- *
- * Returns 0-6 corresponding to Sunday through Saturday
- */
-
- int dow(long jul)
- {
- return (int) ((jul + 5) % 7);
- }
-
-
- NODEPTR addlist(struct find_t info, char *path, NODEPTR *head, NODEPTR *tail)
- {
- NODEPTR newnode;
- char *p;
-
- newnode = (NODEPTR) malloc(sizeof(NODE));
- if (newnode)
- {
- newnode->finfo = info;
- newnode->next = NULL;
- strcpy(newnode->path, path);
- if (*head == NULL)
- *head = *tail = newnode;
- else
- *tail = (*tail)->next = newnode;
- }
- return newnode;
- }
-
-
- int compare(NODEPTR *arg1, NODEPTR *arg2) /* used by qsort */
- {
- unsigned date1, date2, time1, time2;
-
- date1 = (*arg1)->finfo.wr_date;
- date2 = (*arg2)->finfo.wr_date;
-
- if (date1 > date2)
- return -1; /* for descending sort */
- else if (date1 < date2)
- return 1;
-
- /* same date, so check the time */
-
- time1 = (*arg1)->finfo.wr_time;
- time2 = (*arg2)->finfo.wr_time;
-
- if (time1 > time2)
- return -1;
- else if (time1 < time2)
- return 1;
-
- /* if same date and time, sort by filename (ascending) */
-
- return strcmp((*arg1)->finfo.name, (*arg2)->finfo.name);
- }
-
-
- void display()
- {
- NODEPTR lp;
- struct find_t *p;
- int i, month, day, year, hours, mins, secs, pos;
- char ampm, dispname[128], *format;
- char *format1 = "%2d-%02d-%02d %2d:%02d:%02d %cm %8ld %s\n";
- char *format1d = "%2d-%02d-%02d %2d:%02d:%02d %cm <Dir> %s\n";
- char *format2 = "%2d-%02d-%03d %2d:%02d:%02d %cm %8ld %s\n";
- char *format2d = "%2d-%02d-%03d %2d:%02d:%02d %cm <Dir> %s\n";
-
- /* create an array of pointers to the nodes in the linked list,
- * sort the array using qsort, and display the directory listing
- */
- larray = calloc(hits, sizeof(NODEPTR));
- for (i = 0, lp = filehead; i < hits; i++, lp = lp->next)
- larray[i] = lp;
- qsort(larray, hits, sizeof(NODEPTR), compare);
-
- for (i = 0; i < hits; i++) /* go through the pointers in larray */
- {
- ++lines;
- p = &larray[i]->finfo;
- month = PACKED_DATE(p->wr_date).mo;
- day = PACKED_DATE(p->wr_date).da;
- year = PACKED_DATE(p->wr_date).yr + 80;
- hours = PACKED_TIME(p->wr_time).hh;
- mins = PACKED_TIME(p->wr_time).mm;
- secs = PACKED_TIME(p->wr_time).ss * 2;
- ampm = hours < 12 ? 'a' : 'p';
- hours = (hours + 11) % 12 + 1;
- if (year < 100)
- format = p->attrib & _A_SUBDIR ? format1d : format1;
- else
- format = p->attrib & _A_SUBDIR ? format2d : format2;
-
- sprintf(dispname, "%s%s", strlwr(larray[i]->path), p->name);
- if (strlen(dispname) > 47)
- {
- pos = strchr(&dispname[3], '\\') - dispname + 1;
- strncpy(&dispname[pos], "...", 3);
- pos += 3;
- memmove(&dispname[pos], strchr(dispname, EOS)-(47-pos), 48-pos);
- }
- if (p->attrib & _A_SUBDIR)
- printf(format, month, day, year, hours, mins, secs, ampm,
- strlwr(dispname));
- else
- printf(format, month, day, year, hours, mins, secs, ampm,
- p->size, dispname);
-
- check_pause();
- }
- }
-
-
- void check_pause()
- {
- int i;
-
- if (pausing && lines % numrows == 0)
- {
- printf("Strike any key to continue...");
- getch();
- for (i = 0; i < 29; i++)
- printf("\b \b");
- }
- }
-
-
- void search(char *basepath, char *filespec)
- {
- struct find_t file;
- char nextpath[128];
- int done, month, day, year, hours, isadir;
- long fjul;
-
- /* search the current basepath for the given filespec */
- strcat(strcpy(findspec, basepath), filespec);
- done = _dos_findfirst(findspec, _A_SUBDIR, &file);
- while (!done)
- {
- hours = PACKED_TIME(file.wr_time).hh;
- month = PACKED_DATE(file.wr_date).mo;
- day = PACKED_DATE(file.wr_date).da;
- year = PACKED_DATE(file.wr_date).yr + 1980;
- fjul = gtoj(month, day, year);
- isadir = file.attrib & _A_SUBDIR;
- if ((!before && (fjul > jul || (fjul == jul && hours > 5))) ||
- ( before && (fjul < jul || (fjul == jul && hours < 6))))
- {
- if ( (junk || fjul <= tjul) &&
- (file.name[0] != '.') &&
- (dirs || (dirsonly && isadir) ||
- (!dirs && !dirsonly && !isadir)) )
- {
- ++hits;
- addlist(file, basepath, &filehead, &filetail);
- }
- }
- done = _dos_findnext(&file);
- }
-
- if (subdirs)
- {
- fprintf(stderr, "%-79s\r", basepath);
- /* search for more directories */
- strcat(strcpy(findspec, basepath), "*.*");
- done = _dos_findfirst(findspec, _A_SUBDIR, &file);
- while (!done)
- {
- if ((file.attrib & _A_SUBDIR) && file.name[0] != '.')
- {
- sprintf(nextpath, "%s%s\\", basepath, file.name);
- search(nextpath, filespec);
- }
- done = _dos_findnext(&file);
- }
- }
- }
-