diff --git a/qse/lib/cmn/path-canon.c b/qse/lib/cmn/path-canon.c index 69320aa7..0836e6da 100644 --- a/qse/lib/cmn/path-canon.c +++ b/qse/lib/cmn/path-canon.c @@ -28,6 +28,23 @@ #define ISSEPNIL(c) (ISSEP(c) || ((c) == QSE_T('\0'))) +#define ISDRIVE(s) \ + (((s[0] >= QSE_T('A') && s[0] <= QSE_T('Z')) || \ + (s[0] >= QSE_T('a') && s[0] <= QSE_T('a'))) && \ + s[1] == QSE_T(':')) + +int qse_isabspath (const qse_char_t* path) +{ + if (ISSEP(path[0])) return 1; +#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) + /* a drive like c:tmp is absolute in positioning the drive. + * but the path within the drive is kind of relative */ + if (ISDRIVE(path)) return 1; +#endif + return 0; + +} + qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon) { const qse_char_t* ptr; @@ -39,9 +56,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon) dst = canon; #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) - if (((ptr[0] >= QSE_T('A') && ptr[0] <= QSE_T('Z')) || - (ptr[0] >= QSE_T('a') && ptr[0] <= QSE_T('z'))) && - ptr[1] == QSE_T(':')) + if (ISDRIVE(ptr)) { /* handle drive letter */ *dst++ = *ptr++; /* drive letter */ diff --git a/qse/lib/fs/dir.c b/qse/lib/fs/dir.c index 052f0254..83cc5907 100644 --- a/qse/lib/fs/dir.c +++ b/qse/lib/fs/dir.c @@ -43,6 +43,10 @@ struct info_t HANDLE handle; WIN32_FIND_DATA wfd; int no_more_files; +#elif defined(__OS2__) +#elif defined(__DOS__) +#else + DIR* handle; #endif }; @@ -89,7 +93,9 @@ int qse_dir_init (qse_dir_t* dir, qse_mmgr_t* mmgr) void qse_dir_fini (qse_dir_t* dir) { - info_t* info = dir->info; + info_t* info; + + info = dir->info; if (info) { if (info->name.ptr) @@ -106,6 +112,16 @@ void qse_dir_fini (qse_dir_t* dir) FindClose (info->handle); info->handle = INVALID_HANDLE_VALUE; } +#elif defined(__OS2__) +# error NOT IMPLEMENTED +#elif defined(__DOS__) +# error NOT IMPLEMENTED +#else + if (info->handle) + { + closedir (info->handle); + info->handle = QSE_NULL; + } #endif QSE_MMGR_FREE (dir->mmgr, info); @@ -119,27 +135,23 @@ void qse_dir_fini (qse_dir_t* dir) } } -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; + info_t* info; + +#if defined(_WIN32) HANDLE handle; WIN32_FIND_DATA wfd; const qse_char_t* tmp_name[4]; qse_size_t idx; +#elif defined(__OS2__) +# error NOT IMPLEMENTED +#elif defined(__DOS__) +# error NOT IMPLEMENTED +#else + DIR* handle; + qse_mchar_t* mbsdirname; #endif if (name[0] == QSE_T('\0')) @@ -148,10 +160,7 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name) return -1; } - -/* TODO: if name is a relative path??? combine it with the current path - and canonicalize it to get the actual path */ - + info = dir->info; if (info == QSE_NULL) { info = QSE_MMGR_ALLOC (dir->mmgr, QSE_SIZEOF(*info)); @@ -161,13 +170,12 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name) #if defined(_WIN32) info->handle = INVALID_HANDLE_VALUE; #endif - dir->info = info; } #if defined(_WIN32) idx = 0; - if (!is_absolute(name) && dir->curdir) + if (!qse_isabspath(name) && dir->curdir) tmp_name[idx++] = dir->curdir; tmp_name[idx++] = name; tmp_name[idx++] = QSE_T("\\ "); @@ -205,19 +213,85 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name) dir->curdir = dirname; return 0; +#elif defined(__OS2__) +# error NOT IMPLEMENTED +#elif defined(__DOS__) +# error NOT IMPLEMENTED #else - return -1; + dirname = qse_strdup (name, dir->mmgr); + if (dirname == QSE_NULL) + { + /* dir->errnum = QSE_DIR_ENOMEM; */ + return -1; + } + + qse_canonpath (dirname, dirname); + +#if defined(QSE_CHAR_IS_MCHAR) + mbsdirname = dirname; +#else + mbsdirname = qse_wcstombsdup (name, dir->mmgr); + if (mbsdirname == QSE_NULL) + { + /* dir->errnum = QSE_DIR_ENOMEM */ + QSE_MMGR_FREE (dir->mmgr, dirname); + return -1; + } +#endif + + handle = opendir (mbsdirname); + +#if defined(QSE_CHAR_IS_MCHAR) + /* do nothing */ +#else + QSE_MMGR_FREE (dir->mmgr, mbsdirname); +#endif + + if (handle == QSE_NULL) + { + /* dir->errnum = QSE_DIR... */ + QSE_MMGR_FREE (dir->mmgr, dirname); + return -1; + } + + if (info->handle) closedir (info->handle); + info->handle = handle; + + if (dir->curdir) QSE_MMGR_FREE (dir->mmgr, dir->curdir); + dir->curdir = dirname; + + return 0; #endif } +#if defined(QSE_CHAR_IS_MCHAR) || defined(_WIN32) static int set_entry_name (qse_dir_t* dir, const qse_char_t* name) +#else +static int set_entry_name (qse_dir_t* dir, const qse_mchar_t* name) +#endif { - info_t* info = dir->info; + info_t* info; qse_size_t len; + info = dir->info; QSE_ASSERT (info != QSE_NULL); +#if defined(QSE_CHAR_IS_MCHAR) || defined(_WIN32) len = qse_strlen (name); +#else + { + qse_size_t mlen; + + /* TODO: ignore MBWCERR */ + mlen = qse_mbstowcslen (name, &len); + if (name[mlen] != QSE_MT('\0')) + { + /* invalid name ??? */ + return -1; + } + } +#endif + if (len > info->name.len) { qse_char_t* tmp; @@ -238,17 +312,32 @@ static int set_entry_name (qse_dir_t* dir, const qse_char_t* name) info->name.ptr = tmp; } +#if defined(QSE_CHAR_IS_MCHAR) || defined(_WIN32) qse_strcpy (info->name.ptr, name); +#else + len++; + qse_mbstowcs (name, info->name.ptr, &len); +#endif dir->ent.name = info->name.ptr; return 0; } qse_dir_ent_t* qse_dir_read (qse_dir_t* dir) { - info_t* info = dir->info; - if (info == QSE_NULL) return QSE_NULL; + + info_t* info; + + info = dir->info; + if (info == QSE_NULL) + { + /* + dir->errnum = NO CHANGE DIR YET; + */ + return QSE_NULL; + } #if defined(_WIN32) + if (info->no_more_files) { /* @@ -257,6 +346,10 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir) return QSE_NULL; } + /* 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; + if (info->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { dir->ent.size = 0; @@ -271,15 +364,45 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir) dir->ent.type = QSE_DIR_ENT_UNKNOWN; } - if (set_entry_name (dir, info->wfd.cFileName) <= -1) return QSE_NULL; - if (FindNextFile (info->handle, &info->wfd) == FALSE) { /*if (GetLastError() == ERROR_NO_MORE_FILES) */ info->no_more_files = 1; } -#endif +#elif defined(__OS2__) +# error NOT IMPLEMENTED +#elif defined(__DOS__) +# error NOT IMPLEMENTED +#else + struct dirent* ent; + ent = readdir (info->handle); + if (ent == QSE_NULL) + { + /* TODO: dir->errnum = ... */ + return QSE_NULL; + } + + if (set_entry_name (dir, ent->d_name) <= -1) return QSE_NULL; + + #if defined(HAVE_STRUCT_DIRENT_D_TYPE) + switch (ent->d_type) + { + case DT_DIR: + dir->ent.size = 0; + dir->ent.type = QSE_DIR_ENT_DIRECTORY; + break; + + default: + dir->ent.size = 0; + dir->ent.type = QSE_DIR_ENT_UNKNOWN; + break; + } + + #else + /* call lstat??? */ + #endif +#endif return &dir->ent; }