diff --git a/.travis.sh b/.travis.sh index 76586145..5529d01e 100755 --- a/.travis.sh +++ b/.travis.sh @@ -1,6 +1,6 @@ #!/bin/sh if [ "$ANALYZE" = "true" ] ; then - cppcheck --error-exitcode=1 -j2 -DRANGECHECK -ISource Source toolsrc 2> stderr.txt + cppcheck --error-exitcode=1 -j2 -DRANGECHECK -iSource/win_opendir.c -ISource Source toolsrc 2> stderr.txt RET=$? if [ -s stderr.txt ] then diff --git a/CMakeLists.txt b/CMakeLists.txt index ce4225d9..a2fffad3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ include(CheckLibraryExists) +include(CheckIncludeFile) include(ExternalProject) # Adds the cmake directory to the CMake include path. @@ -43,6 +44,7 @@ option("${PROJECT_NAME}_STRICT" "Prefer original MBF code paths over demo compat # Compiler environment requirements. check_library_exists(m pow "" m_FOUND) +check_include_file("dirent.h" HAVE_DIRENT_H) # Library requirements. # diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 90c4bc2e..4815b913 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -27,6 +27,7 @@ set(WOOF_SOURCES g_game.c g_game.h hu_lib.c hu_lib.h hu_stuff.c hu_stuff.h + i_glob.c i_glob.h i_main.c i_midipipe.c i_midipipe.h i_net.c i_net.h @@ -92,6 +93,12 @@ set(WOOF_SOURCES wi_stuff.c wi_stuff.h z_zone.c z_zone.h) +if(MSVC) + list(APPEND + WOOF_SOURCES + win_opendir.c win_opendir.h) +endif() + # Some platforms require standard libraries to be linked against. if(m_FOUND) list(APPEND WOOF_LIBRARIES m) diff --git a/Source/d_deh.c b/Source/d_deh.c index 51d81c8b..dd04df3d 100644 --- a/Source/d_deh.c +++ b/Source/d_deh.c @@ -1400,7 +1400,7 @@ actionf_t deh_codeptr[NUMSTATES]; // killough 10/98: // substantially modified to allow input from wad lumps instead of .deh files. -void ProcessDehFile(char *filename, char *outfilename, int lumpnum) +void ProcessDehFile(const char *filename, char *outfilename, int lumpnum) { static FILE *fileout; // In case -dehout was used DEHFILE infile, *filein = &infile; // killough 10/98 diff --git a/Source/d_main.c b/Source/d_main.c index 52f4c2c7..d7f3c45a 100644 --- a/Source/d_main.c +++ b/Source/d_main.c @@ -67,11 +67,12 @@ #include "d_deh.h" // Ty 04/08/98 - Externalizations #include "statdump.h" // [FG] StatDump() #include "u_mapinfo.h" // U_ParseMapInfo() +#include "i_glob.h" // [FG] I_StartMultiGlob() // DEHacked support - Ty 03/09/97 // killough 10/98: // Add lump number as third argument, for use when filename==NULL -void ProcessDehFile(char *filename, char *outfilename, int lump); +void ProcessDehFile(const char *filename, char *outfilename, int lump); // killough 10/98: support -dehout filename static char *D_dehout(void) @@ -532,7 +533,7 @@ static char title[128]; // killough 11/98: remove limit on number of files // -void D_AddFile(char *file) +void D_AddFile(const char *file) { static int numwadfiles, numwadfiles_alloc; @@ -630,6 +631,31 @@ char *D_DoomPrefDir(void) return dir; } +// Calculate the path to the directory for autoloaded WADs/DEHs. +// Creates the directory as necessary. + +static char *autoload_path = NULL; + +static char *GetAutoloadDir(const char *iwadname) +{ + char *result; + + if (autoload_path == NULL) + { + char *prefdir; + prefdir = D_DoomPrefDir(); + autoload_path = M_StringJoin(prefdir, DIR_SEPARATOR_S, "autoload", NULL); + (free)(prefdir); + } + + M_MakeDirectory(autoload_path); + + result = M_StringJoin(autoload_path, DIR_SEPARATOR_S, iwadname, NULL); + M_MakeDirectory(result); + + return result; +} + // // CheckIWAD // @@ -1362,6 +1388,28 @@ static void D_ProcessDehCommandLine(void) // ty 03/09/98 end of do dehacked stuff } +// Load all WAD files from the given directory. + +static void AutoLoadWADs(const char *path) +{ + glob_t *glob; + const char *filename; + + glob = I_StartMultiGlob(path, GLOB_FLAG_NOCASE|GLOB_FLAG_SORTED, + "*.wad", "*.lmp", NULL); + for (;;) + { + filename = I_NextGlob(glob); + if (filename == NULL) + { + break; + } + D_AddFile(filename); + } + + I_EndGlob(glob); +} + // killough 10/98: support preloaded wads static void D_ProcessWadPreincludes(void) @@ -1385,9 +1433,45 @@ static void D_ProcessWadPreincludes(void) printf("\nWarning: could not open %s\n", file); } } + // auto-loading of .wad and .deh files. + { + char *autoload_dir; + + // common auto-loaded files for all Doom flavors + autoload_dir = GetAutoloadDir("doom-all"); + AutoLoadWADs(autoload_dir); + (free)(autoload_dir); + + // auto-loaded files per IWAD + autoload_dir = GetAutoloadDir(M_BaseName(wadfiles[0])); + AutoLoadWADs(autoload_dir); + (free)(autoload_dir); + } } } +// Load all dehacked patches from the given directory. + +static void AutoLoadPatches(const char *path) +{ + const char *filename; + glob_t *glob; + + glob = I_StartMultiGlob(path, GLOB_FLAG_NOCASE|GLOB_FLAG_SORTED, + "*.deh", "*.bex", NULL); + for (;;) + { + filename = I_NextGlob(glob); + if (filename == NULL) + { + break; + } + ProcessDehFile(filename, D_dehout(), 0); + } + + I_EndGlob(glob); +} + // killough 10/98: support preloaded deh/bex files static void D_ProcessDehPreincludes(void) @@ -1417,6 +1501,20 @@ static void D_ProcessDehPreincludes(void) } } } + // auto-loading of .wad and .deh files. + { + char *autoload_dir; + + // common auto-loaded files for all Doom flavors + autoload_dir = GetAutoloadDir("doom-all"); + AutoLoadPatches(autoload_dir); + (free)(autoload_dir); + + // auto-loaded files per IWAD + autoload_dir = GetAutoloadDir(M_BaseName(wadfiles[0])); + AutoLoadPatches(autoload_dir); + (free)(autoload_dir); + } } } diff --git a/Source/d_main.h b/Source/d_main.h index e032eef9..57dc34f0 100644 --- a/Source/d_main.h +++ b/Source/d_main.h @@ -35,7 +35,7 @@ extern char **wadfiles; // killough 11/98 -void D_AddFile(char *file); +void D_AddFile(const char *file); char *D_DoomExeDir(void); // killough 2/16/98: path to executable's dir char *D_DoomExeName(void); // killough 10/98: executable's name diff --git a/Source/i_glob.c b/Source/i_glob.c new file mode 100644 index 00000000..464d9694 --- /dev/null +++ b/Source/i_glob.c @@ -0,0 +1,376 @@ +// +// Copyright(C) 2018 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// File globbing API. This allows the contents of the filesystem +// to be interrogated. +// + +#include +#include +#include + +#include "i_glob.h" +#include "m_misc.h" +#include "m_misc2.h" +#include "config.h" + +#if defined(_MSC_VER) +// For Visual C++, we need to include the win_opendir module. +#include "win_opendir.h" +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#include +#define S_ISDIR(m) (((m)& S_IFMT) == S_IFDIR) +#elif defined(HAVE_DIRENT_H) +#include +#include +#elif defined(__WATCOMC__) +// Watcom has the same API in a different header. +#include +#else +#define NO_DIRENT_IMPLEMENTATION +#endif + +#ifndef NO_DIRENT_IMPLEMENTATION + +// Only the fields d_name and (as an XSI extension) d_ino are specified +// in POSIX.1. Other than Linux, the d_type field is available mainly +// only on BSD systems. The remaining fields are available on many, but +// not all systems. +static boolean IsDirectory(char *dir, struct dirent *de) +{ +#if defined(_DIRENT_HAVE_D_TYPE) + if (de->d_type != DT_UNKNOWN && de->d_type != DT_LNK) + { + return de->d_type == DT_DIR; + } + else +#endif + { + char *filename; + struct stat sb; + int result; + + filename = M_StringJoin(dir, DIR_SEPARATOR_S, de->d_name, NULL); + result = stat(filename, &sb); + (free)(filename); + + if (result != 0) + { + return false; + } + + return S_ISDIR(sb.st_mode); + } +} + +struct glob_s +{ + char **globs; + int num_globs; + int flags; + DIR *dir; + char *directory; + char *last_filename; + // These fields are only used when the GLOB_FLAG_SORTED flag is set: + char **filenames; + int filenames_len; + int next_index; +}; + +static void FreeStringList(char **globs, int num_globs) +{ + int i; + for (i = 0; i < num_globs; ++i) + { + (free)(globs[i]); + } + free(globs); +} + +glob_t *I_StartMultiGlob(const char *directory, int flags, + const char *glob, ...) +{ + char **globs; + int num_globs; + glob_t *result; + va_list args; + + globs = malloc(sizeof(char *)); + if (globs == NULL) + { + return NULL; + } + globs[0] = M_StringDuplicate(glob); + num_globs = 1; + + va_start(args, glob); + for (;;) + { + const char *arg = va_arg(args, const char *); + char **new_globs; + + if (arg == NULL) + { + break; + } + + new_globs = realloc(globs, sizeof(char *) * (num_globs + 1)); + if (new_globs == NULL) + { + FreeStringList(globs, num_globs); + } + globs = new_globs; + globs[num_globs] = M_StringDuplicate(arg); + ++num_globs; + } + va_end(args); + + result = malloc(sizeof(glob_t)); + if (result == NULL) + { + FreeStringList(globs, num_globs); + return NULL; + } + + result->dir = opendir(directory); + if (result->dir == NULL) + { + FreeStringList(globs, num_globs); + free(result); + return NULL; + } + + result->directory = M_StringDuplicate(directory); + result->globs = globs; + result->num_globs = num_globs; + result->flags = flags; + result->last_filename = NULL; + result->filenames = NULL; + result->filenames_len = 0; + result->next_index = -1; + return result; +} + +glob_t *I_StartGlob(const char *directory, const char *glob, int flags) +{ + return I_StartMultiGlob(directory, flags, glob, NULL); +} + +void I_EndGlob(glob_t *glob) +{ + if (glob == NULL) + { + return; + } + + FreeStringList(glob->globs, glob->num_globs); + FreeStringList(glob->filenames, glob->filenames_len); + + (free)(glob->directory); + free(glob->last_filename); + (void) closedir(glob->dir); + free(glob); +} + +static boolean MatchesGlob(const char *name, const char *glob, int flags) +{ + int n, g; + + while (*glob != '\0') + { + n = *name; + g = *glob; + + if ((flags & GLOB_FLAG_NOCASE) != 0) + { + n = tolower(n); + g = tolower(g); + } + + if (g == '*') + { + // To handle *-matching we skip past the * and recurse + // to check each subsequent character in turn. If none + // match then the whole match is a failure. + while (*name != '\0') + { + if (MatchesGlob(name, glob + 1, flags)) + { + return true; + } + ++name; + } + return glob[1] == '\0'; + } + else if (g != '?' && n != g) + { + // For normal characters the name must match the glob, + // but for ? we don't care what the character is. + return false; + } + + ++name; + ++glob; + } + + // Match successful when glob and name end at the same time. + return *name == '\0'; +} + +static boolean MatchesAnyGlob(const char *name, glob_t *glob) +{ + int i; + + for (i = 0; i < glob->num_globs; ++i) + { + if (MatchesGlob(name, glob->globs[i], glob->flags)) + { + return true; + } + } + return false; +} + +static char *NextGlob(glob_t *glob) +{ + struct dirent *de; + + do + { + de = readdir(glob->dir); + if (de == NULL) + { + return NULL; + } + } while (IsDirectory(glob->directory, de) + || !MatchesAnyGlob(de->d_name, glob)); + + // Return the fully-qualified path, not just the bare filename. + return M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL); +} + +static void ReadAllFilenames(glob_t *glob) +{ + char *name; + + glob->filenames = NULL; + glob->filenames_len = 0; + glob->next_index = 0; + + for (;;) + { + name = NextGlob(glob); + if (name == NULL) + { + break; + } + glob->filenames = realloc(glob->filenames, + (glob->filenames_len + 1) * sizeof(char *)); + glob->filenames[glob->filenames_len] = name; + ++glob->filenames_len; + } +} + +static void SortFilenames(char **filenames, int len, int flags) +{ + char *pivot, *tmp; + int i, left_len, cmp; + + if (len <= 1) + { + return; + } + pivot = filenames[len - 1]; + left_len = 0; + for (i = 0; i < len-1; ++i) + { + if ((flags & GLOB_FLAG_NOCASE) != 0) + { + cmp = strcasecmp(filenames[i], pivot); + } + else + { + cmp = strcmp(filenames[i], pivot); + } + + if (cmp < 0) + { + tmp = filenames[i]; + filenames[i] = filenames[left_len]; + filenames[left_len] = tmp; + ++left_len; + } + } + filenames[len - 1] = filenames[left_len]; + filenames[left_len] = pivot; + + SortFilenames(filenames, left_len, flags); + SortFilenames(&filenames[left_len + 1], len - left_len - 1, flags); +} + +const char *I_NextGlob(glob_t *glob) +{ + const char *result; + + if (glob == NULL) + { + return NULL; + } + + // In unsorted mode we just return the filenames as we read + // them back from the system API. + if ((glob->flags & GLOB_FLAG_SORTED) == 0) + { + free(glob->last_filename); + glob->last_filename = NextGlob(glob); + return glob->last_filename; + } + + // In sorted mode we read the whole list of filenames into memory, + // sort them and return them one at a time. + if (glob->next_index < 0) + { + ReadAllFilenames(glob); + SortFilenames(glob->filenames, glob->filenames_len, glob->flags); + } + if (glob->next_index >= glob->filenames_len) + { + return NULL; + } + result = glob->filenames[glob->next_index]; + ++glob->next_index; + return result; +} + +#else /* #ifdef NO_DIRENT_IMPLEMENTATION */ + +#warning No native implementation of file globbing. + +glob_t *I_StartGlob(const char *directory, const char *glob, int flags) +{ + return NULL; +} + +void I_EndGlob(glob_t *glob) +{ +} + +const char *I_NextGlob(glob_t *glob) +{ + return ""; +} + +#endif /* #ifdef NO_DIRENT_IMPLEMENTATION */ + diff --git a/Source/i_glob.h b/Source/i_glob.h new file mode 100644 index 00000000..f976db01 --- /dev/null +++ b/Source/i_glob.h @@ -0,0 +1,44 @@ +// +// Copyright(C) 2018 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System specific file globbing interface. +// + + +#ifndef __I_GLOB__ +#define __I_GLOB__ + +#define GLOB_FLAG_NOCASE 0x01 +#define GLOB_FLAG_SORTED 0x02 + +typedef struct glob_s glob_t; + +// Start reading a list of file paths from the given directory which match +// the given glob pattern. I_EndGlob() must be called on completion. +glob_t *I_StartGlob(const char *directory, const char *glob, int flags); + +// Same as I_StartGlob but multiple glob patterns can be provided. The list +// of patterns must be terminated with NULL. +glob_t *I_StartMultiGlob(const char *directory, int flags, + const char *glob, ...); + +// Finish reading file list. +void I_EndGlob(glob_t *glob); + +// Read the name of the next globbed filename. NULL is returned if there +// are no more found. +const char *I_NextGlob(glob_t *glob); + +#endif + diff --git a/Source/win_opendir.c b/Source/win_opendir.c new file mode 100644 index 00000000..b2f67805 --- /dev/null +++ b/Source/win_opendir.c @@ -0,0 +1,336 @@ +// +// 03/10/2006 James Haley +// +// For this module only: +// This code is public domain. No change sufficient enough to constitute a +// significant or original work has been made, and thus it remains as such. +// +// +// DESCRIPTION: +// +// Implementation of POSIX opendir for Visual C++. +// Derived from the MinGW C Library Extensions Source (released to the +// public domain). As with other Win32 modules, don't include most DOOM +// headers into this or conflicts will occur. +// +// Original Header: +// +// * dirent.c +// * This file has no copyright assigned and is placed in the Public Domain. +// * This file is a part of the mingw-runtime package. +// * No warranty is given; refer to the file DISCLAIMER within the package. +// * +// * Derived from DIRLIB.C by Matt J. Weinstein +// * This note appears in the DIRLIB.H +// * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 +// * +// * Updated by Jeremy Bettis +// * Significantly revised and rewinddir, seekdir and telldir added by Colin +// * Peters +// + +#ifndef _MSC_VER +#error i_opndir.c is for Microsoft Visual C++ only +#endif + +#include +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include /* for GetFileAttributes */ + +#include +#define SUFFIX _T("*") +#define SLASH _T("\\") + +#include "win_opendir.h" + +// +// opendir +// +// Returns a pointer to a DIR structure appropriately filled in to begin +// searching a directory. +// +DIR *opendir(const _TCHAR *szPath) +{ + DIR *nd; + unsigned int rc; + _TCHAR szFullPath[MAX_PATH]; + + errno = 0; + + if(!szPath) + { + errno = EFAULT; + return (DIR *)0; + } + + if(szPath[0] == _T('\0')) + { + errno = ENOTDIR; + return (DIR *)0; + } + + /* Attempt to determine if the given path really is a directory. */ + rc = GetFileAttributes(szPath); + if(rc == (unsigned int)-1) + { + /* call GetLastError for more error info */ + errno = ENOENT; + return (DIR *)0; + } + if(!(rc & FILE_ATTRIBUTE_DIRECTORY)) + { + /* Error, entry exists but not a directory. */ + errno = ENOTDIR; + return (DIR *)0; + } + + /* Make an absolute pathname. */ + _tfullpath(szFullPath, szPath, MAX_PATH); + + /* Allocate enough space to store DIR structure and the complete + * directory path given. */ + nd = (DIR *)(malloc(sizeof(DIR) + (_tcslen(szFullPath) + + _tcslen(SLASH) + + _tcslen(SUFFIX) + 1) + * sizeof(_TCHAR))); + + if(!nd) + { + /* Error, out of memory. */ + errno = ENOMEM; + return (DIR *)0; + } + + /* Create the search expression. */ + _tcscpy(nd->dd_name, szFullPath); + + /* Add on a slash if the path does not end with one. */ + if(nd->dd_name[0] != _T('\0') + && _tcsrchr(nd->dd_name, _T('/')) != nd->dd_name + + _tcslen(nd->dd_name) - 1 + && _tcsrchr(nd->dd_name, _T('\\')) != nd->dd_name + + _tcslen(nd->dd_name) - 1) + { + _tcscat(nd->dd_name, SLASH); + } + + /* Add on the search pattern */ + _tcscat(nd->dd_name, SUFFIX); + + /* Initialize handle to -1 so that a premature closedir doesn't try + * to call _findclose on it. */ + nd->dd_handle = -1; + + /* Initialize the status. */ + nd->dd_stat = 0; + + /* Initialize the dirent structure. ino and reclen are invalid under + * Win32, and name simply points at the appropriate part of the + * findfirst_t structure. */ + nd->dd_dir.d_ino = 0; + nd->dd_dir.d_reclen = 0; + nd->dd_dir.d_namlen = 0; + memset(nd->dd_dir.d_name, 0, FILENAME_MAX); + + return nd; +} + +// +// readdir +// +// Return a pointer to a dirent structure filled with the information on the +// next entry in the directory. +// +struct dirent *readdir(DIR *dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if(!dirp) + { + errno = EFAULT; + return (struct dirent *)0; + } + + if (dirp->dd_stat < 0) + { + /* We have already returned all files in the directory + * (or the structure has an invalid dd_stat). */ + return (struct dirent *)0; + } + else if (dirp->dd_stat == 0) + { + /* We haven't started the search yet. */ + /* Start the search */ + dirp->dd_handle = _tfindfirst(dirp->dd_name, &(dirp->dd_dta)); + + if(dirp->dd_handle == -1) + { + /* Whoops! Seems there are no files in that + * directory. */ + dirp->dd_stat = -1; + } + else + { + dirp->dd_stat = 1; + } + } + else + { + /* Get the next search entry. */ + if(_tfindnext(dirp->dd_handle, &(dirp->dd_dta))) + { + /* We are off the end or otherwise error. + _findnext sets errno to ENOENT if no more file + Undo this. */ + DWORD winerr = GetLastError(); + if(winerr == ERROR_NO_MORE_FILES) + errno = 0; + _findclose(dirp->dd_handle); + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Update the status to indicate the correct + * number. */ + dirp->dd_stat++; + } + } + + if (dirp->dd_stat > 0) + { + /* Successfully got an entry. Everything about the file is + * already appropriately filled in except the length of the + * file name. */ + dirp->dd_dir.d_namlen = _tcslen(dirp->dd_dta.name); + _tcscpy(dirp->dd_dir.d_name, dirp->dd_dta.name); + return &dirp->dd_dir; + } + + return (struct dirent *)0; +} + + +// +// closedir +// +// Frees up resources allocated by opendir. +// +int closedir(DIR *dirp) +{ + int rc; + + errno = 0; + rc = 0; + + if(!dirp) + { + errno = EFAULT; + return -1; + } + + if(dirp->dd_handle != -1) + { + rc = _findclose(dirp->dd_handle); + } + + /* Delete the dir structure. */ + free(dirp); + + return rc; +} + +// +// rewinddir +// +// Return to the beginning of the directory "stream". We simply call findclose +// and then reset things like an opendir. +// +void rewinddir(DIR * dirp) +{ + errno = 0; + + if(!dirp) + { + errno = EFAULT; + return; + } + + if(dirp->dd_handle != -1) + { + _findclose(dirp->dd_handle); + } + + dirp->dd_handle = -1; + dirp->dd_stat = 0; +} + +// +// telldir +// +// Returns the "position" in the "directory stream" which can be used with +// seekdir to go back to an old entry. We simply return the value in stat. +// +long telldir(DIR *dirp) +{ + errno = 0; + + if(!dirp) + { + errno = EFAULT; + return -1; + } + return dirp->dd_stat; +} + +// +// seekdir +// +// Seek to an entry previously returned by telldir. We rewind the directory +// and call readdir repeatedly until either dd_stat is the position number +// or -1 (off the end). This is not perfect, in that the directory may +// have changed while we weren't looking. But that is probably the case with +// any such system. +// +void seekdir(DIR *dirp, long lPos) +{ + errno = 0; + + if(!dirp) + { + errno = EFAULT; + return; + } + + if(lPos < -1) + { + /* Seeking to an invalid position. */ + errno = EINVAL; + return; + } + else if(lPos == -1) + { + /* Seek past end. */ + if(dirp->dd_handle != -1) + { + _findclose(dirp->dd_handle); + } + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Rewind and read forward to the appropriate index. */ + rewinddir(dirp); + + while((dirp->dd_stat < lPos) && readdir(dirp)) + ; /* do-nothing loop */ + } +} + +// EOF + diff --git a/Source/win_opendir.h b/Source/win_opendir.h new file mode 100644 index 00000000..c1844e11 --- /dev/null +++ b/Source/win_opendir.h @@ -0,0 +1,73 @@ +// +// 03/10/2006 James Haley +// +// For this module only: +// This code is public domain. No change sufficient enough to constitute a +// significant or original work has been made, and thus it remains as such. +// +// +// DESCRIPTION: +// +// Implementation of POSIX opendir for Visual C++. +// Derived from the MinGW C Library Extensions Source (released to the +// public domain). +// + +#ifndef I_OPNDIR_H__ +#define I_OPNDIR_H__ + +#include + +#ifndef FILENAME_MAX +#define FILENAME_MAX 260 +#endif + +struct dirent +{ + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char d_name[FILENAME_MAX]; /* File name. */ +}; + +/* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + * dd_stat field is now int (was short in older versions). + */ +typedef struct +{ + /* disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + intptr_t dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; +} DIR; + +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int closedir(DIR *); +void rewinddir(DIR *); +long telldir(DIR *); +void seekdir(DIR *, long); + +#endif + +// EOF + diff --git a/config.h.in b/config.h.in index f26a65cb..6b90f7c0 100644 --- a/config.h.in +++ b/config.h.in @@ -2,3 +2,4 @@ #cmakedefine PROJECT_STRING "@PROJECT_STRING@" #cmakedefine PROJECT_TARNAME "@PROJECT_TARNAME@" #cmakedefine m_FOUND +#cmakedefine HAVE_DIRENT_H