enhanced qse_dir_t

This commit is contained in:
hyung-hwan 2011-10-25 01:48:07 +00:00
parent 67e9eb8d9f
commit f2d60b9366
6 changed files with 258 additions and 118 deletions

View File

@ -70,6 +70,22 @@ int qse_isabspath (
const qse_char_t* path const qse_char_t* path
); );
/**
* The qse_isdrivepath() function determines if a path name begins with
* a drive letter followed by a colon like A:.
*/
int qse_isdrivepath (
const qse_char_t* path
);
/**
* The qse_isdrivecurpath() function determines if a path name is in the form
* of a drive letter followed by a colon like A:, without any trailing path.
*/
int qse_isdrivecurpath (
const qse_char_t* path
);
/** /**
* The qse_canonpath() function canonicalizes a path name @a path by deleting * The qse_canonpath() function canonicalizes a path name @a path by deleting
* unnecessary path segments from it and stores the result to a memory buffer * unnecessary path segments from it and stores the result to a memory buffer

View File

@ -33,7 +33,7 @@ enum qse_dir_errnum_t
QSE_DIR_EINVAL, QSE_DIR_EINVAL,
QSE_DIR_EACCES, QSE_DIR_EACCES,
QSE_DIR_ENOENT, QSE_DIR_ENOENT,
QSE_DIR_ENOTDIR, QSE_DIR_ENODIR,
QSE_DIR_ESYSTEM QSE_DIR_ESYSTEM
}; };
typedef enum qse_dir_errnum_t qse_dir_errnum_t; typedef enum qse_dir_errnum_t qse_dir_errnum_t;

View File

@ -30,7 +30,7 @@
#define ISDRIVE(s) \ #define ISDRIVE(s) \
(((s[0] >= QSE_T('A') && s[0] <= QSE_T('Z')) || \ (((s[0] >= QSE_T('A') && s[0] <= QSE_T('Z')) || \
(s[0] >= QSE_T('a') && s[0] <= QSE_T('a'))) && \ (s[0] >= QSE_T('a') && s[0] <= QSE_T('z'))) && \
s[1] == QSE_T(':')) s[1] == QSE_T(':'))
int qse_isabspath (const qse_char_t* path) int qse_isabspath (const qse_char_t* path)
@ -45,12 +45,30 @@ int qse_isabspath (const qse_char_t* path)
} }
int qse_isdrivepath (const qse_char_t* path)
{
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
if (ISDRIVE(path)) return 1;
#endif
return 0;
}
int qse_isdrivecurpath (const qse_char_t* path)
{
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
if (ISDRIVE(path) && path[2] == QSE_T('\0')) return 1;
#endif
return 0;
}
qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon) qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
{ {
const qse_char_t* ptr; const qse_char_t* ptr;
qse_char_t* dst; qse_char_t* dst;
qse_char_t* non_root_start; qse_char_t* non_root_start;
int has_root = 0; int has_root = 0;
int begins_with_curdir = 0;
qse_size_t canon_len;
ptr = path; ptr = path;
dst = canon; dst = canon;
@ -94,12 +112,20 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
} }
#endif #endif
} }
else if (ptr[0] == QSE_T('.') && ISSEPNIL(ptr[1]))
{
begins_with_curdir = 1;
}
#else #else
if (ISSEP(*ptr)) if (ISSEP(*ptr))
{ {
*dst++ = *ptr++; /* root directory */ *dst++ = *ptr++; /* root directory */
has_root = 1; has_root = 1;
} }
else if (ptr[0] == QSE_T('.') && ISSEPNIL(ptr[1]))
{
begins_with_curdir = 1;
}
#endif #endif
/* non_root_start points to the beginning of the canonicalized /* non_root_start points to the beginning of the canonicalized
@ -228,14 +254,25 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
* the origial path ends with a separator * the origial path ends with a separator
*/ */
dst[-1] = QSE_T('\0'); dst[-1] = QSE_T('\0');
return dst - canon - 1; canon_len = dst - canon - 1;
} }
else else
{ {
/* just null-terminate the canonical path normally */ /* just null-terminate the canonical path normally */
dst[0] = QSE_T('\0'); dst[0] = QSE_T('\0');
return dst - canon; canon_len = dst - canon;
} }
if (canon_len <= 0 && begins_with_curdir)
{
/* when resolving to a single dot, a trailing separator is not
* retained though the orignal path name contains it */
dst[0] = QSE_T('.');
dst[1] = QSE_T('\0');
canon_len = 1;
}
return canon_len;
} }
qse_size_t qse_realpath (const qse_char_t* path, qse_char_t* real) qse_size_t qse_realpath (const qse_char_t* path, qse_char_t* real)

