From 38500b97d6a705cb3f16a283aad4f417afbe4efa Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sat, 15 Oct 2011 23:18:55 +0000 Subject: [PATCH] added qse_stradup() and related functions coded qse_dir_change() for win32 --- qse/include/qse/cmn/path.h | 48 ++++++-- qse/include/qse/cmn/str.h | 12 ++ qse/include/qse/fs/dir.h | 28 ++++- qse/lib/cmn/path-basename.c | 18 +-- qse/lib/cmn/str-dup.c | 41 +++++++ qse/lib/fs/dir.c | 217 ++++++++++++++++++++++++++++-------- qse/samples/cmn/path01.c | 10 +- qse/samples/fs/dir01.c | 44 +++++--- 8 files changed, 331 insertions(+), 87 deletions(-) diff --git a/qse/include/qse/cmn/path.h b/qse/include/qse/cmn/path.h index 861d6348..bc4fbe8c 100644 --- a/qse/include/qse/cmn/path.h +++ b/qse/include/qse/cmn/path.h @@ -22,12 +22,17 @@ #define _QSE_CMN_PATH_H_ /** @file - * This file provides functions for simple path name manipulation. + * This file provides functions for path name manipulation. */ #include #include +/** + * The qse_basename() macro returns the pointer to the file name + * segment in a path name. It maps to qse_mbsbasename() if #QSE_CHAR_IS_MCHAR + * is defined; it maps to qse_wcsbasename() if #QSE_CHAR_IS_WCHAR is defined. + */ #ifdef QSE_CHAR_IS_MCHAR # define qse_basename(path) qse_mbsbasename(path) #else @@ -38,26 +43,45 @@ extern "C" { #endif +/** + * The qse_mbsbasename() function returns the pointer to the file name + * segment in a multibyte path name. + */ const qse_mchar_t* qse_mbsbasename ( const qse_mchar_t* path ); +/** + * The qse_wcsbasename() function returns the pointer to the file name + * segment in a wide-character path name. + */ const qse_wchar_t* qse_wcsbasename ( const qse_wchar_t* path ); -/* - * The qse_canonpath() function deletes unnecessary path segments - * from a path name 'path' and stores it to a memory buffer pointed - * to by 'canon'. It null-terminates the canonical path in 'canon' and - * returns the number of characters excluding the terminating null. - * The caller must ensure that it is large enough before calling this - * because this function does not check the size of the memory buffer. - * Since the canonical path cannot be larger than the original path, - * you can simply ensure this by providing a memory buffer as long as - * the number of characters and a terminating null in the original path. +/** + * 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 + * pointed to by @a canon. Canonicalization is purely performed on the path + * name without refering to actual file systems. It null-terminates the + * canonical path in @a canon and returns the number of characters excluding + * the terminating null. * - * @return the number of characters in the resulting canonical path. + * @code + * qse_char_t buf[64]; + * qse_canonpath ("/usr/local/../bin/sh", buf); + * qse_printf (QSE_T("%s\n")); // prints /usr/bin/sh + * @endcode + * + * The caller must ensure that it is large enough to hold the resulting + * canonical path before calling because this function does not check the + * size of the memory buffer. Since the canonical path cannot be larger + * than the original path, you can simply ensure this by providing a memory + * buffer as long as the number of characters and a terminating null in + * the original path. + * + * @return number of characters in the resulting canonical path excluding + * the terminating null. */ qse_size_t qse_canonpath ( const qse_char_t* path, diff --git a/qse/include/qse/cmn/str.h b/qse/include/qse/cmn/str.h index 65dbf02a..c5f06fcd 100644 --- a/qse/include/qse/cmn/str.h +++ b/qse/include/qse/cmn/str.h @@ -961,6 +961,11 @@ qse_mchar_t* qse_mbsxdup2 ( qse_mmgr_t* mmgr ); +qse_mchar_t* qse_mbsadup ( + const qse_mchar_t* str[], + qse_mmgr_t* mmgr +); + qse_wchar_t* qse_wcsdup ( const qse_wchar_t* str, qse_mmgr_t* mmgr @@ -986,16 +991,23 @@ qse_wchar_t* qse_wcsxdup2 ( qse_mmgr_t* mmgr ); +qse_wchar_t* qse_wcsadup ( + const qse_wchar_t* str[], + qse_mmgr_t* mmgr +); + #ifdef QSE_CHAR_IS_MCHAR # define qse_strdup(s,mmgr) qse_mbsdup(s,mmgr) # define qse_strdup2(s1,s2,mmgr) qse_mbsdup2(s1,s2,mmgr) # define qse_strxdup(s,l,mmgr) qse_mbsxdup(s,l,mmgr) # define qse_strxdup2(s1,l1,s2,l2,mmgr) qse_mbsxdup(s1,l1,s2,l2,mmgr) +# define qse_stradup(sa,mmgr) qse_mbsadup(sa,mmgr) #else # define qse_strdup(s,mmgr) qse_wcsdup(s,mmgr) # define qse_strdup2(s1,s2,mmgr) qse_wcsdup2(s1,s2,mmgr) # define qse_strxdup(s,l,mmgr) qse_wcsxdup(s,l,mmgr) # define qse_strxdup2(s1,l1,s2,l2,mmgr) qse_wcsxdup(s1,l1,s2,l2,mmgr) +# define qse_stradup(sa,mmgr) qse_wcsadup(sa,mmgr) #endif /** diff --git a/qse/include/qse/fs/dir.h b/qse/include/qse/fs/dir.h index a47436c4..791272d2 100644 --- a/qse/include/qse/fs/dir.h +++ b/qse/include/qse/fs/dir.h @@ -24,8 +24,6 @@ #include #include -typedef struct qse_dir_ent_t qse_dir_ent_t; - struct qse_dir_ent_t { enum @@ -38,8 +36,18 @@ struct qse_dir_ent_t QSE_DIR_ENT_BLOCK, QSE_DIR_ENT_LINK } type; - qse_foff_t size; - const qse_char_t* name; + qse_foff_t size; + qse_char_t* name; +}; + +typedef struct qse_dir_ent_t qse_dir_ent_t; + +struct qse_dir_t +{ + QSE_DEFINE_COMMON_FIELDS (dir) + qse_dir_ent_t ent; + qse_char_t* curdir; + void* info; }; typedef struct qse_dir_t qse_dir_t; @@ -52,14 +60,22 @@ QSE_DEFINE_COMMON_FUNCTIONS (dir) qse_dir_t* qse_dir_open ( qse_mmgr_t* mmgr, - qse_size_t xtnsize, - const qse_char_t* name + qse_size_t xtnsize ); void qse_dir_close ( qse_dir_t* dir ); +int qse_dir_init ( + qse_dir_t* dir, + qse_mmgr_t* mmgr +); + +void qse_dir_fini ( + qse_dir_t* dir +); + qse_dir_ent_t* qse_dir_read ( qse_dir_t* dir ); diff --git a/qse/lib/cmn/path-basename.c b/qse/lib/cmn/path-basename.c index e2dcfe1e..c8da9093 100644 --- a/qse/lib/cmn/path-basename.c +++ b/qse/lib/cmn/path-basename.c @@ -21,16 +21,21 @@ #include +#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) +# define ISMSEP(c) ((c) == QSE_MT('/') || (c) == QSE_MT('\\')) +# define ISWSEP(c) ((c) == QSE_WT('/') || (c) == QSE_WT('\\')) +#else +# define ISMSEP(c) ((c) == QSE_MT('/')) +# define ISWSEP(c) ((c) == QSE_WT('/')) +#endif + const qse_mchar_t* qse_mbsbasename (const qse_mchar_t* path) { const qse_mchar_t* p, * last = QSE_NULL; for (p = path; *p != QSE_MT('\0'); p++) { - if (*p == QSE_MT('/')) last = p; - #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) - else if (*p == QSE_MT('\\')) last = p; - #endif + if (ISMSEP(*p)) last = p; } return (last == QSE_NULL)? path: (last + 1); @@ -42,10 +47,7 @@ const qse_wchar_t* qse_wcsbasename (const qse_wchar_t* path) for (p = path; *p != QSE_WT('\0'); p++) { - if (*p == QSE_WT('/')) last = p; - #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) - else if (*p == QSE_WT('\\')) last = p; - #endif + if (ISWSEP(*p)) last = p; } return (last == QSE_NULL)? path: (last + 1); diff --git a/qse/lib/cmn/str-dup.c b/qse/lib/cmn/str-dup.c index 32263921..d2199225 100644 --- a/qse/lib/cmn/str-dup.c +++ b/qse/lib/cmn/str-dup.c @@ -72,6 +72,27 @@ qse_mchar_t* qse_mbsxdup2 ( return tmp; } +qse_mchar_t* qse_mbsadup (const qse_mchar_t* str[], qse_mmgr_t* mmgr) +{ + qse_mchar_t* buf, * ptr; + qse_size_t i; + qse_size_t capa = 0; + + QSE_ASSERT (mmgr != QSE_NULL); + + for (i = 0; str[i]; i++) capa += qse_mbslen(str[i]); + + buf = (qse_mchar_t*) QSE_MMGR_ALLOC (mmgr, (capa+1)*QSE_SIZEOF(*buf)); + if (buf == QSE_NULL) return QSE_NULL; + + ptr = buf; + for (i = 0; str[i]; i++) ptr += qse_mbscpy (ptr, str[i]); + + return buf; +} + +/* --------------------------------------------------------------- */ + qse_wchar_t* qse_wcsdup (const qse_wchar_t* str, qse_mmgr_t* mmgr) { qse_wchar_t* tmp; @@ -124,3 +145,23 @@ qse_wchar_t* qse_wcsxdup2 ( qse_wcsncpy (tmp + len1, str2, len2); return tmp; } + +qse_wchar_t* qse_wcsadup (const qse_wchar_t* str[], qse_mmgr_t* mmgr) +{ + qse_wchar_t* buf, * ptr; + qse_size_t i; + qse_size_t capa = 0; + + QSE_ASSERT (mmgr != QSE_NULL); + + for (i = 0; str[i]; i++) capa += qse_wcslen(str[i]); + + buf = (qse_wchar_t*) QSE_MMGR_ALLOC (mmgr, (capa+1)*QSE_SIZEOF(*buf)); + if (buf == QSE_NULL) return QSE_NULL; + + ptr = buf; + for (i = 0; str[i]; i++) ptr += qse_wcscpy (ptr, str[i]); + + return buf; +} + diff --git a/qse/lib/fs/dir.c b/qse/lib/fs/dir.c index e232b968..052f0254 100644 --- a/qse/lib/fs/dir.c +++ b/qse/lib/fs/dir.c @@ -19,35 +19,36 @@ */ #include -#include "../cmn/mem.h" #include +#include +#include "../cmn/mem.h" #if defined(_WIN32) # include +#elif defined(__OS2__) +# error NOT IMPLEMENTED +#elif defined(__DOS__) +# error NOT IMPLEMENTED +#else +# include +# include #endif -struct qse_dir_t +typedef struct info_t info_t; +struct info_t { - QSE_DEFINE_COMMON_FIELDS (dir) - - qse_dir_ent_t ent; + qse_xstr_t name; #if defined(_WIN32) HANDLE handle; WIN32_FIND_DATA wfd; int no_more_files; -#else - #endif }; QSE_IMPLEMENT_COMMON_FUNCTIONS (dir) -int qse_dir_init (qse_dir_t* dir, qse_mmgr_t* mmgr, const qse_char_t* name); -void qse_dir_fini (qse_dir_t* dir); - -qse_dir_t* qse_dir_open ( - qse_mmgr_t* mmgr, qse_size_t xtnsize, const qse_char_t* name) +qse_dir_t* qse_dir_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) { qse_dir_t* dir; @@ -61,10 +62,10 @@ qse_dir_t* qse_dir_open ( if (mmgr == QSE_NULL) return QSE_NULL; } - dir = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(*dir)); + dir = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(*dir) + xtnsize); if (dir == QSE_NULL) return QSE_NULL; - if (qse_dir_init (dir, mmgr, name) <= -1) + if (qse_dir_init (dir, mmgr) <= -1) { QSE_MMGR_FREE (mmgr, dir); return QSE_NULL; @@ -79,49 +80,184 @@ void qse_dir_close (qse_dir_t* dir) QSE_MMGR_FREE (dir->mmgr, dir); } -int qse_dir_init (qse_dir_t* dir, qse_mmgr_t* mmgr, const qse_char_t* name) +int qse_dir_init (qse_dir_t* dir, qse_mmgr_t* mmgr) { -#if defined(_WIN32) - qse_char_t* dirname; -#endif - QSE_MEMSET (dir, 0, QSE_SIZEOF(*dir)); dir->mmgr = mmgr; + return 0; +} + +void qse_dir_fini (qse_dir_t* dir) +{ + info_t* info = dir->info; + if (info) + { + if (info->name.ptr) + { + QSE_ASSERT (info->name.len > 0); + QSE_MMGR_FREE (dir->mmgr, info->name.ptr); + info->name.ptr = QSE_NULL; + info->name.len = 0; + } #if defined(_WIN32) - dirname = qse_strdup2 (name, QSE_T("\\*"), dir->mmgr); + if (info->handle != INVALID_HANDLE_VALUE) + { + FindClose (info->handle); + info->handle = INVALID_HANDLE_VALUE; + } +#endif + + QSE_MMGR_FREE (dir->mmgr, info); + dir->info = QSE_NULL; + } + + if (dir->curdir) + { + QSE_MMGR_FREE (dir->mmgr, dir->curdir); + dir->curdir = QSE_NULL; + } +} + +static int is_absolute (const qse_char_t* name) +{ + if (name[0] == QSE_T('/')) return 1; +#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) + if (name[0] == QSE_T('\\')) return 1; + if (((name[0] >= QSE_T('A') && name[0] <= QSE_T('Z')) || + (name[0] >= QSE_T('a') && name[0] <= QSE_T('a'))) && + name[1] == QSE_T(':')) return 1; +#endif + return 0; +} + +int qse_dir_change (qse_dir_t* dir, const qse_char_t* name) +{ + info_t* info = dir->info; +#if defined(_WIN32) + qse_char_t* dirname; + HANDLE handle; + WIN32_FIND_DATA wfd; + const qse_char_t* tmp_name[4]; + qse_size_t idx; +#endif + + if (name[0] == QSE_T('\0')) + { + /* dir->errnum = QSE_DIR_EINVAL; */ + return -1; + } + + +/* TODO: if name is a relative path??? combine it with the current path + and canonicalize it to get the actual path */ + + if (info == QSE_NULL) + { + info = QSE_MMGR_ALLOC (dir->mmgr, QSE_SIZEOF(*info)); + if (info == QSE_NULL) return -1; + + QSE_MEMSET (info, 0, QSE_SIZEOF(*info)); +#if defined(_WIN32) + info->handle = INVALID_HANDLE_VALUE; +#endif + + dir->info = info; + } + +#if defined(_WIN32) + idx = 0; + if (!is_absolute(name) && dir->curdir) + tmp_name[idx++] = dir->curdir; + tmp_name[idx++] = name; + tmp_name[idx++] = QSE_T("\\ "); + tmp_name[idx] = QSE_NULL; + + dirname = qse_stradup (tmp_name, dir->mmgr); if (dirname == QSE_NULL) { /* dir->errnum = QSE_DIR_ENOMEM; */ return -1; } - dir->handle = FindFirstFile (dirname, &dir->wfd); - QSE_MMGR_FREE (dir->mmgr, dirname); - if (dir->handle == INVALID_HANDLE_VALUE) + idx = qse_canonpath (dirname, dirname); + /* Put the asterisk after canonicalization to prevent side-effects. + * otherwise, .\* would be transformed to * by qse_canonpath() */ + dirname[idx-1] = QSE_T('*'); + + handle = FindFirstFile (dirname, &wfd); + if (handle == INVALID_HANDLE_VALUE) { + /* dir->errnum = QSE_DIR_ESYSTEM; */ + QSE_MMGR_FREE (dir->mmgr, dirname); return -1; } + if (info->handle != INVALID_HANDLE_VALUE) + FindClose (info->handle); + + QSE_MEMSET (info, 0, QSE_SIZEOF(*info)); + info->handle = handle; + info->wfd = wfd; + + if (dir->curdir) QSE_MMGR_FREE (dir->mmgr, dir->curdir); + dirname[idx-1] = QSE_T('\0'); /* drop the asterisk */ + dir->curdir = dirname; + return 0; #else return -1; #endif } -void qse_dir_fini (qse_dir_t* dir) +static int set_entry_name (qse_dir_t* dir, const qse_char_t* name) { -#if defined(_WIN32) - FindClose (dir->handle); -#endif + info_t* info = dir->info; + qse_size_t len; + + QSE_ASSERT (info != QSE_NULL); + + len = qse_strlen (name); + if (len > info->name.len) + { + qse_char_t* tmp; + +/* TOOD: round up len to the nearlest multiples of something (32, 64, ??)*/ + tmp = QSE_MMGR_REALLOC ( + dir->mmgr, + info->name.ptr, + (len + 1) * QSE_SIZEOF(*tmp) + ); + if (tmp == QSE_NULL) + { + /* dir->errnum = QSE_DIR_ENOMEM; */ + return -1; + } + + info->name.len = len; + info->name.ptr = tmp; + } + + qse_strcpy (info->name.ptr, name); + dir->ent.name = info->name.ptr; + return 0; } qse_dir_ent_t* qse_dir_read (qse_dir_t* dir) { -#if defined(_WIN32) - if (dir->no_more_files) return QSE_NULL; + info_t* info = dir->info; + if (info == QSE_NULL) return QSE_NULL; - if (dir->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) +#if defined(_WIN32) + if (info->no_more_files) + { + /* + dir->errnum = QSE_DIR_ENOENT; + */ + return QSE_NULL; + } + + if (info->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { dir->ent.size = 0; dir->ent.type = QSE_DIR_ENT_DIRECTORY; @@ -129,19 +265,18 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir) else { LARGE_INTEGER li; - li.LowPart = dir->wfd.nFileSizeLow; - li.HighPart = dir->wfd.nFileSizeHigh; + li.LowPart = info->wfd.nFileSizeLow; + li.HighPart = info->wfd.nFileSizeHigh; dir->ent.size = li.QuadPart; dir->ent.type = QSE_DIR_ENT_UNKNOWN; } -// TODO: proper management... - dir->ent.name = qse_strdup (dir->wfd.cFileName, dir->mmgr); + if (set_entry_name (dir, info->wfd.cFileName) <= -1) return QSE_NULL; - if (FindNextFile (dir->handle, &dir->wfd) == FALSE) + if (FindNextFile (info->handle, &info->wfd) == FALSE) { /*if (GetLastError() == ERROR_NO_MORE_FILES) */ - dir->no_more_files = 1; + info->no_more_files = 1; } #endif @@ -153,13 +288,3 @@ int qse_dir_rewind (qse_dir_t* dir) return 0; } -#if 0 -int qse_dir_change (qse_dir_t* dir, const qse_char_t* name) -{ -#if defined(_WIN32) - qse_strxdup (dir->current, -#else - return -1; -#endif -} -#endif diff --git a/qse/samples/cmn/path01.c b/qse/samples/cmn/path01.c index 60cd1904..02169721 100644 --- a/qse/samples/cmn/path01.c +++ b/qse/samples/cmn/path01.c @@ -16,16 +16,22 @@ int path_main (int argc, qse_char_t* argv[]) return -1; } +/* canon = QSE_MMGR_ALLOC (QSE_MMGR_GETDFL(), (qse_strlen(argv[1]) + 1) * QSE_SIZEOF(*canon)); if (canon == QSE_NULL) { qse_fprintf (QSE_STDERR, QSE_T("Error: out of memory\n")); return -1; } - len = qse_canonpath (argv[1], canon); qse_printf (QSE_T("[%s] => [%s] %d chars\n"), argv[1], canon, (int)len); - QSE_MMGR_FREE (QSE_MMGR_GETDFL(), canon); + QSE_MMGR_FREE (QSE_MMGR_GETDFL(), canon); +*/ + + qse_printf (QSE_T("[%s] => "), argv[1]); + len = qse_canonpath (argv[1], argv[1]); + qse_printf (QSE_T("[%s] %d chars\n"), argv[1], (int)len); + return 0; } diff --git a/qse/samples/fs/dir01.c b/qse/samples/fs/dir01.c index a6c67ab7..faf5d605 100644 --- a/qse/samples/fs/dir01.c +++ b/qse/samples/fs/dir01.c @@ -3,24 +3,19 @@ #include #include -int dir_main (int argc, qse_char_t* argv[]) +static void list (qse_dir_t* dir, const qse_char_t* name) { - int n; - qse_dir_t* dir; qse_dir_ent_t* ent; - if (argc != 2) + if (qse_dir_change (dir, name) <= -1) { - qse_fprintf (QSE_STDERR, QSE_T("Usage: %s \n"), argv[0]); - return -1; - } + qse_fprintf (QSE_STDERR, QSE_T("Error: Cannot change directory to %s\n"), name); + return; + } - dir = qse_dir_open (QSE_NULL, 0, argv[1]); - if (dir == QSE_NULL) - { - qse_fprintf (QSE_STDERR, QSE_T("Error: Cannot open directory\n"), argv[1]); - return -1; - } + qse_printf (QSE_T("----------------------------------------------------------------\n"), dir->curdir); + qse_printf (QSE_T("CURRENT DIRECTORY: [%s]\n"), dir->curdir); + qse_printf (QSE_T("----------------------------------------------------------------\n"), dir->curdir); do { @@ -34,6 +29,29 @@ int dir_main (int argc, qse_char_t* argv[]) } while (1); +} + +int dir_main (int argc, qse_char_t* argv[]) +{ + int n; + qse_dir_t* dir; + + if (argc != 2) + { + qse_fprintf (QSE_STDERR, QSE_T("Usage: %s \n"), argv[0]); + return -1; + } + + dir = qse_dir_open (QSE_NULL, 0); + if (dir == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("Error: Cannot open directory\n"), argv[1]); + return -1; + } + + list (dir, argv[1]); + list (dir, QSE_T("..")); + qse_dir_close (dir); return n; }