783 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			783 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include <hawk-dir.h>
 | |
| #include "hawk-prv.h"
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| #	include <windows.h>
 | |
| #elif defined(__OS2__)
 | |
| #	define INCL_DOSFILEMGR
 | |
| #	define INCL_ERRORS
 | |
| #	include <os2.h>
 | |
| #elif defined(__DOS__)
 | |
| #	include <dos.h>
 | |
| #	include <errno.h>
 | |
| #else
 | |
| #	include "syscall.h"
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #define STATUS_OPENED    (1 << 0)
 | |
| #define STATUS_DONE      (1 << 1)
 | |
| #define STATUS_DONE_ERR  (1 << 2)
 | |
| #define STATUS_POPHEAP   (1 << 3)
 | |
| #define STATUS_SORT_ERR  (1 << 4)
 | |
| 
 | |
| #define IS_CURDIR(x) ((x)[0] == '.' && (x)[1] == '\0')
 | |
| #define IS_PREVDIR(x) ((x)[0] == '.' && (x)[1] == '.' && (x)[2] == '\0')
 | |
| 
 | |
| 
 | |
| struct hawk_dir_t
 | |
| {
 | |
| 	hawk_gem_t* gem;
 | |
| 	int flags;
 | |
| 
 | |
| 	hawk_uecs_t wbuf;
 | |
| 	hawk_becs_t mbuf;
 | |
| 
 | |
| 	hawk_arr_t* stab;
 | |
| 	int status;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	HANDLE h;
 | |
| 	WIN32_FIND_DATA wfd;
 | |
| #elif defined(__OS2__)
 | |
| 	HDIR h;
 | |
| 	#if defined(FIL_STANDARDL)
 | |
| 	FILEFINDBUF3L ffb;
 | |
| 	#else
 | |
| 	FILEFINDBUF3 ffb;
 | |
| 	#endif
 | |
| 	ULONG count;
 | |
| #elif defined(__DOS__)
 | |
| 	struct find_t f;
 | |
| #else
 | |
| 	HAWK_DIR* dp;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| int hawk_dir_init (hawk_dir_t* dir, hawk_gem_t* gem, const hawk_ooch_t* path, int flags);
 | |
| void hawk_dir_fini (hawk_dir_t* dir);
 | |
| 
 | |
| static void close_dir_safely (hawk_dir_t* dir);
 | |
| static int reset_to_path (hawk_dir_t* dir, const hawk_ooch_t* path);
 | |
| static int read_ahead_and_sort (hawk_dir_t* dir, const hawk_ooch_t* path);
 | |
| 
 | |
| hawk_dir_t* hawk_dir_open (hawk_gem_t* gem, hawk_oow_t xtnsize, const hawk_ooch_t* path, int flags)
 | |
| {
 | |
| 	hawk_dir_t* dir;
 | |
| 
 | |
| 	dir = hawk_gem_allocmem(gem, HAWK_SIZEOF(*dir) + xtnsize);
 | |
| 	if (dir)
 | |
| 	{
 | |
| 		if (hawk_dir_init(dir, gem, path, flags) <= -1)
 | |
| 		{
 | |
| 			hawk_gem_freemem (gem, dir);
 | |
| 			dir = HAWK_NULL;
 | |
| 		}
 | |
| 		else HAWK_MEMSET (dir + 1, 0, xtnsize);
 | |
| 	}
 | |
| 
 | |
| 	return dir;
 | |
| }
 | |
| 
 | |
| void hawk_dir_close (hawk_dir_t* dir)
 | |
| {
 | |
| 	hawk_dir_fini (dir);
 | |
| 	hawk_gem_freemem (dir->gem, dir);
 | |
| }
 | |
| 
 | |
| void* hawk_dir_getxtn (hawk_dir_t* dir)
 | |
| {
 | |
| 	return (void*)(dir + 1);
 | |
| }
 | |
| 
 | |
| static int compare_dirent (hawk_arr_t* arr, const void* dptr1, hawk_oow_t dlen1, const void* dptr2, hawk_oow_t dlen2)
 | |
| {
 | |
| 	int n = HAWK_MEMCMP(dptr1, dptr2, ((dlen1 < dlen2)? dlen1: dlen2));
 | |
| 	if (n == 0 && dlen1 != dlen2) n = (dlen1 > dlen2)? 1: -1;
 | |
| 	return -n;
 | |
| }
 | |
| 
 | |
| int hawk_dir_init (hawk_dir_t* dir, hawk_gem_t* gem, const hawk_ooch_t* path, int flags)
 | |
| {
 | |
| 	static hawk_arr_style_t stab_style =
 | |
| 	{
 | |
| 		HAWK_ARR_COPIER_INLINE,
 | |
| 		HAWK_ARR_FREEER_DEFAULT,
 | |
| 		compare_dirent,
 | |
| 		HAWK_ARR_KEEPER_DEFAULT,
 | |
| 		HAWK_ARR_SIZER_DEFAULT
 | |
| 	};
 | |
| 
 | |
| 	int n;
 | |
| 	int path_flags;
 | |
| 
 | |
| 	path_flags = flags & (HAWK_DIR_BPATH | HAWK_DIR_UPATH);
 | |
| 	if (path_flags == (HAWK_DIR_BPATH | HAWK_DIR_UPATH) || path_flags == 0)
 | |
| 	{
 | |
| 		/* if both are set or none are set, force it to the default */
 | |
| 	#if defined(HAWK_OOCH_IS_BCH)
 | |
| 		flags |= HAWK_DIR_BPATH;
 | |
| 		flags &= ~HAWK_DIR_UPATH;
 | |
| 	#else
 | |
| 		flags |= HAWK_DIR_UPATH;
 | |
| 		flags &= ~HAWK_DIR_BPATH;
 | |
| 	#endif
 | |
| 	}
 | |
| 
 | |
| 	HAWK_MEMSET (dir, 0, HAWK_SIZEOF(*dir));
 | |
| 
 | |
| 	dir->gem = gem;
 | |
| 	dir->flags = flags;
 | |
| 
 | |
| 	if (hawk_uecs_init(&dir->wbuf, gem, 256) <= -1) goto oops_0;
 | |
| 	if (hawk_becs_init(&dir->mbuf, gem, 256) <= -1) goto oops_1;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	dir->h = INVALID_HANDLE_VALUE;
 | |
| #endif
 | |
| 
 | |
| 	n = reset_to_path(dir, path);
 | |
| 	if (n <= -1) goto oops_2;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_SORT)
 | |
| 	{
 | |
| 		dir->stab = hawk_arr_open(gem, 0, 128);
 | |
| 		if (HAWK_UNLIKELY(!dir->stab)) goto oops_3;
 | |
| 
 | |
| 		/*hawk_arr_setscale (dir->stab, 1);*/
 | |
| 		hawk_arr_setstyle (dir->stab, &stab_style);
 | |
| 
 | |
| 		if (read_ahead_and_sort(dir, path) <= -1) goto oops_4;
 | |
| 	}
 | |
| 
 | |
| 	return n;
 | |
| 
 | |
| oops_4:
 | |
| 	hawk_arr_close (dir->stab);
 | |
| oops_3:
 | |
| 	close_dir_safely (dir);
 | |
| oops_2:
 | |
| 	hawk_becs_fini (&dir->mbuf);
 | |
| oops_1:
 | |
| 	hawk_uecs_fini (&dir->wbuf);
 | |
| oops_0:
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| static void close_dir_safely (hawk_dir_t* dir)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 	if (dir->h != INVALID_HANDLE_VALUE)
 | |
| 	{
 | |
| 		FindClose (dir->h);
 | |
| 		dir->h = INVALID_HANDLE_VALUE;
 | |
| 	}
 | |
| #elif defined(__OS2__)
 | |
| 	if (dir->status & STATUS_OPENED)
 | |
| 	{
 | |
| 		DosFindClose (dir->h);
 | |
| 		dir->status &= ~STATUS_OPENED;
 | |
| 	}
 | |
| #elif defined(__DOS__)
 | |
| 	if (dir->status & STATUS_OPENED)
 | |
| 	{
 | |
| 		_dos_findclose (&dir->f);
 | |
| 		dir->status &= ~STATUS_OPENED;
 | |
| 	}
 | |
| #else
 | |
| 	if (dir->dp)
 | |
| 	{
 | |
| 		HAWK_CLOSEDIR (dir->dp);
 | |
| 		dir->dp = HAWK_NULL;
 | |
| 	}
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void hawk_dir_fini (hawk_dir_t* dir)
 | |
| {
 | |
| 	close_dir_safely (dir);
 | |
| 
 | |
| 	hawk_becs_fini (&dir->mbuf);
 | |
| 	hawk_uecs_fini (&dir->wbuf);
 | |
| 
 | |
| 	if (dir->stab) hawk_arr_close (dir->stab);
 | |
| }
 | |
| 
 | |
| static hawk_bch_t* wcs_to_mbuf (hawk_dir_t* dir, const hawk_uch_t* wcs, hawk_becs_t* mbuf)
 | |
| {
 | |
| 	hawk_becs_clear (mbuf);
 | |
| 	if (hawk_becs_ncatuchars(mbuf, wcs, hawk_count_ucstr(wcs), dir->gem->cmgr) == (hawk_oow_t)-1) return HAWK_NULL;
 | |
| 	return HAWK_BECS_PTR(mbuf);
 | |
| }
 | |
| 
 | |
| static hawk_uch_t* mbs_to_wbuf (hawk_dir_t* dir, const hawk_bch_t* mbs, hawk_uecs_t* wbuf)
 | |
| {
 | |
| 	/* convert all regardless of encoding failure */
 | |
| 	hawk_uecs_clear (wbuf);
 | |
| 	if (hawk_uecs_ncatbchars(wbuf, mbs, hawk_count_bcstr(mbs), dir->gem->cmgr, 1) == (hawk_oow_t)-1) return HAWK_NULL;
 | |
| 	return HAWK_UECS_PTR(wbuf);
 | |
| }
 | |
| 
 | |
| static hawk_uch_t* wcs_to_wbuf (hawk_dir_t* dir, const hawk_uch_t* wcs, hawk_uecs_t* wbuf)
 | |
| {
 | |
| 	if (hawk_uecs_cpy(&dir->wbuf, wcs) == (hawk_oow_t)-1) return HAWK_NULL;
 | |
| 	return HAWK_UECS_PTR(wbuf);
 | |
| }
 | |
| 
 | |
| static hawk_bch_t* mbs_to_mbuf (hawk_dir_t* dir, const hawk_bch_t* mbs, hawk_becs_t* mbuf)
 | |
| {
 | |
| 	if (hawk_becs_cpy(&dir->mbuf, mbs) == (hawk_oow_t)-1) return HAWK_NULL;
 | |
| 	return HAWK_BECS_PTR(mbuf);
 | |
| }
 | |
| 
 | |
| #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | |
| static hawk_bch_t* make_mbsdos_path (hawk_dir_t* dir, const hawk_bch_t* mpath)
 | |
| {
 | |
| 	if (mpath[0] == '\0')
 | |
| 	{
 | |
| 		if (hawk_becs_cpy(&dir->mbuf, "*.*") == (hawk_oow_t)-1) return HAWK_NULL;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		hawk_oow_t len;
 | |
| 		if ((len = hawk_becs_cpy(&dir->mbuf, mpath)) == (hawk_oow_t)-1 ||
 | |
| 		    (!HAWK_ISPATHMBSEP(mpath[len - 1]) &&
 | |
| 		     !hawk_ismbsdrivecurpath(mpath) &&
 | |
| 		     hawk_becs_ccat(&dir->mbuf, '\\') == (hawk_oow_t)-1) ||
 | |
| 		    hawk_becs_cat(&dir->mbuf, "*.*") == (hawk_oow_t)-1) return HAWK_NULL;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_BECS_PTR(&dir->mbuf);
 | |
| }
 | |
| 
 | |
| static hawk_uch_t* make_wcsdos_path (hawk_dir_t* dir, const hawk_uch_t* wpath)
 | |
| {
 | |
| 	if (wpath[0] == HAWK_UT('\0'))
 | |
| 	{
 | |
| 		if (hawk_uecs_cpy (&dir->wbuf, HAWK_UT("*.*")) == (hawk_oow_t)-1) return HAWK_NULL;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		hawk_oow_t len;
 | |
| 		if ((len = hawk_uecs_cpy (&dir->wbuf, wpath)) == (hawk_oow_t)-1 ||
 | |
| 		    (!HAWK_ISPATHWCSEP(wpath[len - 1]) &&
 | |
| 		     !hawk_iswcsdrivecurpath(wpath) &&
 | |
| 		     hawk_uecs_ccat (&dir->wbuf, HAWK_UT('\\')) == (hawk_oow_t)-1) ||
 | |
| 		    hawk_uecs_cat (&dir->wbuf, HAWK_UT("*.*")) == (hawk_oow_t)-1) return HAWK_NULL;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_UECS_PTR(&dir->wbuf);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static int reset_to_path (hawk_dir_t* dir, const hawk_ooch_t* path)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 	const hawk_ooch_t* tptr;
 | |
| 	HANDLE dh;
 | |
| 	WIN32_FIND_DATA wfd;
 | |
| 
 | |
| 	dir->status &= ~STATUS_DONE;
 | |
| 	dir->status &= ~STATUS_DONE_ERR;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_BPATH)
 | |
| 	{
 | |
| 		hawk_bch_t* mptr;
 | |
| 
 | |
| 		mptr = make_mbsdos_path(dir, (const hawk_bch_t*)path);
 | |
| 		if (mptr == HAWK_NULL) return -1;
 | |
| 
 | |
| 	#if defined(HAWK_OOCH_IS_BCH)
 | |
| 		tptr = mptr;
 | |
| 	#else
 | |
| 		tptr = mbs_to_wbuf (dir, mptr, &dir->wbuf);
 | |
| 	#endif
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		hawk_uch_t* wptr;
 | |
| 		HAWK_ASSERT (dir->flags & HAWK_DIR_UPATH);
 | |
| 
 | |
| 		wptr = make_wcsdos_path(dir, (const hawk_uch_t*)path);
 | |
| 		if (wptr == HAWK_NULL) return -1;
 | |
| 
 | |
| 	#if defined(HAWK_OOCH_IS_BCH)
 | |
| 		tptr = wcs_to_mbuf(dir, wptr, &dir->mbuf);
 | |
| 	#else
 | |
| 		tptr = wptr;
 | |
| 	#endif
 | |
| 	}
 | |
| 	if (tptr == HAWK_NULL) return -1;
 | |
| 
 | |
| 	dh = FindFirstFile(tptr, &wfd);
 | |
| 	if (dh == INVALID_HANDLE_VALUE)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	close_dir_safely (dir);
 | |
| 
 | |
| 	dir->h = dh;
 | |
| 	dir->wfd = wfd;
 | |
| 	return 0;
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| 
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 	APIRET rc;
 | |
| 	const hawk_bch_t* mptr;
 | |
| 	HDIR h = HDIR_CREATE;
 | |
| 	#if defined(FIL_STANDARDL)
 | |
| 	FILEFINDBUF3L ffb = { 0 };
 | |
| 	#else
 | |
| 	FILEFINDBUF3 ffb = { 0 };
 | |
| 	#endif
 | |
| 	ULONG count = 1;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_BPATH)
 | |
| 	{
 | |
| 		mptr = make_mbsdos_path (dir, (const hawk_bch_t*)path);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		hawk_uch_t* wptr;
 | |
| 		HAWK_ASSERT (dir->flags & HAWK_DIR_UPATH);
 | |
| 
 | |
| 		wptr = make_wcsdos_path(dir, (const hawk_uch_t*)path);
 | |
| 		if (wptr == HAWK_NULL) return -1;
 | |
| 		mptr = wcs_to_mbuf(dir, wptr, &dir->mbuf);
 | |
| 	}
 | |
| 	if (mptr == HAWK_NULL) return -1;
 | |
| 
 | |
| 	rc = DosFindFirst (
 | |
| 		mptr,
 | |
| 		&h,
 | |
| 		FILE_DIRECTORY | FILE_READONLY,
 | |
| 		&ffb,
 | |
| 		HAWK_SIZEOF(dir->ffb),
 | |
| 		&count,
 | |
| 	#if defined(FIL_STANDARDL)
 | |
| 		FIL_STANDARDL
 | |
| 	#else
 | |
| 		FIL_STANDARD
 | |
| 	#endif
 | |
| 	);
 | |
| 
 | |
| 	if (rc != NO_ERROR)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(rc));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	close_dir_safely (dir);
 | |
| 
 | |
| 	dir->h = h;
 | |
| 	dir->ffb = ffb;
 | |
| 	dir->count = count;
 | |
| 	dir->status |= STATUS_OPENED;
 | |
| 	return 0;
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 	unsigned int rc;
 | |
| 	const hawk_bch_t* mptr;
 | |
| 	struct find_t f;
 | |
| 
 | |
| 	dir->status &= ~STATUS_DONE;
 | |
| 	dir->status &= ~STATUS_DONE_ERR;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_BPATH)
 | |
