#ifndef LINT static char sccsid[]="@(#) nextfile.c 2.2 87/12/26 12:23:43"; #endif /* LINT */ #include "options.h" /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved */ /* Functions to collect filenames from command line etc. Nextfile() is used by both Atoz and Zoo. Wildcard expansion by nextfile() is specific to MS-DOS and this implementation is specific to Microsoft C. If the symbol PORTABLE is defined, nextfile() becomes effectively a no-op that will return the original filespec the first time and NULL subsequently. */ #define FMAX 3 /* Number of different filename patterns */ #ifndef OK_STDIO #include #define OK_STDIO #endif #include "various.h" #include "zoo.h" /* solely to define PATHSIZE */ #ifdef PORTABLE #ifndef SPECNEXT /* If portable version, nextfile() is effectively a no-op and any wildcard expansion must be done by the runtime system before the command line is received by this program */ char *nextfile (what, filespec, fileset) int what; /* whether to initialize or match */ register char *filespec; /* filespec to match if initializing */ register int fileset; /* which set of files */ { static int first_time [FMAX+1]; static char saved_fspec [FMAX+1][PATHSIZE]; /* our own copy of filespec */ if (what == 0) { strcpy (saved_fspec[fileset], filespec); /* save the filespec */ first_time[fileset] = 1; return NULL; } if (first_time[fileset]) { first_time[fileset] = 0; return saved_fspec[fileset]; } else { return NULL; } } #endif /* SPECNEXT */ #else /* if not PORTABLE then */ #include #include #include "assert.h" /* macro definition: assert() macro */ void fcbpath PARMS((struct ffblk *, char *, char *)); /*******************/ /* nextfile() returns the name of the next source file matching a filespec. INPUT what: A flag specifying what to do. If "what" is 0, nextfile() initializes itself. If "what" is 1, nextfile() returns the next matching filename. filespec: The filespec, usually containing wildcard characters, that specifies which files are needed. If "what" is 0, filespec must be the filespec for which matching filenames are needed. If "what" is 1, nextfile() does not use "filespec" and "filespec" should be NULL to avoid an assertion error during debugging. fileset: nextfile() can keep track of more than one set of filespecs. The fileset specifies which filespec is being matched and therefore which set of files is being considered. "fileset" can be in the range 0:FMAX. Initialization of one fileset does not affect the other filesets. OUTPUT IF what == 0 THEN return value is NULL ELSE IF what == 1 THEN IF a matching filename is found THEN return value is pointer to matching filename including supplied path ELSE IF at least one file matched previously but no more match THEN return value is NULL ELSE IF supplied filespec never matched any filename THEN IF this is the first call with what == 1 THEN return value is pointer to original filespec ELSE return value is NULL END IF END IF END IF END IF NOTE Initialization done when "what"=0 is not dependent on the correctness of the supplied filespec but simply initializes internal variables and makes a local copy of the supplied filespec. If the supplied filespec was illegal, the only effect is that the first time that nextfile() is called with "what"=1, it will return the original filespec instead of a matching filename. That the filespec was illegal will become obvious when the caller attempts to open the returned filename for input/output and the open attempt fails. USAGE HINTS nextfile() can be used in the following manner: char *filespec; -- will point to filespec char *this_file; -- will point to matching filename filespec = parse_command_line(); -- may contain wildcards FILE *stream; nextfile (0, filespec, 0); -- initialize fileset 0 while ((this_file = nextfile(1, (char *) NULL, 0)) != NULL) { stream = fopen (this_file, "whatever"); if (stream == NULL) printf ("could not open %s\n", this_file); else perform_operations (stream); } */ char *nextfile (what, filespec, fileset) int what; /* whether to initialize or match */ register char *filespec; /* filespec to match if initializing */ register int fileset; /* which set of files */ { static struct ffblk ffblk[FMAX+1]; static int first_time [FMAX+1]; static char pathholder [FMAX+1][PATHSIZE]; /* holds a pathname to return */ static char saved_fspec [FMAX+1][PATHSIZE];/* our own copy of filespec */ int ffretval; /* return value from findfirst() or findnext() */ assert(fileset >= 0 && fileset <= FMAX); if (what == 0) { assert(filespec != NULL); strcpy (saved_fspec[fileset], filespec); /* save the filespec */ first_time[fileset] = 1; return (NULL); } assert(what == 1); assert(filespec == NULL); assert(first_time[fileset] == 0 || first_time[fileset] == 1); if (first_time[fileset]) /* first time -- initialize etc. */ ffretval = findfirst(saved_fspec[fileset], &ffblk[fileset], 0); else ffretval = findnext(&ffblk[fileset]); if (ffretval != 0) { /* if error status */ if (first_time[fileset]) { /* if file never matched then */ first_time[fileset] = 0; return (saved_fspec[fileset]);/* return original filespec */ } else { /* else */ first_time[fileset] = 0; /* */ return (NULL); /* return (NULL) for no more */ } } else { /* a file matched */ first_time[fileset] = 0; /* add path info */ fcbpath (&ffblk[fileset], saved_fspec[fileset], pathholder[fileset]); return (pathholder[fileset]); /* matching path */ } } /* nextfile */ /*******************/ /* fcbpath() accepts a pointer to an ffblk structure, a character pointer to a pathname that may contain wildcards, and a character pointer to a buffer. Copies into buffer the path prefix from the pathname and the filename prefix from the ffblk so that it forms a complete path. */ void fcbpath (ffblk, old_path, new_path) struct ffblk *ffblk; char *old_path; register char *new_path; { register int i; int length, start_pos; strcpy(new_path, old_path); /* copy the whole thing first */ length = strlen(new_path); i = length - 1; /* i points to end of path */ while (i >= 0 && new_path[i] != '/' && new_path[i] != '\\' && new_path[i] != ':') i--; /* either we found a "/", "\", or ":", or we reached the beginning of the name. In any case, i points to the last character of the path part. */ start_pos = i + 1; for (i = 0; i < 13; i++) new_path[start_pos+i] = ffblk->ff_name[i]; new_path[start_pos+13] = '\0'; } #endif /* PORTABLE */