12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286 |
- /* scandir.c Copyright (C) Codemist Ltd., 1994-2002 */
- /*
- *
- * Directory scanning code for use in CSL-related utilities.
- *
- * A C Norman
- */
- /*
- * This code may be used and modified, and redistributed in binary
- * or source form, subject to the "CCL Public License", which should
- * accompany it. This license is a variant on the BSD license, and thus
- * permits use of code derived from this in either open and commercial
- * projects: but it does require that updates to this code be made
- * available back to the originators of the package.
- * Before merging other code in with this or linking this code
- * with other packages or libraries please check that the license terms
- * of the other material are compatible with those of this.
- */
- /* Signature: 163eeafe 10-Oct-2002 */
- #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_hook)(len);
- else return (*realloc_hook)(p, len);
- }
- void set_hostcase(int fg)
- {
- hostcase = fg;
- }
- #ifdef __LCC__
- static char filename[LONGEST_LEGAL_FILENAME];
- static struct _finddata_t *found_files = NULL;
- static int n_found_files = 0, max_found_files = 0;
- #define TABLE_INCREMENT 50
- static int more_files(void)
- {
- if (n_found_files > max_found_files - 5)
- { struct _finddata_t *fnew = (struct _finddata_t *)
- my_realloc((void *)found_files,
- sizeof(struct _finddata_t) *
- (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 struct _finddata_t *fa = (const struct _finddata_t *)a,
- *fb = (const struct _finddata_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;
- long code;
- int first = n_found_files;
- long fh;
- struct _finddata_t found;
- fh = _findfirst(filename, &found);
- code = fh;
- while (code != -1)
- { if (more_files()) break;
- found_files[n_found_files++] = found;
- code = _findnext(fh, &found);
- }
- _findclose(fh);
- qsort((void *)&found_files[first],
- n_found_files-first,
- sizeof(struct _finddata_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;
- 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++] = (char)c;
- }
- filename[namelength] = 0;
- if (found_files[n_found_files].attrib & _A_SUBDIR)
- { 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);
- }
- #define SCANDIR_KNOWN 1
- #else
- #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(void)
- {
- 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++] = (char)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(void)
- {
- 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++] = (char)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(void)
- {
- 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++] = (char)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(void)
- {
- 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++] = (char)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(void)
- {
- 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++] = (char)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++] = (char)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 */
- #endif /* __LCC__ */
- #ifndef SCANDIR_KNOWN
- #error "Directory scanning machine-specific code not present"
- #endif
- /* end of scandir.c */
|