| 	{
 | |
| 		mptr = make_mbsdos_path(dir, (const hawk_bch_t*)path);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		hawk_uch_t* wptr;
 | |
| 
 | |
| 		HAWK_ASSERT (dir->flags & HAWK_DIR_UPATH);
 | |
| 
 | |
| 		wptr = make_wcsdos_path(dir, (const hawk_uch_t*)path);
 | |
| 		if (wptr == HAWK_NULL) return -1;
 | |
| 		mptr = wcs_to_mbuf(dir, wptr, &dir->mbuf);
 | |
| 	}
 | |
| 	if (mptr == HAWK_NULL) return -1;
 | |
| 
 | |
| 	rc = _dos_findfirst(mptr, _A_NORMAL | _A_SUBDIR, &f);
 | |
| 	if (rc != 0)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	close_dir_safely (dir);
 | |
| 
 | |
| 	dir->f = f;
 | |
| 	dir->status |= STATUS_OPENED;
 | |
| 	return 0;
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 
 | |
| #else
 | |
| 	DIR* dp;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_BPATH)
 | |
| 	{
 | |
| 		const hawk_bch_t* mpath = (const hawk_bch_t*)path;
 | |
| 		dp = HAWK_OPENDIR(mpath[0] == '\0'? ".": mpath);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		const hawk_uch_t* wpath;
 | |
| 		/*HAWK_ASSERT (dir->flags & HAWK_DIR_UPATH);*/
 | |
| 
 | |
| 		wpath = (const hawk_uch_t*)path;
 | |
| 		if (wpath[0] == '\0')
 | |
| 		{
 | |
| 			dp = HAWK_OPENDIR(".");
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			hawk_bch_t* mptr;
 | |
| 
 | |
| 			mptr = wcs_to_mbuf(dir, wpath, &dir->mbuf);
 | |
| 			if (mptr == HAWK_NULL) return -1;
 | |
| 
 | |
| 			dp = HAWK_OPENDIR(mptr);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (dp == HAWK_NULL)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	close_dir_safely (dir);
 | |
| 
 | |
| 	dir->dp = dp;
 | |
| 	return 0;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| int hawk_dir_reset (hawk_dir_t* dir, const hawk_ooch_t* path)
 | |
| {
 | |
| 	if (reset_to_path(dir, path) <= -1) return -1;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_SORT)
 | |
| 	{
 | |
| 		hawk_arr_clear (dir->stab);
 | |
| 		if (read_ahead_and_sort(dir, path) <= -1)
 | |
| 		{
 | |
| 			dir->status |= STATUS_SORT_ERR;
 | |
| 			return -1;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			dir->status &= ~STATUS_SORT_ERR;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int read_dir_to_buf (hawk_dir_t* dir, void** name)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 	if (dir->status & STATUS_DONE) return (dir->status & STATUS_DONE_ERR)? -1: 0;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_SKIPSPCDIR)
 | |
| 	{
 | |
| 		/* skip . and .. */
 | |
| 		while (IS_CURDIR(dir->wfd.cFileName) || IS_PREVDIR(dir->wfd.cFileName))
 | |
| 		{
 | |
| 			if (FindNextFile(dir->h, &dir->wfd) == FALSE)
 | |
| 			{
 | |
| 				DWORD x = GetLastError();
 | |
| 				if (x == ERROR_NO_MORE_FILES)
 | |
| 				{
 | |
| 					dir->status |= STATUS_DONE;
 | |
| 					return 0;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(x));
 | |
| 					dir->status |= STATUS_DONE;
 | |
| 					dir->status |= STATUS_DONE_ERR;
 | |
| 					return -1;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_BPATH)
 | |
| 	{
 | |
| 	#if defined(HAWK_OOCH_IS_BCH)
 | |
| 		if (mbs_to_mbuf(dir, dir->wfd.cFileName, &dir->mbuf) == HAWK_NULL) return -1;
 | |
| 	#else
 | |
| 		if (wcs_to_mbuf(dir, dir->wfd.cFileName, &dir->mbuf) == HAWK_NULL) return -1;
 | |
| 	#endif
 | |
| 		*name = HAWK_BECS_PTR(&dir->mbuf);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		HAWK_ASSERT (dir->flags & HAWK_DIR_UPATH);
 | |
| 	#if defined(HAWK_OOCH_IS_BCH)
 | |
| 		if (mbs_to_wbuf(dir, dir->wfd.cFileName, &dir->wbuf) == HAWK_NULL) return -1;
 | |
| 	#else
 | |
| 		if (wcs_to_wbuf(dir, dir->wfd.cFileName, &dir->wbuf) == HAWK_NULL) return -1;
 | |
| 	#endif
 | |
| 		*name = HAWK_UECS_PTR(&dir->wbuf);
 | |
| 	}
 | |
| 
 | |
| 	if (FindNextFile (dir->h, &dir->wfd) == FALSE)
 | |
| 	{
 | |
| 		DWORD x = GetLastError();
 | |
| 		if (x == ERROR_NO_MORE_FILES) dir->status |= STATUS_DONE;
 | |
| 		else
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(x));
 | |
| 			dir->status |= STATUS_DONE;
 | |
| 			dir->status |= STATUS_DONE_ERR;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 1;
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| 
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 	APIRET rc;
 | |
| 
 | |
| 	if (dir->count <= 0) return 0;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_SKIPSPCDIR)
 | |
| 	{
 | |
| 		/* skip . and .. */
 | |
| 		while (IS_CURDIR(dir->ffb.achName) || IS_PREVDIR(dir->ffb.achName))
 | |
| 		{
 | |
| 			rc = DosFindNext (dir->h, &dir->ffb, HAWK_SIZEOF(dir->ffb), &dir->count);
 | |
| 			if (rc == ERROR_NO_MORE_FILES)
 | |
| 			{
 | |
| 				dir->count = 0;
 | |
| 				return 0;
 | |
| 			}
 | |
| 			else if (rc != NO_ERROR)
 | |
| 			{
 | |
| 				hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(rc));
 | |
| 				return -1;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_BPATH)
 | |
| 	{
 | |
| 		if (mbs_to_mbuf (dir, dir->ffb.achName, &dir->mbuf) == HAWK_NULL) return -1;
 | |
| 		*name = HAWK_BECS_PTR(&dir->mbuf);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		HAWK_ASSERT (dir->flags & HAWK_DIR_UPATH);
 | |
| 		if (mbs_to_wbuf (dir, dir->ffb.achName, &dir->wbuf) == HAWK_NULL) return -1;
 | |
| 		*name = HAWK_UECS_PTR(&dir->wbuf);
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	rc = DosFindNext (dir->h, &dir->ffb, HAWK_SIZEOF(dir->ffb), &dir->count);
 | |
| 	if (rc == ERROR_NO_MORE_FILES) dir->count = 0;
 | |
| 	else if (rc != NO_ERROR)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(rc));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 1;
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 
 | |
| 	if (dir->status & STATUS_DONE) return (dir->status & STATUS_DONE_ERR)? -1: 0;
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_SKIPSPCDIR)
 | |
| 	{
 | |
| 		/* skip . and .. */
 | |
| 		while (IS_CURDIR(dir->f.name) || IS_PREVDIR(dir->f.name))
 | |
| 		{
 | |
| 			if (_dos_findnext (&dir->f) != 0)
 | |
| 			{
 | |
| 				if (errno == ENOENT)
 | |
| 				{
 | |
| 					dir->status |= STATUS_DONE;
 | |
| 					return 0;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 					dir->status |= STATUS_DONE;
 | |
| 					dir->status |= STATUS_DONE_ERR;
 | |
| 					return -1;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_BPATH)
 | |
| 	{
 | |
| 		if (mbs_to_mbuf (dir, dir->f.name, &dir->mbuf) == HAWK_NULL) return -1;
 | |
| 		*name = HAWK_BECS_PTR(&dir->mbuf);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		HAWK_ASSERT (dir->flags & HAWK_DIR_UPATH);
 | |
| 
 | |
| 		if (mbs_to_wbuf (dir, dir->f.name, &dir->wbuf) == HAWK_NULL) return -1;
 | |
| 		*name = HAWK_UECS_PTR(&dir->wbuf);
 | |
| 	}
 | |
| 
 | |
| 	if (_dos_findnext (&dir->f) != 0)
 | |
| 	{
 | |
| 		if (errno == ENOENT) dir->status |= STATUS_DONE;
 | |
| 		else
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 			dir->status |= STATUS_DONE;
 | |
| 			dir->status |= STATUS_DONE_ERR;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 1;
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 
 | |
| #else
 | |
| 
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 	hawk_dirent_t* de;
 | |
| 
 | |
| read:
 | |
| 	errno = 0;
 | |
| 	de = HAWK_READDIR(dir->dp);
 | |
| 	if (de == NULL)
 | |
| 	{
 | |
| 		if (errno == 0) return 0;
 | |
| 		hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_SKIPSPCDIR)
 | |
| 	{
 | |
| 		/* skip . and .. */
 | |
| 		if (IS_CURDIR(de->d_name) || IS_PREVDIR(de->d_name)) goto read;
 | |
| 	}
 | |
| 
 | |
| 	if (dir->flags & HAWK_DIR_BPATH)
 | |
| 	{
 | |
| 		if (mbs_to_mbuf(dir, de->d_name, &dir->mbuf) == HAWK_NULL) return -1;
 | |
| 		*name = HAWK_BECS_PTR(&dir->mbuf);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		/*HAWK_ASSERT (dir->flags & HAWK_DIR_UPATH);*/
 | |
| 		if (mbs_to_wbuf(dir, de->d_name, &dir->wbuf) == HAWK_NULL) return -1;
 | |
| 		*name = HAWK_UECS_PTR(&dir->wbuf);
 | |
| 	}
 | |
| 
 | |
| 	return 1;
 | |
| 	/* ------------------------------------------------------------------- */
 | |
| 
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static int read_ahead_and_sort (hawk_dir_t* dir, const hawk_ooch_t* path)
 | |
| {
 | |
| 	int x;
 | |
| 	void* name;
 | |
| 
 | |
| 	while (1)
 | |
| 	{
 | |
| 		x = read_dir_to_buf (dir, &name);
 | |
| 		if (x >= 1)
 | |
| 		{
 | |
| 			hawk_oow_t size;
 | |
| 
 | |
| 			if (dir->flags & HAWK_DIR_BPATH)
 | |
| 				size = (hawk_count_bcstr(name) + 1) * HAWK_SIZEOF(hawk_bch_t);
 | |
| 			else
 | |
| 				size = (hawk_count_ucstr(name) + 1) * HAWK_SIZEOF(hawk_uch_t);
 | |
| 
 | |
| 			if (hawk_arr_pushheap(dir->stab, name, size) == (hawk_oow_t)-1) return -1;
 | |
| 		}
 | |
| 		else if (x == 0) break;
 | |
| 		else return -1;
 | |
| 	}
 | |
| 
 | |
| 	dir->status &= ~STATUS_POPHEAP;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| int hawk_dir_read (hawk_dir_t* dir, hawk_dir_ent_t* ent)
 | |
| {
 | |
| 	if (dir->flags & HAWK_DIR_SORT)
 | |
| 	{
 | |
| 		if (dir->status & STATUS_SORT_ERR)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (dir->gem, HAWK_NULL, HAWK_ESTATE);
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		if (dir->status & STATUS_POPHEAP) hawk_arr_popheap (dir->stab);
 | |
| 		else dir->status |= STATUS_POPHEAP;
 | |
| 
 | |
| 		if (HAWK_ARR_SIZE(dir->stab) <= 0) return 0; /* no more entry */
 | |
| 
 | |
| 		ent->name = HAWK_ARR_DPTR(dir->stab, 0);
 | |
| 		return 1;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		int x;
 | |
| 		void* name;
 | |
| 
 | |
| 		x = read_dir_to_buf(dir, &name);
 | |
| 		if (x >= 1)
 | |
| 		{
 | |
| 			HAWK_MEMSET (ent, 0, HAWK_SIZEOF(*ent));
 | |
| 			ent->name = name;
 | |
| 		}
 | |
| 
 | |
| 		return x;
 | |
| 	}
 | |
| }
 |