123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149 |
- /*
- * scandir.c Copyright (C) Codemist Ltd., 1994-98
- *
- *
- * Directory scanning code for use in CSL-related utilities.
- *
- * A C Norman
- */
- /* Signature: 29696d9f 15-Sep-1998 */
- #include "sys.h"
- /*
- * If I am to process directories I need a set of routines that will
- * scan sub-directories for me. This is (necessarily?) dependent on
- * the operating system I am running under, hence the conditional compilation
- * here. The specification I want is:
- * void scan_directory(char *dir,
- * void (*proc)(char *name, int why, long int size));
- *
- * This is called with a file- or directory-name as its first argument
- * and a function as its second.
- * It calls the function for every directory and every file that can be found
- * rooted from the given place. If the file to scan is specified as NULL
- * the current directory is processed. I also arrange that an input string
- * "." (on Windows, DOS and Unix) or "@" (Archimedes) is treated as a request
- * to scan the whole of the current directory.
- * When a simple file is found the procedure is called with the name of the
- * file, why=0, and the length (in bytes) of the file. For a directory
- * the function is called with why=1, then the contents of the directory are
- * processed. For directories the size information will be 0. There is no
- * guarantee of useful behaviour if some of the files to be scanned are
- * flagged as "invisible" or "not readable" or if they are otherwise special.
- *
- * I also provide a similar function scan_files() with the same arguments that
- * does just the same except that it does not recurse into sub-directories,
- * but if the name originally passed is that of a directory then all the
- * files in it will be scanned.
- */
- /*
- * When scan_directory calls the procedure it has been passed, it will have
- * set scan_leafstart to the offset in the passed filename where the
- * original directory ended and the new information starts.
- */
- int scan_leafstart = 0;
- /* #define SCAN_FILE 0 */ /* In scandir.h - listed here for emphasis */
- /* #define SCAN_STARTDIR 1 */
- /* #define SCAN_ENDDIR 2 */
- /*
- * I use a (static) flag to indicate how sub-directories should be
- * handled, and what to do about case. By default I fold to lower case
- * on windows. setting hostcase non-zero causes case to be preserved.
- */
- static int recursive_scan, hostcase = 0;
- /*
- * The following is an expression of despair! ANSI C (all the way back from
- * 1989, and based on good practise from before then, mandates that
- * realloc should behave as malloc if its first arg is NULL. But STILL there
- * are C libraries out there which do not honour this and which crash
- * in such cases. Thus this veneer ought to be unnecessary but in reality
- * is a useful safety net!
- */
- static void *my_realloc(void *p, int len)
- {
- if (p == NULL) return malloc(len);
- else return realloc(p, len);
- }
- void set_hostcase(int fg)
- {
- hostcase = fg;
- }
- #ifdef WINDOWS_NT
- /*
- * Note that I put the test for WINDOWS_NT before the test for MS_DOS
- * so that if it happens that the symbol MS_DOS is defined that fact will
- * not cause too much confusion.
- */
- static char filename[LONGEST_LEGAL_FILENAME];
- static WIN32_FIND_DATA *found_files = NULL;
- static int n_found_files = 0, max_found_files = 0;
- #define TABLE_INCREMENT 50
- static int more_files()
- {
- if (n_found_files > max_found_files - 5)
- { WIN32_FIND_DATA *fnew = (WIN32_FIND_DATA *)
- my_realloc((void *)found_files,
- sizeof(WIN32_FIND_DATA)*
- (max_found_files + TABLE_INCREMENT));
- if (fnew == NULL) return 1; /* failure flag */
- found_files = fnew;
- max_found_files += TABLE_INCREMENT;
- }
- return 0;
- }
- /*
- * Anybody compiling using Microsoft Visual C++ had better note that
- * the type declared in the Microsoft header files for qsort insists
- * on a __cdecl here. Ugh.
- */
- int MS_CDECL alphasort_files(const void *a, const void *b)
- {
- const WIN32_FIND_DATA *fa = (const WIN32_FIND_DATA *)a,
- *fb = (const WIN32_FIND_DATA *)b;
- return strncmp(fb->cFileName, fa->cFileName, sizeof(fa->cFileName));
- }
- static void exall(int namelength,
- void (*proc)(char *name, int why, long int size))
- /*
- * This procedure scans a directory-full of files, calling the given procedure
- * to process each one it finds.
- */
- {
- WIN32_FIND_DATA found;
- int rootlen = namelength, first = n_found_files;
- HANDLE hSearch = FindFirstFile(filename, &found);
- if (hSearch == INVALID_HANDLE_VALUE) return; /* No files found at all */
- for (;;)
- { if (more_files()) break;
- found_files[n_found_files++] = found;
- if (!FindNextFile(hSearch, &found)) break;
- }
- FindClose(hSearch);
- qsort((void *)&found_files[first],
- n_found_files-first,
- sizeof(WIN32_FIND_DATA),
- alphasort_files);
- while (rootlen>=0 && filename[rootlen]!='\\') rootlen--;
- while (n_found_files != first)
- { char *p = (char *)&found_files[--n_found_files].cFileName;
- int c;
- /*
- * Fill out filename with the actual name I grabbed, i.e. with
- * wild-cards expanded.
- */
- namelength = rootlen+1;
- /*
- * I fold DOS filenames into lower case because it does not matter much
- * to DOS and I think it looks better - furthermore it helps when I move
- * archives to other systems. So I do the same on NT.
- */
- while ((c = *p++) != 0)
- { if (!hostcase) if (isupper(c)) c = tolower(c);
- filename[namelength++] = c;
- }
- filename[namelength] = 0;
- if (found_files[n_found_files].dwFileAttributes &
- FILE_ATTRIBUTE_DIRECTORY)
- { if (found_files[n_found_files].cFileName[0] != '.')
- /*
- * I filter out directory names that start with '.'.
- * This is to avoid calamity with recursion though chains such as .\.\.\.....
- */
- { proc(filename, SCAN_STARTDIR, 0);
- if (!recursive_scan) continue;
- strcpy(&filename[namelength], "\\*.*");
- /*
- * Append "\*.*" to the directory-name and try again, thereby scanning
- * its contents.
- */
- exall(namelength+4, proc);
- filename[namelength] = 0;
- proc(filename, SCAN_ENDDIR, 0);
- }
- }
- else proc(filename, SCAN_FILE,
- found_files[n_found_files].nFileSizeLow);
- }
- return;
- }
- void scan_directory(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 1;
- if (dir==NULL || strcmp(dir,".")==0)
- { dir = "*.*";
- scan_leafstart = 0;
- }
- else scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- exall(strlen(filename), proc);
- }
- void scan_files(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 0;
- if (dir==NULL || strcmp(dir,".")==0)
- { strcpy(filename, "*.*");
- scan_leafstart = 0;
- }
- else
- { scan_leafstart = strlen(dir);
- strcpy(filename, dir);
- if (filename[scan_leafstart-1] == '\\')
- { /* Root directory */
- strcpy(filename+scan_leafstart, "*.*");
- --scan_leafstart;
- }
- else strcpy(filename+scan_leafstart, "\\*.*");
- scan_leafstart++;
- }
- exall(strlen(filename), proc);
- }
- #define SCANDIR_KNOWN 1
- #else /* WINDOWS_NT */
- #ifdef MS_DOS
- /*
- * This will be OK for both Zortech and Watcom. The entry for GCCWIN refers
- * to Cygnus cygwin32 "Windows GCC" together with the windows32api header
- * files and libraries. However note well that the cygwin32 version of this
- * code has not yet been got working and the status of various bits of
- * Windows code in that environment remains slightly delicate as of 1Q97.
- */
- #if defined __WATCOMC__ || defined _MSC_VER || defined GCCWIN
- static char filename[LONGEST_LEGAL_FILENAME];
- static WIN32_FIND_DATA *found_files = NULL;
- static int n_found_files = 0, max_found_files = 0;
- #define TABLE_INCREMENT 50
- static int more_files()
- {
- if (n_found_files > max_found_files - 5)
- { WIN32_FIND_DATA *fnew = (WIN32_FIND_DATA *)
- my_realloc((void *)found_files,
- sizeof(WIN32_FIND_DATA) *
- (max_found_files + TABLE_INCREMENT));
- if (fnew == NULL) return 1; /* failure flag */
- found_files = fnew;
- max_found_files += TABLE_INCREMENT;
- }
- return 0;
- }
- int MS_CDECL alphasort_files(const void *a, const void *b)
- {
- const WIN32_FIND_DATA *fa = (const WIN32_FIND_DATA *)a,
- *fb = (const WIN32_FIND_DATA *)b;
- return strncmp(fb->cFileName, fa->cFileName, sizeof(fa->cFileName));
- }
- static void exall(int namelength,
- void (*proc)(char *name, int why, long int size))
- /*
- * This procedure scans a directory-full of files, calling the given procedure
- * to process each one it finds.
- */
- {
- int rootlen = namelength;
- int code, first = n_found_files;
- HANDLE fh;
- WIN32_FIND_DATA found;
- fh = FindFirstFile(filename, &found);
- code = (fh != INVALID_HANDLE_VALUE);
- while (code)
- { if (more_files()) break;
- found_files[n_found_files++] = found;
- code = FindNextFile(fh, &found);
- }
- FindClose(fh);
- qsort((void *)&found_files[first],
- n_found_files-first,
- sizeof(WIN32_FIND_DATA),
- alphasort_files);
- while (rootlen>=0 && filename[rootlen]!='\\') rootlen--;
- while (n_found_files != first)
- { char *p = (char *)&found_files[--n_found_files].cFileName;
- int c;
- /*
- * Fill out filename with the actual name I grabbed, i.e. with
- * wild-cards expanded.
- */
- namelength = rootlen+1;
- /*
- * I fold DOS filenames into lower case because it does not matter much
- * to DOS and I think it looks better - furthermore it helps when I move
- * archives to other systems.
- */
- while ((c = *p++) != 0)
- { if (!hostcase) if (isupper(c)) c = tolower(c);
- filename[namelength++] = c;
- }
- filename[namelength] = 0;
- if (found_files[n_found_files].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- { if (found_files[n_found_files].cFileName[0] != '.')
- /*
- * I filter out directory names that start with '.'.
- * This is to avoid calamity with recursion though chains such as .\.\.\.....
- */
- { proc(filename, SCAN_STARTDIR, 0);
- if (!recursive_scan) continue;
- strcpy(&filename[namelength], "\\*.*");
- /*
- * Append "\*.*" to the directory-name and try again, thereby scanning
- * its contents.
- */
- exall(namelength+4, proc);
- filename[namelength] = 0;
- proc(filename, SCAN_ENDDIR, 0);
- }
- }
- else proc(filename, SCAN_FILE, found_files[n_found_files].nFileSizeLow);
- }
- return;
- }
- void scan_directory(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 1;
- if (dir==NULL || strcmp(dir,".")==0)
- { dir = "*.*";
- scan_leafstart = 0;
- }
- else scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- exall(strlen(filename), proc);
- }
- void scan_files(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 0;
- if (dir==NULL || strcmp(dir,".")==0)
- { strcpy(filename, "*.*");
- scan_leafstart = 0;
- }
- else
- { scan_leafstart = strlen(dir);
- strcpy(filename, dir);
- strcpy(filename+scan_leafstart, "\\*.*");
- scan_leafstart++;
- }
- exall(strlen(filename), proc);
- }
- #else
- #ifdef GCC386
- /*
- * BEWARE: this version will not recognise Windows 95 long file-names
- * and so there is very real possibility of muddle.
- */
- static char filename[LONGEST_LEGAL_FILENAME];
- static struct ffblk *found_files = NULL;
- static int n_found_files = 0, max_found_files = 0;
- #define TABLE_INCREMENT 50
- static int more_files()
- {
- if (n_found_files > max_found_files - 5)
- { struct ffblk *fnew = (struct ffblk *)
- my_realloc((void *)found_files,
- sizeof(struct ffblk) *
- (max_found_files + TABLE_INCREMENT));
- if (fnew == NULL) return 1; /* failure flag */
- found_files = fnew;
- max_found_files += TABLE_INCREMENT;
- }
- return 0;
- }
- int alphasort_files(const void *a, const void *b)
- {
- const struct ffblk *fa = (const struct ffblk *)a,
- *fb = (const struct ffblk *)b;
- return strncmp(fb->ff_name, fa->ff_name, sizeof(fa->ff_name));
- }
- static void exall(int namelength,
- void (*proc)(char *name, int why, long int size))
- /*
- * This procedure scans a directory-full of files, calling the given procedure
- * to process each one it finds.
- */
- {
- int rootlen = namelength;
- int code, first = n_found_files;
- struct ffblk found;
- code = findfirst(filename, &found, FA_DIREC);
- while (code == 0)
- { if (more_files()) break;
- found_files[n_found_files++] = found;
- code = findnext(&found);
- }
- qsort((void *)&found_files[first],
- n_found_files-first,
- sizeof(struct ffblk),
- alphasort_files);
- while (rootlen>=0 && filename[rootlen]!='\\') rootlen--;
- while (n_found_files != first)
- { char *p = (char *)&found_files[--n_found_files].ff_name;
- int c;
- /*
- * Fill out filename with the actual name I grabbed, i.e. with
- * wild-cards expanded.
- */
- namelength = rootlen+1;
- /*
- * I fold DOS filenames into lower case because it does not matter much
- * to DOS and I think it looks better - furthermore it helps when I move
- * archives to other systems.
- */
- while ((c = *p++) != 0)
- { if (!hostcase) if (isupper(c)) c = tolower(c);
- filename[namelength++] = c;
- }
- filename[namelength] = 0;
- if (found_files[n_found_files].ff_attrib & FA_DIREC)
- { if (found_files[n_found_files].ff_name[0] != '.')
- /*
- * I filter out directory names that start with '.'.
- * This is to avoid calamity with recursion though chains such as .\.\.\.....
- */
- { proc(filename, SCAN_STARTDIR, 0);
- if (!recursive_scan) continue;
- strcpy(&filename[namelength], "\\*.*");
- /*
- * Append "\*.*" to the directory-name and try again, thereby scanning
- * its contents.
- */
- exall(namelength+4, proc);
- filename[namelength] = 0;
- proc(filename, SCAN_ENDDIR, 0);
- }
- }
- else proc(filename, SCAN_FILE, found_files[n_found_files].ff_fsize);
- }
- return;
- }
- void scan_directory(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 1;
- if (dir==NULL || strcmp(dir,".")==0)
- { dir = "*.*";
- scan_leafstart = 0;
- }
- else scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- exall(strlen(filename), proc);
- }
- void scan_files(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 0;
- if (dir==NULL || strcmp(dir,".")==0)
- { strcpy(filename, "*.*");
- scan_leafstart = 0;
- }
- else
- { scan_leafstart = strlen(dir);
- strcpy(filename, dir);
- strcpy(filename+scan_leafstart, "\\*.*");
- scan_leafstart++;
- }
- exall(strlen(filename), proc);
- }
- #else /* __WATCOMC__ */
- static char filename[LONGEST_LEGAL_FILENAME];
- static struct find_t *found_files = NULL;
- static int n_found_files = 0, max_found_files = 0;
- #define TABLE_INCREMENT 50
- static int more_files()
- {
- if (n_found_files > max_found_files - 5)
- { struct find_t *fnew = (struct find_t *)
- my_realloc((void *)found_files,
- sizeof(struct find_t) *
- (max_found_files + TABLE_INCREMENT));
- if (fnew == NULL) return 1; /* failure flag */
- found_files = fnew;
- max_found_files += TABLE_INCREMENT;
- }
- return 0;
- }
- int alphasort_files(const void *a, const void *b)
- {
- const struct find_t *fa = (const struct find_t *)a,
- *fb = (const struct find_t *)b;
- return strncmp(fb->name, fa->name, sizeof(fa->name));
- }
- static void exall(int namelength,
- void (*proc)(char *name, int why, long int size))
- /*
- * This procedure scans a directory-full of files, calling the given procedure
- * to process each one it finds.
- */
- {
- int rootlen = namelength;
- int code, first = n_found_files;
- struct find_t found;
- #ifdef FA_DIREC
- code = _dos_findfirst(filename, FA_DIREC, &found);
- #else
- code = _dos_findfirst(filename, _A_SUBDIR, &found);
- #endif
- while (code == 0)
- { if (more_files()) break;
- found_files[n_found_files++] = found;
- code = _dos_findnext(&found);
- }
- qsort((void *)&found_files[first],
- n_found_files-first,
- sizeof(struct find_t),
- alphasort_files);
- while (rootlen>=0 && filename[rootlen]!='\\') rootlen--;
- while (n_found_files != first)
- { char *p = (char *)&found_files[--n_found_files].name;
- int c;
- /*
- * Fill out filename with the actual name I grabbed, i.e. with
- * wild-cards expanded.
- */
- namelength = rootlen+1;
- /*
- * I fold DOS filenames into lower case because it does not matter much
- * to DOS and I think it looks better - furthermore it helps when I move
- * archives to other systems.
- */
- while ((c = *p++) != 0)
- { if (!hostcase) if (isupper(c)) c = tolower(c);
- filename[namelength++] = c;
- }
- filename[namelength] = 0;
- #ifdef FA_DIREC
- if (found_files[n_found_files].attribute & FA_DIREC)
- #else
- if (found_files[n_found_files].attrib & _A_SUBDIR)
- #endif
- { if (found_files[n_found_files].name[0] != '.')
- /*
- * I filter out directory names that start with '.'.
- * This is to avoid calamity with recursion though chains such as .\.\.\.....
- */
- { proc(filename, SCAN_STARTDIR, 0);
- if (!recursive_scan) continue;
- strcpy(&filename[namelength], "\\*.*");
- /*
- * Append "\*.*" to the directory-name and try again, thereby scanning
- * its contents.
- */
- exall(namelength+4, proc);
- filename[namelength] = 0;
- proc(filename, SCAN_ENDDIR, 0);
- }
- }
- else proc(filename, SCAN_FILE, found_files[n_found_files].size);
- }
- return;
- }
- void scan_directory(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 1;
- if (dir==NULL || strcmp(dir,".")==0)
- { dir = "*.*";
- scan_leafstart = 0;
- }
- else scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- exall(strlen(filename), proc);
- }
- void scan_files(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 0;
- if (dir==NULL || strcmp(dir,".")==0)
- { strcpy(filename, "*.*");
- scan_leafstart = 0;
- }
- else
- { scan_leafstart = strlen(dir);
- strcpy(filename, dir);
- strcpy(filename+scan_leafstart, "\\*.*");
- scan_leafstart++;
- }
- exall(strlen(filename), proc);
- }
- #endif /* __WATCOMC__ */
- #endif /* GCC386 */
- #define SCANDIR_KNOWN 1
- #else /* MS_DOS */
- #ifdef UNIX
- static char filename[LONGEST_LEGAL_FILENAME];
- /*
- * The code here uses opendir, readdir and closedir and as such ought to
- * be Posix compatible. The macro USE_DIRECT_H can cause an older variant
- * on this idea to be used. BUt it may need adjustment for different
- * systems.
- */
- #ifdef USE_DIRECT_H
- #include <sys/types.h>
- #include <sys/dir.h>
- #else
- #include <dirent.h>
- #endif
- static char **found_files = NULL;
- int n_found_files = 0, max_found_files = 0;
- #define TABLE_INCREMENT 50
- static int more_files()
- {
- if (n_found_files > max_found_files - 5)
- { char **fnew = (char **)
- my_realloc((void *)found_files,
- sizeof(char *) *
- (max_found_files + TABLE_INCREMENT));
- if (fnew == NULL) return 1; /* failure flag */
- found_files = fnew;
- max_found_files += TABLE_INCREMENT;
- }
- return 0;
- }
- int alphasort_files(const void *a, const void *b)
- {
- const char *fa = *(const char **)a,
- *fb = *(const char **)b;
- return strcmp(fb, fa);
- }
- extern int stat(const char *, struct stat*);
- static void scan_file(int namelength,
- void (*proc)(char *name, int why, long int size));
- static void exall(int namelength,
- void (*proc)(char *name, int why, long int size))
- {
- DIR *d;
- #ifdef USE_DIRECT_H
- struct direct *dd;
- #else
- struct dirent *dd;
- #endif
- int i, j;
- int rootlen = namelength, first = n_found_files;
- proc(filename, SCAN_STARTDIR, 0);
- d = opendir(filename);
- if (d != NULL)
- { while ((dd = readdir(d)) != NULL)
- { char *leafname = dd->d_name;
- char *copyname;
- /*
- * readdir hands back both "." and ".." but I had better not recurse
- * into either!
- */
- if (strcmp(leafname, ".") == 0 ||
- strcmp(leafname, "..") == 0) continue;
- if (more_files()) break;
- copyname = (char *)malloc(1+strlen(leafname));
- if (copyname == NULL) break;
- strcpy(copyname, leafname);
- found_files[n_found_files++] = copyname;
- }
- closedir(d);
- }
- qsort((void *)&found_files[first],
- n_found_files-first,
- sizeof(char *),
- alphasort_files);
- filename[rootlen] = '/';
- while (n_found_files != first)
- { char *p = found_files[--n_found_files];
- int c;
- namelength = rootlen+1;
- while ((c = *p++) != 0) filename[namelength++] = c;
- free((void *)found_files[n_found_files]);
- filename[namelength] = 0;
- scan_file(namelength, proc);
- }
- filename[rootlen] = 0;
- proc(filename, SCAN_ENDDIR, 0);
- }
- #ifndef S_IFMT
- # ifdef __S_IFMT
- # define S_IFMT __S_IFMT
- # endif
- #endif
- #ifndef S_IFDIR
- # ifdef __S_IFDIR
- # define S_IFDIR __S_IFDIR
- # endif
- #endif
- #ifndef S_IFREG
- # ifdef __S_IFREG
- # define S_IFREG __S_IFREG
- # endif
- #endif
- static void scan_file(int namelength,
- void (*proc)(char *name, int why, long int size))
- {
- struct stat buf;
- stat(filename, &buf);
- if ((buf.st_mode & S_IFMT) == S_IFDIR)
- { if (!recursive_scan) proc(filename, SCAN_STARTDIR, 0);
- else exall(namelength, proc);
- }
- else if ((buf.st_mode & S_IFMT) == S_IFREG)
- proc(filename, SCAN_FILE, buf.st_size);
- /* else fprintf(stderr, "Mode of %s is %o\n", filename, buf.st_mode); */
- }
- void scan_directory(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 1;
- if (dir==NULL || strcmp(dir, ".")==0) dir = ".";
- scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- scan_file(scan_leafstart-1, proc);
- }
- void scan_files(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 0;
- if (dir==NULL || strcmp(dir, ".")==0) dir = ".";
- scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- exall(scan_leafstart-1, proc);
- }
- #define SCANDIR_KNOWN 1
- #else /* UNIX */
- #ifdef __arm
- /*
- * I want to be able to find the currently-selected directory - if
- * only so I can restore it at the end of processing. Yes I do know
- * that RISCOS is moving away from the concept of a current directory,
- * but this is a command-line utility at present, at least.
- */
- static void find_current_directory(char dir[])
- {
- os_gbpbstr block;
- char drivename[64];
- char name[32];
- /*
- * osgbpb(5) reads the name of the current disc - which I need as the first
- * part of a full-rooted file-path.
- */
- block.action = 5;
- block.file_handle = 0;
- block.data_addr = drivename;
- os_gbpb(&block);
- for (;;)
- { int len;
- /*
- * osgbpb(6) reads the name of the currently selected directory - but just
- * the trailing component.
- */
- block.action = 6;
- block.file_handle = 0;
- block.data_addr = name;
- os_gbpb(&block);
- len = name[1];
- /* Here I trim trailing blanks from the name */
- while (name[len + 1] == ' ' && len > 0) len--;
- if (dir[0] == 0)
- { memcpy(dir, &name[2], len);
- dir[len] = 0;
- }
- else
- { memmove(&dir[1 + len], dir, strlen(dir) + 1);
- memcpy(dir, &name[2], len);
- dir[len] = '.';
- }
- /*
- * When I find that the director name is '$' I conclude that I must be
- * at the top of the tree, and I exit.
- */
- if (len == 1 && name[2] == '$')
- { len = drivename[0];
- memmove(&dir[2 + len], dir, strlen(dir) + 1);
- memcpy(&dir[1], &drivename[1], len);
- dir[0] = ':';
- dir[len+1] = '.';
- return;
- }
- /*
- * Mostly I select the parent directory, and by reading names of
- * successive parents I build up a complete name.
- */
- system("dir ^");
- }
- }
- #define AT_ONCE 80
- #define NAME_LENGTH 12
- static char filename[LONGEST_LEGAL_FILENAME];
- static char dirsave[LONGEST_LEGAL_FILENAME+4];
- /* Original directory the user had selected */
- static void exall(int namelength,
- void (*proc)(char *name, int why, long int size))
- /*
- * This procedure scans a directory-full of files, calling the given procedure
- * to process each one it finds.
- */
- {
- os_filestr file_status;
- /*
- * osfile(5) reads information about a file - in particular it allows me to
- * tell if I have a simple file or a directory.
- */
- file_status.action = 5;
- file_status.name = filename;
- if (os_file(&file_status) != NULL) file_status.action = 99;
- switch (file_status.action)
- {
- default:
- /* fprintf(stderr, "\nBad return code from osfile\n"); */
- return;
- /* case 0: fprintf(stderr, "\nFile %s not found\n", filename); */
- /* exit(EXIT_FAILURE); */
- case 0xff: /* Protected file */
- case 1: proc(filename, SCAN_FILE, file_status.start); /* Simple file */
- return;
- case 2: /* Here we have a directory to scan */
- proc(filename, SCAN_STARTDIR, 0);
- if (!recursive_scan) return;
- { char workvec[NAME_LENGTH*AT_ONCE];
- os_gbpbstr block;
- block.seq_point = 0;
- for (;;)
- { char *p = workvec;
- block.action = 9;
- block.file_handle = (int)filename;/* Scan given directory */
- block.data_addr = workvec;
- block.number = AT_ONCE;
- block.buf_len = NAME_LENGTH*AT_ONCE;
- block.wild_fld = "*";
- filename[namelength] = 0;
- /*
- * osgbpb(9) reads (several) file-names from the specified directory.
- */
- os_gbpb(&block);
- if (block.number == 0) break; /* Nothing transfered */
- while (block.number != 0)
- { int len = strlen(p);
- filename[namelength] = '.';
- strcpy(&filename[namelength+1], p);
- p += len + 1;
- /*
- * I concatenate the name of the new directory on the end of my current path
- * and recurse into it.
- */
- exall(namelength + len + 1, proc);
- block.number--;
- }
- if (block.seq_point == -1) break;
- }
- filename[namelength] = 0;
- }
- proc(filename, SCAN_ENDDIR, 0);
- return;
- }
- }
- void scan_directory(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 1;
- strcpy(dirsave, "dir ");
- find_current_directory(dirsave+4); /* Find initial directory */
- system(dirsave); /* Restore initial directory */
- strcpy(filename, dir==NULL ? "@" : dir);
- scan_leafstart = strcmp(dir, "@")==0 ? 2 : 0;
- exall(strlen(filename), proc);
- system(dirsave); /* Restore initial directory */
- }
- void scan_files(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 0;
- strcpy(dirsave, "dir ");
- find_current_directory(dirsave+4); /* Find initial directory */
- system(dirsave); /* Restore initial directory */
- strcpy(filename, dir==NULL ? "@" : dir);
- scan_leafstart = strcmp(dir, "@")==0 ? 2 : 0;
- exall(strlen(filename), proc);
- system(dirsave); /* Restore initial directory */
- }
- #define SCANDIR_KNOWN 1
- #else /* __arm */
- #ifdef ATARI
- static char filename[LONGEST_LEGAL_FILENAME];
- static void exall(int32 namelength,
- void (*proc)(char *name, int why, long int size))
- /*
- * This procedure scans a directory-full of files, calling the given procedure
- * to process each one it finds.
- */
- {
- int32 rootlen = namelength;
- int code;
- struct FILEINFO found;
- code = dfind(&found, filename, FA_DIREC);
- while (rootlen>=0 && filename[rootlen]!='\\') rootlen--;
- /*
- * If I used _dos_findfirst I could allow recursion here,
- * and if I call findfirst(filename, FA_DIREC) then directories can
- * be found as well as just files.
- */
- while (code == 0)
- { char *p = (char *)&found.name;
- int c;
- /*
- * Fill out filename with the actual name I grabbed, i.e. with
- * wild-cards expanded.
- */
- namelength = rootlen+1;
- /*
- * I fold Atari filenames into lower case because it does not matter much
- * to Atari and I think it looks better - furthermore it helps when I move
- * archives to other systems.
- */
- while ((c = *p++) != 0)
- { if (!hostcase) c = tolower(c);
- filename[namelength++] = c;
- }
- filename[namelength] = 0;
- if (found.attr & FA_DIREC)
- { if (found.name[0]!='.')
- /*
- * I filter out directory names that start with '.'.
- * This is to avoid calamity with recursion though chains such as .\.\.\.....
- */
- { proc(filename, SCAN_STARTDIR, 0);
- if (!recursive_scan) continue;
- strcpy(&filename[namelength], "\\*.*");
- /*
- * Append "\*.*" to the directory-name and try again, thereby scanning
- * its contents.
- */
- exall(namelength+4, proc);
- filename[namelength] = 0;
- proc(filename, SCAN_ENDDIR, 0);
- }
- }
- else proc(filename, SCAN_FILE, found.size);
- code = dnext(&found);
- }
- return;
- }
- void scan_directory(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 1;
- if (dir==NULL || strcmp(dir,".")==0)
- { dir = "*.*";
- scan_leafstart = 0;
- }
- else scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- exall(strlen(filename), proc);
- }
- void scan_files(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 0;
- if (dir==NULL || strcmp(dir,".")==0)
- { dir = "*.*";
- scan_leafstart = 0;
- }
- else scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- exall(strlen(filename), proc);
- }
- #define SCANDIR_KNOWN 1
- #else /* ATARI */
- #ifdef macintosh
- /*
- * I have place-holder routines here, so that at some stage proper versions
- * can be written and installed. By leaving the Unix code in as comment I hope
- * to help whoever gets around to building the Macintosh-specific versions...
- */
- static char filename[LONGEST_LEGAL_FILENAME];
- #ifdef THIS_NEEDS_RE_WRITING_FOR_MACINTOSH
- static int remove_dot(struct direct *name)
- {
- if (strcmp(name->d_name, ".")==0 || strcmp(name->d_name, "..")==0) return 0;
- return 1;
- }
- #endif
- /* int alphasort(struct direct **, struct direct **); */
- /* extern int stat(const char *, struct stat*); */
- static void scan_file(int namelength,
- void (*proc)(char *name, int why, long int size));
- static void exall(int namelength,
- void (*proc)(char *name, int why, long int size))
- {
- #ifdef THIS_NEEDS_RE_WRITING_FOR_MACINTOSH
- struct direct **namelist;
- int i, j;
- proc(filename, SCAN_STARTDIR, 0);
- if (!recursive_scan) return;
- i = scandir(filename, &namelist, remove_dot, alphasort);
- for(j=0; j<i; j++)
- { char *leafname = namelist[j]->d_name;
- filename[namelength] = '/';
- strcpy(&filename[namelength+1], leafname);
- scan_file(namelength+1+strlen(leafname), proc);
- free(namelist[j]);
- }
- free(namelist);
- filename[namelength] = 0;
- proc(filename, SCAN_ENDDIR, 0);
- #endif
- }
- static void scan_file(int namelength,
- void (*proc)(char *name, int why, long int size))
- {
- #ifdef THIS_NEEDS_RE_WRITING_FOR_MACINTOSH
- struct stat buf;
- stat(filename, &buf);
- if ((buf.st_mode & S_IFMT) == S_IFDIR) exall(namelength, proc);
- else if ((buf.st_mode & S_IFMT) == S_IFREG)
- proc(filename, SCAN_FILE, buf.st_size);
- /* else fprintf(stderr, "Mode of %s is %o\n", filename, buf.st_mode); */
- #endif
- }
- void scan_directory(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 1;
- if (dir==NULL || strcmp(dir, ".")==0) dir = ".";
- scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- scan_file(scan_leafstart-1, proc);
- }
- void scan_files(char *dir,
- void (*proc)(char *name, int why, long int size))
- {
- recursive_scan = 0;
- if (dir==NULL || strcmp(dir, ".")==0) dir = ".";
- scan_leafstart = strlen(dir)+1;
- strcpy(filename, dir);
- scan_file(scan_leafstart-1, proc);
- }
- #define SCANDIR_KNOWN 1
- #endif /* macintosh */
- #endif /* ATARI */
- #endif /* __arm */
- #endif /* UNIX */
- #endif /* MS_DOS */
- #endif /* WINDOWS_NT */
- #ifndef SCANDIR_KNOWN
- #error "Directory scanning machine-specific code not present"
- #endif
- /* end of scandir.c */
|