842 lines
19 KiB
C
842 lines
19 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
Copyright (c) 2006-2019 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)
|
|
{
|
|
int n;
|
|
int path_flags;
|
|
|
|
path_flags = flags & (HAWK_DIR_MBSPATH | HAWK_DIR_WCSPATH);
|
|
if (path_flags == (HAWK_DIR_MBSPATH | HAWK_DIR_WCSPATH) || 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_MBSPATH;
|
|
flags &= ~HAWK_DIR_WCSPATH;
|
|
#else
|
|
flags |= HAWK_DIR_WCSPATH;
|
|
flags &= ~HAWK_DIR_MBSPATH;
|
|
#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 (dir->stab == HAWK_NULL) goto oops_3;
|
|
|
|
/*hawk_arr_setscale (dir->stab, 1);*/
|
|
hawk_arr_setcopier (dir->stab, HAWK_ARR_COPIER_INLINE);
|
|
hawk_arr_setcomper (dir->stab, compare_dirent);
|
|
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)
|
|
{
|
|
#if 0
|
|
hawk_oow_t ml, wl;
|
|
|
|
if (hawk_gem_convutobcstr(gem, wcs, &wl, HAWK_NULL, &ml) <= -1) return HAWK_NULL;
|
|
|
|
if (hawk_becs_setlen(mbuf, ml) == (hawk_oow_t)-1)
|
|
{
|
|
dir->errnum = HAWK_DIR_ENOMEM;
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
hawk_wcstombs (wcs, &wl, HAWK_BECS_PTR(mbuf), &ml);
|
|
return HAWK_BECS_PTR(mbuf);
|
|
|
|
#else
|
|
|
|
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);
|
|
#endif
|
|
}
|
|
|
|
static hawk_uch_t* mbs_to_wbuf (hawk_dir_t* dir, const hawk_bch_t* mbs, hawk_uecs_t* wbuf)
|
|
{
|
|
#if 0
|
|
hawk_oow_t ml, wl;
|
|
|
|
if (hawk_mbstowcs (mbs, &ml, HAWK_NULL, &wl) <= -1)
|
|
{
|
|
dir->errnum = HAWK_DIR_EINVAL;
|
|
return HAWK_NULL;
|
|
}
|
|
if (hawk_uecs_setlen (wbuf, wl) == (hawk_oow_t)-1)
|
|
{
|
|
dir->errnum = HAWK_DIR_ENOMEM;
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
hawk_mbstowcs (mbs, &ml, HAWK_UECS_PTR(wbuf), &wl);
|
|
return HAWK_UECS_PTR(wbuf);
|
|
#else
|
|
/* convert all regardless of encoding failure */
|
|
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);
|
|
#endif
|
|
}
|
|
|
|
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 hawk_ooch_t* make_dos_path (hawk_dir_t* dir, const hawk_ooch_t* path)
|
|
{
|
|
if (path[0] == HAWK_T('\0'))
|
|
{
|
|
if (hawk_str_cpy (&dir->tbuf, HAWK_T("*.*")) == (hawk_oow_t)-1)
|
|
{
|
|
dir->errnum = HAWK_DIR_ENOMEM;
|
|
return HAWK_NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hawk_oow_t len;
|
|
if ((len = hawk_str_cpy (&dir->tbuf, path)) == (hawk_oow_t)-1 ||
|
|
(!HAWK_ISPATHSEP(path[len - 1]) &&
|
|
!hawk_isdrivecurpath(path) &&
|
|
hawk_str_ccat (&dir->tbuf, HAWK_T('\\')) == (hawk_oow_t)-1) ||
|
|
hawk_str_cat (&dir->tbuf, HAWK_T("*.*")) == (hawk_oow_t)-1)
|
|
{
|
|
dir->errnum = HAWK_DIR_ENOMEM;
|
|
return HAWK_NULL;
|
|
}
|
|
}
|
|
|
|
return HAWK_STR_PTR(&dir->tbuf);
|
|
}
|
|
|
|
static hawk_bch_t* mkdospath (hawk_dir_t* dir, const hawk_ooch_t* path)
|
|
{
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
return make_dos_path (dir, path);
|
|
#else
|
|
if (dir->flags & HAWK_DIR_MBSPATH)
|
|
{
|
|
return make_mbsdos_path (dir, (const hawk_bch_t*) path);
|
|
}
|
|
else
|
|
{
|
|
hawk_ooch_t* tptr;
|
|
hawk_bch_t* mptr;
|
|
|
|
tptr = make_dos_path (dir, path);
|
|
if (tptr == HAWK_NULL) return HAWK_NULL;
|
|
|
|
mptr = wcs_to_mbuf (dir, HAWK_STR_PTR(&dir->tbuf), &dir->mbuf);
|
|
if (mptr == HAWK_NULL) return HAWK_NULL;
|
|
|
|
return mptr;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
*/
|
|
|
|
static int reset_to_path (hawk_dir_t* dir, const hawk_ooch_t* path)
|
|
{
|
|
#if defined(_WIN32)
|
|
/* ------------------------------------------------------------------- */
|
|
const hawk_ooch_t* tptr;
|
|
|
|
dir->status &= ~STATUS_DONE;
|
|
dir->status &= ~STATUS_DONE_ERR;
|
|
|
|
if (dir->flags & HAWK_DIR_MBSPATH)
|
|
{
|
|
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_WCSPATH);
|
|
|
|
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;
|
|
|
|
dir->h = FindFirstFile(tptr, &dir->wfd);
|
|
if (dir->h == INVALID_HANDLE_VALUE)
|
|
{
|
|
hawk_gem_seterrnum (dir->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
APIRET rc;
|
|
const hawk_bch_t* mptr;
|
|
|
|
dir->h = HDIR_CREATE;
|
|
dir->count = 1;
|
|
|
|
if (dir->flags & HAWK_DIR_MBSPATH)
|
|
{
|
|
mptr = make_mbsdos_path (dir, (const hawk_bch_t*)path);
|
|
}
|
|
else
|
|
{
|
|
hawk_uch_t* wptr;
|
|
HAWK_ASSERT (dir->flags & HAWK_DIR_WCSPATH);
|
|
|
|
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,
|
|
&dir->h,
|
|
FILE_DIRECTORY | FILE_READONLY,
|
|
&dir->ffb,
|
|
HAWK_SIZEOF(dir->ffb),
|
|
&dir->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;
|
|
}
|
|
|
|
dir->status |= STATUS_OPENED;
|
|
return 0;
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
#elif defined(__DOS__)
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
unsigned int rc;
|
|
const hawk_bch_t* mptr;
|
|
|
|
dir->status &= ~STATUS_DONE;
|
|
dir->status &= ~STATUS_DONE_ERR;
|
|
|
|
if (dir->flags & HAWK_DIR_MBSPATH)
|
|
{
|
|
mptr = make_mbsdos_path(dir, (const hawk_bch_t*)path);
|
|
}
|
|
else
|
|
{
|
|
hawk_uch_t* wptr;
|
|
|
|
HAWK_ASSERT (dir->flags & HAWK_DIR_WCSPATH);
|
|
|
|
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, &dir->f);
|
|
if (rc != 0)
|
|
{
|
|
hawk_gem_seterrnum (dir->gem, HAWK_NULL,hawk_syserr_to_errnum(errno));
|
|
return -1;
|
|
}
|
|
|
|
dir->status |= STATUS_OPENED;
|
|
return 0;
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
#else
|
|
DIR* dp;
|
|
|
|
if (dir->flags & HAWK_DIR_MBSPATH)
|
|
{
|
|
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_WCSPATH);*/
|
|
|
|
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;
|
|
}
|
|
|
|
dir->dp = dp;
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int hawk_dir_reset (hawk_dir_t* dir, const hawk_ooch_t* path)
|
|
{
|
|
close_dir_safely (dir);
|
|
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_MBSPATH)
|
|
{
|
|
#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_WCSPATH);
|
|
#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_MBSPATH)
|
|
{
|
|
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_WCSPATH);
|
|
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_MBSPATH)
|
|
{
|
|
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_WCSPATH);
|
|
|
|
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_MBSPATH)
|
|
{
|
|
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_WCSPATH);*/
|
|
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_MBSPATH)
|
|
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) 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;
|
|
}
|
|
}
|