/* Program: FILES.C Author : Kim Moser Date : 04/01/89 (1.0) 09/20/89 (1.1) Added switches to allow user to suppress displaying of drive, path, filename, or extension. System : IBM PC / Borland Turbo-C 2.0 Descrip: Copies full path name of each file in current (or specified directory) to stdout; optionally recurses subdirectories. Usage : FILES [-switches] {[drive:][path]filespec]} Switches: r skip read-only files h skip hidden files s skip system files d skip directory names a skip archive files n recurse subdirectories i do NOT display drive t do NOT display path m do NOT display name e do NOT display extension M do not print messages W do not print warnings P prevent pausing Examples of possible filespecs: *.COM (*.COM in current directory on current drive) C: (*.* in current directory on C:) C:*.* (*.* in current directory on C:) C:\ (*.* in root directory on C:) C:\DOS (DOS.* in root directory on C:) C:\DOS\*.EXE (*.EXE in DOS directory on C:) Algorithm for parsing 'path' and 'pattern' from filespec (command line): Search 'arg' backward from end for '\', ':', or until at beginning of 'arg'. This string (from where we stopped until end) is the 'pattern', and the part of 'arg' from the beginning of 'arg' to where we stopped is the 'path'. If 'pattern' is NULL, OR if 'pattern' is a directory, then 'pattern' = "*.*". If 'pattern' is not NULL, and not a directory, then if either filename or extension is empty (e.g. 'pattern' is '.DOC') then make filename or filespec (or both, if needed) '*'. */ #include #include #include #include #include #include #include /* kbhit() */ unsigned int total=0; /* How many filenames printed total */ int WARN=1, MSG=1, PAUSE=1; char pattern[14]={0}; /* Just pattern */ char path[255]={0}; /* Just path (may include drive and trailing backslash); changed by dodir() */ char filespec[255]; /* Contains path+pattern; changed by dodir() */ char temp[255]; /* Will contain full drive and path of each file; used by dodir()'s call to searchpath() */ int d_drive=1, d_path=1, d_name=1, d_ext=1; /* Whether to display drive, path, filename, and extension */ char drive[3], path[255], name[9], ext[5]; /* 'ext[]' also holds '.' */ /* Will be set to drive, path, name, and extension of file */ /* For some reason, name[] must be at least 9 chars */ unsigned int skipbits=FA_LABEL; /* Default files to SKIP: Volume labels */ char recurse=0; /* Default: do NOT recurse subdirectories */ void credits(void); void credits(void) /* Displays credits only on first call */ { static int yet=0; /* Whether credits have been displayed yet */ if (!yet++ && MSG) fputs( "FILES v1.1 (09/20/89) Copyright (C) 1989 Kim Moser All Rights Reserved\n", stderr); } void usage(void); void usage(void) { credits(); fputs("Usage: FILES [-switches] [[drive:][path]filespec]\n", stderr); fputs(" Writes (to stdout) fully qualified name of each file which matches filespec.\n", stderr); fputs(" Skips files with specified attributes; recurses subdirectories if requested.\n", stderr); fputs(" If drive, path, or filespec are omitted, they default to current drive,\n", stderr); fputs(" current path, and '*.*', respectively.\n\n", stderr); fputs(" SWITCH MEANING\n", stderr); fputs(" r skip read-only files\n", stderr); fputs(" h skip hidden files\n", stderr); fputs(" s skip system files\n", stderr); fputs(" d skip directory names\n", stderr); fputs(" a skip archive files\n", stderr); fputs(" n recurse subdirectories\n", stderr); fputs(" i do NOT display drive\n", stderr); fputs(" t do NOT display path\n", stderr); fputs(" m do NOT display name\n", stderr); fputs(" e do NOT display extension\n", stderr); fputs(" M do not print messages\n", stderr); fputs(" W do not print warnings\n", stderr); fputs(" P prevent pausing\n", stderr); exit(-1); } void checkpause(void); void checkpause(void) /* Checks to see if a key is hit; if so, prints message to stderr, waits for another keypress; if ESC, then exits, otherwise returns */ { if (!PAUSE) return; if (kbhit()) { getch(); /* Ignore it */ fputs( "Paused; hit ESC to halt, or any key to resume.\n", stderr); if (getch()==27) exit(1); } } void dodir(char *p); void dodir(p) char *p; /* 'p' is RELATIVE path -- including trailing backslash, if any. Gets appended to 'path' (note: first call to dodir() may pass an absolute path; this is okay because it will be merely appended to a blank 'path' [global]). */ { unsigned int local=0; static int level=0; struct ffblk info; int old_len=strlen(path); /* Remember previous length of path */ int path_len; char *n; int doname; /* Whether filename should be printed */ unsigned int subtotal=0; /* How many filenames printed in this directory */ unsigned int dirsfound=0; /* How many directories found */ strcat(path,p); /* Append new path */ if (level++) strcat(path,"\\"); path_len = strlen(path); /* Remember length of new path */ strcpy(filespec,path); strcat(filespec,pattern); if (MSG) fprintf( stderr, "FILESPEC=%s\n", filespec ); while ((local++==0 ? !findfirst(filespec,&info,~0) : !findnext(&info))) { checkpause(); doname=1; /* Assume */ /* If it's not (a directory named "." or "..") then print it: */ if (info.ff_attrib & FA_DIREC) { /* It's a directory... */ /* ...so print it only if user specified to print directory names, AND if it's not named "." or "..": */ doname = strcmp(info.ff_name,".")&&strcmp(info.ff_name,".."); } if (doname && !(info.ff_attrib & skipbits)) { subtotal++; strcpy(temp,path); strcat(temp,info.ff_name); if ( (n=searchpath(temp))==NULL ) { if (WARN) fputs( "Unable to get file's full pathname.\n", stderr); exit(1); } /* if (MSG) for (i=0; i 1) curdrive = (s[1]!=':'); strcpy(path, s); /* 'path' will later be truncated */ for (i=strlen(s)-1; i>=0; i--) { if ( (s[i]=='\\') || (s[i]==':') ) break; } strcpy(pattern,s+i+1); path[i+1]='\0'; if (!strlen(path)) { curpath=1; if ( getcwd(path,255)==NULL ) { if (WARN) fprintf( stderr, "Unable to read current working directory.\n" ); exit(1); } /* cwd will end in '\' only if it's the root; otherwise we must append it ourselves: */ if (path[strlen(path)-1]!='\\') strcat(path,"\\"); } if (!strlen(pattern)) strcpy(pattern,"*.*"); if (MSG) fprintf( stderr, "\nPath" ); if ( curpath || (strchr(filespec,'\\')==NULL) ) /* Current directory on whatever drive */ if (MSG) fprintf( stderr, " (current directory)" ); if ( curdrive ) /* No drive specified */ if (MSG) fprintf( stderr, " (current drive)" ); if (MSG) fprintf( stderr, ": '%s'\nPattern: '%s'\n", path, pattern ); } void switches(char *s) { int i; for (i=0; s[i]; i++) { switch (s[i]) { case 'r': /* Read-only */ skipbits |= FA_RDONLY; break; case 'h': /* Hidden */ skipbits |= FA_HIDDEN; break; case 's': /* System */ skipbits |= FA_SYSTEM; break; case 'd': /* Directories */ skipbits |= FA_DIREC; break; case 'a': /* Archives */ skipbits |= FA_ARCH; break; case 'n': /* Recurse directories */ recurse=1; break; case 'i': /* Do NOT display drive */ d_drive = 0; break; case 't': /* Do NOT display path */ d_path = 0; break; case 'm': /* Do NOT display name */ d_name = 0; break; case 'e': /* Do NOT display extension */ d_ext = 0; break; case 'M': /* Don't print messages */ MSG=0; break; case 'W': /* Don't print warnings */ WARN=0; break; case 'P': /* Prevent pausing */ PAUSE=0; break; default: usage(); break; } } } void main(argc, argv) int argc; /* 'argc' is never refered to, but must be present nonetheless, otherwise program has trouble with argv[] */ char **argv; { int i; /* Process first parameter if it's switches: */ for (i=1; i