From 5201de4ff2e4f236c5cf2be064aa506e376b80cb Mon Sep 17 00:00:00 2001 From: James Haley Date: Sun, 30 Jan 2011 04:10:32 +0000 Subject: Add win_opendir.c module for MSVC++ builds which contains public domain implementation of POSIX opendir/readdir/closedir API derived from the MinGW libc extensions source. Will be needed for hub save maintenance. Subversion-branch: /branches/strife-branch Subversion-revision: 2241 --- msvc/strife.vcproj | 8 ++ msvc/win_opendir.c | 340 +++++++++++++++++++++++++++++++++++++++++++++++++++ msvc/win_opendir.h | 77 ++++++++++++ src/strife/m_saves.c | 10 ++ 4 files changed, 435 insertions(+) create mode 100644 msvc/win_opendir.c create mode 100644 msvc/win_opendir.h diff --git a/msvc/strife.vcproj b/msvc/strife.vcproj index 2caf71a1..0890b2dd 100644 --- a/msvc/strife.vcproj +++ b/msvc/strife.vcproj @@ -389,6 +389,10 @@ RelativePath="..\src\w_wad.h" > + + @@ -805,6 +809,10 @@ RelativePath="..\src\w_wad.c" > + + diff --git a/msvc/win_opendir.c b/msvc/win_opendir.c new file mode 100644 index 00000000..c37e232d --- /dev/null +++ b/msvc/win_opendir.c @@ -0,0 +1,340 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// 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/msvc/win_opendir.h b/msvc/win_opendir.h new file mode 100644 index 00000000..afa6aa12 --- /dev/null +++ b/msvc/win_opendir.h @@ -0,0 +1,77 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// 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 */ + long 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/src/strife/m_saves.c b/src/strife/m_saves.c index bec0fede..f845598e 100644 --- a/src/strife/m_saves.c +++ b/src/strife/m_saves.c @@ -28,6 +28,16 @@ // //----------------------------------------------------------------------------- +// For GNU C and POSIX targets, dirent.h should be available. Otherwise, for +// Visual C++, we need to include the win_opendir module. +#if defined(_MSC_VER) +#include +#elif defined(__GNUC__) || defined(POSIX) +#include +#else +#error Need an include for dirent.h! +#endif + #include "z_zone.h" #include "i_system.h" #include "d_player.h" -- cgit v1.2.3