win32.c
changeset 4218 384c7451e3bb
parent 4210 2c1a58c727ed
child 4219 4211284f29ec
equal deleted inserted replaced
4217:58e6b9449c80 4218:384c7451e3bb
    16 #include <wininet.h>
    16 #include <wininet.h>
    17 #include <io.h>
    17 #include <io.h>
    18 #include <fcntl.h>
    18 #include <fcntl.h>
    19 #include "variables.h"
    19 #include "variables.h"
    20 #include "win32.h"
    20 #include "win32.h"
       
    21 #include "fios.h" // opendir/readdir/closedir
    21 #include <ctype.h>
    22 #include <ctype.h>
       
    23 #include <errno.h>
       
    24 #include <sys/types.h>
       
    25 #include <sys/stat.h>
    22 
    26 
    23 static bool _has_console;
    27 static bool _has_console;
    24 
    28 
    25 #if defined(__MINGW32__) || defined(__CYGWIN__)
    29 #if defined(__MINGW32__) || defined(__CYGWIN__)
    26 	#define __TIMESTAMP__   __DATE__ __TIME__
    30 	#define __TIMESTAMP__   __DATE__ __TIME__
   600 
   604 
   601 	SetUnhandledExceptionFilter(ExceptionHandler);
   605 	SetUnhandledExceptionFilter(ExceptionHandler);
   602 }
   606 }
   603 #endif /* _MSC_VER */
   607 #endif /* _MSC_VER */
   604 
   608 
       
   609 /* Code below for windows version of opendir/readdir/closedir copied and
       
   610  * modified from Jan Wassenberg's GPL implementation posted over at
       
   611  * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1&#2398903 */
       
   612 
       
   613 /* suballocator - satisfies most requests with a reusable static instance.
       
   614  * this avoids hundreds of alloc/free which would fragment the heap.
       
   615  * To guarantee thread-safety, we fall back to malloc if the instance is
       
   616  * already in use (it's important to avoid suprises since this is such a
       
   617  * low-level routine). */
       
   618 static DIR _global_dir;
       
   619 static bool _global_dir_is_in_use = false;
       
   620 
       
   621 static inline DIR *dir_calloc(void)
       
   622 {
       
   623 	DIR *d;
       
   624 
       
   625 	if (_global_dir_is_in_use) {
       
   626 		d = calloc(1, sizeof(DIR));
       
   627 	} else {
       
   628 		_global_dir_is_in_use = true;
       
   629 		d = &_global_dir;
       
   630 		memset(d, 0, sizeof(DIR));
       
   631 	}
       
   632 	return d;
       
   633 }
       
   634 
       
   635 static inline void dir_free(DIR *d)
       
   636 {
       
   637 	if (d == &_global_dir) {
       
   638 		_global_dir_is_in_use = false;
       
   639 	} else {
       
   640 		free(d);
       
   641 	}
       
   642 }
       
   643 
       
   644 DIR *opendir(const char *path)
       
   645 {
       
   646 	char search_path[MAX_PATH];
       
   647 	DIR *d;
       
   648 	UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box
       
   649 	DWORD fa = GetFileAttributes(path);
       
   650 
       
   651 	/* not a directory or path not found */
       
   652 	if (fa == INVALID_FILE_ATTRIBUTES || (fa & FILE_ATTRIBUTE_DIRECTORY) == 0) {
       
   653 		errno = ENOENT;
       
   654 		return NULL;
       
   655 	}
       
   656 
       
   657 	d = dir_calloc();
       
   658 	if (d == NULL) {
       
   659 		errno = ENOMEM;
       
   660 		return NULL;
       
   661 	}
       
   662 
       
   663 	/* build search path for FindFirstFile */
       
   664 	snprintf(search_path, lengthof(search_path), "%s" PATHSEP "*", path);
       
   665 	d->hFind = FindFirstFile(search_path, &d->fd);
       
   666 	SetErrorMode(sem); // restore previous setting
       
   667 
       
   668 	if (d->hFind == INVALID_HANDLE_VALUE) {
       
   669 		/* not an error - the directory is just empty */
       
   670 		if (GetLastError() == ERROR_NO_MORE_FILES) return NULL;
       
   671 		dir_free(d);
       
   672 	}
       
   673 
       
   674 	d->ent.dir = d;
       
   675 	d->at_first_entry = true;
       
   676 	return d;
       
   677 }
       
   678 
       
   679 struct dirent *readdir(DIR *d)
       
   680 {
       
   681 	DWORD prev_err = GetLastError(); // avoid polluting last error
       
   682 
       
   683 	if (d->at_first_entry) {
       
   684 		/* the directory was empty when opened */
       
   685 		if (d->hFind == INVALID_HANDLE_VALUE) return NULL;
       
   686 		d->at_first_entry = false;
       
   687 		goto already_have_file;
       
   688 	}
       
   689 
       
   690 	/* Go until the end of directory or until a valid entry was found */
       
   691 	if (!FindNextFile(d->hFind, &d->fd)) { // determine cause and bail
       
   692 		if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
       
   693 		return NULL;
       
   694 	}
       
   695 
       
   696 already_have_file:
       
   697 	/* This entry has passed all checks; return information about it.
       
   698 	 * (note: d_name is a pointer; see struct dirent definition) */
       
   699 	d->ent.d_name = d->fd.cFileName;
       
   700 	return &d->ent;
       
   701 }
       
   702 
       
   703 int closedir(DIR *d)
       
   704 {
       
   705 	FindClose(d->hFind);
       
   706 	dir_free(d);
       
   707 	return 0;
       
   708 }
       
   709 
   605 static char *_fios_path;
   710 static char *_fios_path;
   606 static char *_fios_save_path;
   711 static char *_fios_save_path;
   607 static char *_fios_scn_path;
   712 static char *_fios_scn_path;
   608 static FiosItem *_fios_items;
   713 static FiosItem *_fios_items;
   609 static int _fios_count, _fios_alloc;
   714 static int _fios_count, _fios_alloc;