View File

@ -44,14 +44,63 @@ struct info_t
#if defined(_WIN32) #if defined(_WIN32)
HANDLE handle; HANDLE handle;
WIN32_FIND_DATA wfd; WIN32_FIND_DATA wfd;
unsigned int first_after_change; int just_changed_dir;
#elif defined(__OS2__) #elif defined(__OS2__)
#elif defined(__DOS__) #elif defined(__DOS__)
#else #else
DIR* handle; DIR* handle;
qse_mchar_t* mcurdir;
#endif #endif
}; };
#if defined(_WIN32)
static QSE_INLINE qse_dir_errnum_t syserr_to_errnum (DWORD e)
{
switch (e)
{
case ERROR_INVALID_NAME:
case ERROR_DIRECTORY:
return QSE_DIR_EINVAL;
case ERROR_ACCESS_DENIED:
return QSE_DIR_EACCES;
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
return QSE_DIR_ENOENT;
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OUTOFMEMORY:
return QSE_DIR_ENOMEM;
default:
return QSE_DIR_ESYSTEM;
}
}
#else
static QSE_INLINE qse_dir_errnum_t syserr_to_errnum (int e)
{
switch (e)
{
case EINVAL:
return QSE_DIR_EINVAL;
case EACCES:
return QSE_DIR_EACCES;
case ENOENT:
case ENOTDIR:
return QSE_DIR_ENOENT;
case ENOMEM:
return QSE_DIR_ENOMEM;
default:
return QSE_DIR_ESYSTEM;
}
}
#endif
QSE_IMPLEMENT_COMMON_FUNCTIONS (dir) QSE_IMPLEMENT_COMMON_FUNCTIONS (dir)
qse_dir_t* qse_dir_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) qse_dir_t* qse_dir_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
@ -119,6 +168,10 @@ void qse_dir_fini (qse_dir_t* dir)
#elif defined(__DOS__) #elif defined(__DOS__)
# error NOT IMPLEMENTED # error NOT IMPLEMENTED
#else #else
if (info->mcurdir && info->mcurdir != dir->curdir)
QSE_MMGR_FREE (dir->mmgr, info->mcurdir);
info->mcurdir = QSE_NULL;
if (info->handle) if (info->handle)
{ {
closedir (info->handle); closedir (info->handle);
@ -137,6 +190,30 @@ void qse_dir_fini (qse_dir_t* dir)
} }
} }
static QSE_INLINE info_t* get_info (qse_dir_t* dir)
{
info_t* info;
info = dir->info;
if (info == QSE_NULL)
{
info = QSE_MMGR_ALLOC (dir->mmgr, QSE_SIZEOF(*info));
if (info == QSE_NULL)
{
dir->errnum = QSE_DIR_ENOMEM;
return QSE_NULL;
}
QSE_MEMSET (info, 0, QSE_SIZEOF(*info));
#if defined(_WIN32)
info->handle = INVALID_HANDLE_VALUE;
#endif
dir->info = info;
}
return info;
}
int qse_dir_change (qse_dir_t* dir, const qse_char_t* name) int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
{ {
qse_char_t* dirname; qse_char_t* dirname;
@ -153,7 +230,9 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
# error NOT IMPLEMENTED # error NOT IMPLEMENTED
#else #else
DIR* handle; DIR* handle;
qse_mchar_t* mbsdirname; qse_mchar_t* mdirname;
const qse_char_t* tmp_name[4];
qse_size_t idx;
#endif #endif
if (name[0] == QSE_T('\0')) if (name[0] == QSE_T('\0'))
@ -162,29 +241,20 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
return -1; return -1;
} }
info = dir->info; info = get_info (dir);
if (info == QSE_NULL) if (info == QSE_NULL) return -1;
{
info = QSE_MMGR_ALLOC (dir->mmgr, QSE_SIZEOF(*info));
if (info == QSE_NULL)
{
dir->errnum = QSE_DIR_ENOMEM;
return -1;
}
QSE_MEMSET (info, 0, QSE_SIZEOF(*info));
#if defined(_WIN32)
info->handle = INVALID_HANDLE_VALUE;
#endif
dir->info = info;
}
#if defined(_WIN32) #if defined(_WIN32)
idx = 0; idx = 0;
if (!qse_isabspath(name) && dir->curdir) if (!qse_isabspath(name) && dir->curdir)
tmp_name[idx++] = dir->curdir; tmp_name[idx++] = dir->curdir;
tmp_name[idx++] = name; tmp_name[idx++] = name;
if (qse_isdrivecurpath(name))
tmp_name[idx++] = QSE_T(" ");
else
tmp_name[idx++] = QSE_T("\\ "); tmp_name[idx++] = QSE_T("\\ ");
tmp_name[idx] = QSE_NULL; tmp_name[idx] = QSE_NULL;
dirname = qse_stradup (tmp_name, dir->mmgr); dirname = qse_stradup (tmp_name, dir->mmgr);
@ -195,26 +265,24 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
} }
idx = qse_canonpath (dirname, dirname); idx = qse_canonpath (dirname, dirname);
/* Put the asterisk after canonicalization to prevent side-effects. /* Put an asterisk after canonicalization to prevent side-effects.
* otherwise, .\* would be transformed to * by qse_canonpath() */ * otherwise, .\* would be transformed to * by qse_canonpath() */
dirname[idx-1] = QSE_T('*'); dirname[idx-1] = QSE_T('*');
/* /* Using FindExInfoBasic won't resolve cAlternatFileName.
I don't return a short name so FindExInfoBasic can speed up the function. * so it can get faster a little bit. The problem is that
FindFirstFileEx ( * it is not supported on old windows. just stick to the
* simple API instead. */
#if 0
handle = FindFirstFileEx (
dirname, FindExInfoBasic, dirname, FindExInfoBasic,
&wfd, FindExSearchNameMatch, &wfd, FindExSearchNameMatch,
NULL, FIND_FIRST_EX_CASE_SENSITIVE); NULL, 0/*FIND_FIRST_EX_CASE_SENSITIVE*/);
*/ #endif
handle = FindFirstFile (dirname, &wfd); handle = FindFirstFile (dirname, &wfd);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
{ {
DWORD e = GetLastError(); dir->errnum = syserr_to_errnum (GetLastError());
dir->errnum = (e == ERROR_ACCESS_DENIED)? QSE_DIR_EACCES:
(e == ERROR_FILE_NOT_FOUND)? QSE_DIR_ENOENT:
(e == ERROR_INVALID_NAME)? QSE_DIR_EINVAL:
(e == ERROR_DIRECTORY)? QSE_DIR_EINVAL:
QSE_DIR_ESYSTEM;
QSE_MMGR_FREE (dir->mmgr, dirname); QSE_MMGR_FREE (dir->mmgr, dirname);
return -1; return -1;
} }
@ -225,11 +293,11 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
QSE_MEMSET (info, 0, QSE_SIZEOF(*info)); QSE_MEMSET (info, 0, QSE_SIZEOF(*info));
info->handle = handle; info->handle = handle;
info->wfd = wfd; info->wfd = wfd;
info->just_changed_dir = 1;
if (dir->curdir) QSE_MMGR_FREE (dir->mmgr, dir->curdir); if (dir->curdir) QSE_MMGR_FREE (dir->mmgr, dir->curdir);
dirname[idx-1] = QSE_T('\0'); /* drop the asterisk */ dirname[idx-1] = QSE_T('\0'); /* drop the asterisk */
dir->curdir = dirname; dir->curdir = dirname;
dir->first_after_change = 1;
return 0; return 0;
@ -238,7 +306,17 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
#elif defined(__DOS__) #elif defined(__DOS__)
# error NOT IMPLEMENTED # error NOT IMPLEMENTED
#else #else
dirname = qse_strdup (name, dir->mmgr);
idx = 0;
if (!qse_isabspath(name) && dir->curdir)
{
tmp_name[idx++] = dir->curdir;
tmp_name[idx++] = QSE_T("/");
}
tmp_name[idx++] = name;
tmp_name[idx] = QSE_NULL;
dirname = qse_stradup (tmp_name, dir->mmgr);
if (dirname == QSE_NULL) if (dirname == QSE_NULL)
{ {
dir->errnum = QSE_DIR_ENOMEM; dir->errnum = QSE_DIR_ENOMEM;
@ -248,10 +326,10 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
qse_canonpath (dirname, dirname); qse_canonpath (dirname, dirname);
#if defined(QSE_CHAR_IS_MCHAR) #if defined(QSE_CHAR_IS_MCHAR)
mbsdirname = dirname; mdirname = dirname;
#else #else
mbsdirname = qse_wcstombsdup (name, dir->mmgr); mdirname = qse_wcstombsdup (dirname, dir->mmgr);
if (mbsdirname == QSE_NULL) if (mdirname == QSE_NULL)
{ {
dir->errnum = QSE_DIR_ENOMEM; dir->errnum = QSE_DIR_ENOMEM;
QSE_MMGR_FREE (dir->mmgr, dirname); QSE_MMGR_FREE (dir->mmgr, dirname);
@ -259,22 +337,13 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
} }
#endif #endif
handle = opendir (mbsdirname); handle = opendir (mdirname);
#if defined(QSE_CHAR_IS_MCHAR)
/* do nothing */
#else
QSE_MMGR_FREE (dir->mmgr, mbsdirname);
#endif
if (handle == QSE_NULL) if (handle == QSE_NULL)
{ {
dir->errnum = (errno == EACCES)? QSE_DIR_EACCES: dir->errnum = syserr_to_errnum (errno);
(errno == ENOENT)? QSE_DIR_ENOENT: if (mdirname != dirname)
(errno == ENOTDIR)? QSE_DIR_ENOTDIR: QSE_MMGR_FREE (dir->mmgr, mdirname);
(errno == ENOMEM)? QSE_DIR_ENOMEM:
QSE_DIR_ESYSTEM;
QSE_MMGR_FREE (dir->mmgr, dirname); QSE_MMGR_FREE (dir->mmgr, dirname);
return -1; return -1;
} }
@ -282,6 +351,10 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
if (info->handle) closedir (info->handle); if (info->handle) closedir (info->handle);
info->handle = handle; info->handle = handle;
if (info->mcurdir && info->mcurdir != dir->curdir)
QSE_MMGR_FREE (dir->mmgr, info->mcurdir);
info->mcurdir = mdirname;
if (dir->curdir) QSE_MMGR_FREE (dir->mmgr, dir->curdir); if (dir->curdir) QSE_MMGR_FREE (dir->mmgr, dir->curdir);
dir->curdir = dirname; dir->curdir = dirname;
@ -349,34 +422,19 @@ static int set_entry_name (qse_dir_t* dir, const qse_mchar_t* name)
qse_dir_ent_t* qse_dir_read (qse_dir_t* dir) qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
{ {
#if defined(_WIN32)
info_t* info; info_t* info;
info = dir->info; info = dir->info;
if (info == QSE_NULL) if (info == QSE_NULL)
{ {
/* dir->errnum = QSE_DIR_ENODIR;
dir->errnum = NO CHANGE DIR YET;
*/
return QSE_NULL; return QSE_NULL;
} }
#if defined(_WIN32) if (info->just_changed_dir)
#if 0
if (info->no_more_files)
{ {
dir->errnum = QSE_DIR_ENOERR; info->just_changed_dir = 0;
return QSE_NULL;
}
#endif
if (info->first_after_change)
{
/* call set_entry_name before changing other fields
* in dir->ent not to pollute it in case set_entry_name fails */
if (set_entry_name (dir, info->wfd.cFileName) <= -1) return QSE_NULL;
info->first_after_change = 0;
} }
else else
{ {
@ -385,32 +443,32 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
DWORD e = GetLastError(); DWORD e = GetLastError();
if (e == ERROR_NO_MORE_FILES) if (e == ERROR_NO_MORE_FILES)
{ {
//info->no_more_files = 1;
dir->errnum = QSE_DIR_ENOERR; dir->errnum = QSE_DIR_ENOERR;
return QSE_NULL; return QSE_NULL;
} }
else else
{ {
dir->errnum = (e == ERROR_ACCESS_DENIED)? QSE_DIR_EACCES: dir->errnum = syserr_to_errnum (GetLastError());
(e == ERROR_FILE_NOT_FOUND)? QSE_DIR_ENOENT:
(e == ERROR_INVALID_NAME)? QSE_DIR_EINVAL:
(e == ERROR_DIRECTORY)? QSE_DIR_EINVAL:
QSE_DIR_ESYSTEM;
return QSE_NULL; return QSE_NULL;
} }
} }
}
/* call set_entry_name before changing other fields /* call set_entry_name before changing other fields
* in dir->ent not to pollute it in case set_entry_name fails */ * in dir->ent not to pollute it in case set_entry_name fails */
if (set_entry_name (dir, info->wfd.cFileName) <= -1) return QSE_NULL; if (set_entry_name (dir, info->wfd.cFileName) <= -1) return QSE_NULL;
}
if (info->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) if (info->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ {
dir->ent.size = 0; dir->ent.size = 0;
dir->ent.type = QSE_DIR_ENT_DIRECTORY; dir->ent.type = QSE_DIR_ENT_DIRECTORY;
} }
else if ((info->wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
(info->wfd.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
{
dir->ent.size = 0;
dir->ent.type = QSE_DIR_ENT_LINK;
}
else else
{ {
LARGE_INTEGER li; LARGE_INTEGER li;
@ -425,56 +483,78 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
#elif defined(__DOS__) #elif defined(__DOS__)
# error NOT IMPLEMENTED # error NOT IMPLEMENTED
#else #else
struct dirent* ent;
info_t* info;
struct dirent* ent;
int x;
#if defined(HAVE_LSTAT64)
struct stat64 st;
#else
struct stat st;
#endif
qse_mchar_t* tmp_name[4];
qse_mchar_t* mfname;
info = dir->info;
if (info == QSE_NULL)
{
dir->errnum = QSE_DIR_ENODIR;
return QSE_NULL;
}
errno = 0;
ent = readdir (info->handle); ent = readdir (info->handle);
if (ent == QSE_NULL) if (ent == QSE_NULL)
{ {
/*dir->errnum = QSE_DIR_ENOENT;*/ /* TODO: to be more specific */ if (errno != 0) dir->errnum = syserr_to_errnum (errno);
return QSE_NULL; return QSE_NULL;
} }
#if defined(HAVE_STRUCT_DIRENT_D_TYPE) #if defined(HAVE_STRUCT_DIRENT_D_TYPE)
if (ent->d_type != DT_DIR) /* end->d_type */
#endif #endif
/* TODO: use a buffer in info... instead of allocating an deallocating every time */
tmp_name[0] = info->mcurdir;
tmp_name[1] = QSE_MT("/");
tmp_name[2] = ent->d_name;
tmp_name[3] = QSE_NULL;
mfname = qse_mbsadup (tmp_name, dir->mmgr);
if (mfname == QSE_NULL)
{ {
int x; dir->errnum = QSE_DIR_ENOMEM;
#if defined(HAVE_LSTAT64)
struct stat64 st;
x = lstat64 (ent->d_name, &st);
#else
struct stat st;
x = lstat (ent->d_name, &st);
#endif
if (x == -1)
{
/*TODO: dir->errnum = ... */
return QSE_NULL; return QSE_NULL;
} }
#if defined(HAVE_LSTAT64)
x = lstat64 (mfname, &st);
#else
x = lstat (mfname, &st);
#endif
QSE_MMGR_FREE (dir->mmgr, mfname);
if (x == -1)
{
dir->errnum = syserr_to_errnum (errno);
return QSE_NULL;
} }
if (set_entry_name (dir, ent->d_name) <= -1) return QSE_NULL; if (set_entry_name (dir, ent->d_name) <= -1) return QSE_NULL;
#if defined(HAVE_STRUCT_DIRENT_D_TYPE) if (S_ISDIR(st.st_mode))
switch (ent->d_type)
{ {
case DT_DIR:
dir->ent.size = 0; dir->ent.size = 0;
dir->ent.type = QSE_DIR_ENT_DIRECTORY; dir->ent.type = QSE_DIR_ENT_DIRECTORY;
break;
case DT_REG:
dir->ent.type = QSE_DIR_ENT_REGULAR;
break;
default:
dir->ent.size = 0;
dir->ent.type = QSE_DIR_ENT_UNKNOWN;
break;
} }
#endif else
{
dir->ent.size = st.st_size;
dir->ent.type = QSE_DIR_ENT_UNKNOWN;
}
#endif #endif
return &dir->ent; return &dir->ent;
} }
@ -499,7 +579,7 @@ const qse_char_t* qse_dir_geterrmsg (qse_dir_t* dir)
QSE_T("invalid parameter or data"), QSE_T("invalid parameter or data"),
QSE_T("permission denined"), QSE_T("permission denined"),
QSE_T("no such entry"), QSE_T("no such entry"),
QSE_T("not a directory"), QSE_T("no working directory set"),
QSE_T("system error") QSE_T("system error")
}; };

View File

@ -369,8 +369,9 @@ static int test8 (void)
while (1) while (1)
{ {
qse_size_t mlen;
memset (buf, 'A', sizeof(buf)); memset (buf, 'A', sizeof(buf));
qse_size_t mlen = sizeof(buf); mlen = sizeof(buf);
n = qse_wcstombs (p, buf, &mlen); n = qse_wcstombs (p, buf, &mlen);
if (n == 0) break; if (n == 0) break;
@ -576,9 +577,9 @@ static int test14 (void)
{ {
qse_str_cpy (&x, a1); qse_str_cpy (&x, a1);
qse_str_del (&x, 10, i); qse_str_del (&x, 10, i);
qse_printf (QSE_T("deleleted %d from 10 => %llu [%s]\n"), qse_printf (QSE_T("deleleted %d from 10 => %lu [%s]\n"),
i, i,
(unsigned long long)QSE_STR_LEN(&x), (unsigned long)QSE_STR_LEN(&x),
QSE_STR_PTR(&x)); QSE_STR_PTR(&x));
} }

View File

@ -9,7 +9,7 @@ static void list (qse_dir_t* dir, const qse_char_t* name)
if (qse_dir_change (dir, name) <= -1) if (qse_dir_change (dir, name) <= -1)
{ {
qse_fprintf (QSE_STDERR, QSE_T("Error: Cannot change directory to %s\n"), name); qse_fprintf (QSE_STDERR, QSE_T("Error: Cannot change directory to %s - %s\n"), name, qse_dir_geterrmsg(dir));
return; return;
} }
@ -20,7 +20,13 @@ static void list (qse_dir_t* dir, const qse_char_t* name)
do do
{ {
ent = qse_dir_read (dir); ent = qse_dir_read (dir);
if (ent == QSE_NULL) break; if (ent == QSE_NULL)
{
qse_dir_errnum_t e = qse_dir_geterrnum(dir);
if (e != QSE_DIR_ENOERR)
qse_fprintf (QSE_STDERR, QSE_T("Error: Read error - %s\n"), qse_dir_geterrmsg(dir));
break;
}
if (ent->type == QSE_DIR_ENT_DIRECTORY) if (ent->type == QSE_DIR_ENT_DIRECTORY)
qse_printf (QSE_T("<DIR> %16lu %s\n"), (unsigned long)ent->size, ent->name); qse_printf (QSE_T("<DIR> %16lu %s\n"), (unsigned long)ent->size, ent->name);