diff options
| author | Greg Ercolano <erco@seriss.com> | 2020-07-10 21:49:00 -0700 |
|---|---|---|
| committer | Albrecht Schlosser <albrechts.fltk@online.de> | 2020-07-14 12:52:56 +0200 |
| commit | 0693c70f577624e66fd660a888f2d2bcd3fc180b (patch) | |
| tree | e3b4161c0516ebacaf84e9b58852f48d4e4b6357 /src/scandir_win32.c | |
| parent | 9925b0f12852dc37fb7fb773a525486c258d2c62 (diff) | |
First pass at fixing issue 99
A lot of code touched because low level functions needed to pass up
error messages reliably, and this had to propagate up the entire
driver hierarchy.
Tested OK *in English* on:
> Linux
> OSX 10.10.x
> Windows VS2017
> Windows mingw64
I have no way to test on Android, but it might work.
TODO: Needs testing in other languages to verify proper UTF8 error messages,
esp. with Windows VS, due to complexities with FormatMessage() -- see get_ms_errmsg()
Diffstat (limited to 'src/scandir_win32.c')
| -rw-r--r-- | src/scandir_win32.c | 101 |
1 files changed, 74 insertions, 27 deletions
diff --git a/src/scandir_win32.c b/src/scandir_win32.c index 2663e30dc..822770234 100644 --- a/src/scandir_win32.c +++ b/src/scandir_win32.c @@ -15,16 +15,59 @@ */ #ifndef __CYGWIN__ -/* Emulation of POSIX scandir() call */ +/* Emulation of POSIX scandir() call with error messages */ #include <FL/platform_types.h> #include <FL/fl_utf8.h> #include "flstring.h" #include <windows.h> #include <stdlib.h> +/* Get error message string for last failed WIN32 operation + * in 'errmsg' (if non-NULL), string size limited to errmsg_sz. + * + * NOTE: Copied from: fluid/ExternalCodeEditor_WIN32.cxx + * + * TODO: Verify works in different languages, with utf8 strings. + * TODO: This should be made available globally to the FLTK internals, in case + * other parts of FLTK need OS error messages.. + */ +static void get_ms_errmsg(char *errmsg, int errmsg_sz) { + DWORD lastErr = GetLastError(); + DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM; + DWORD langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); + LPSTR mbuf = 0; + + // Early exit if parent doesn't want an errmsg + if (!errmsg || errmsg_sz<=0 ) return; + // Get error message from Windows + DWORD size = FormatMessageA(flags, 0, lastErr, langid, (LPSTR)&mbuf, 0, NULL); + if ( size == 0 ) { + fl_snprintf(errmsg, errmsg_sz, "Error #%lu", (unsigned long)lastErr); + } else { + int cnt = 0; + /* Copy mbuf -> errmsg, remove '\r's -- they screw up fl_alert()) */ + for ( char *src=mbuf, *dst=errmsg; 1; src++ ) { + if ( *src == '\0' ) { *dst = '\0'; break; } + if ( *src != '\r' ) { + if ( ++cnt >= errmsg_sz ) { *dst = '\0'; break; } // trunc on overflow + *dst++ = *src; + } + } + LocalFree(mbuf); /* Free the buffer allocated by the system */ + } +} + +/* + * This could use some docs. + * + * Returns -1 on error, errmsg returns error string (if non-NULL) + */ int fl_scandir(const char *dirname, struct dirent ***namelist, int (*select)(struct dirent *), - int (*compar)(struct dirent **, struct dirent **)) { + int (*compar)(struct dirent **, struct dirent **), + char *errmsg, int errmsg_sz) { int len; char *findIn, *d, is_dir = 0; WIN32_FIND_DATAW findw; @@ -33,9 +76,14 @@ int fl_scandir(const char *dirname, struct dirent ***namelist, struct dirent **dir = 0, *selectDir; unsigned long ret; + if (errmsg && errmsg_sz>0) errmsg[0] = '\0'; len = (int) strlen(dirname); findIn = (char *)malloc((size_t)(len+10)); - if (!findIn) return -1; + if (!findIn) { + /* win32 malloc() docs: "malloc sets errno to ENOMEM if allocation fails" */ + if (errmsg) fl_snprintf(errmsg, errmsg_sz, "%s", strerror(errno)); + return -1; + } strcpy(findIn, dirname); /* #if defined(__GNUC__) */ @@ -49,7 +97,7 @@ int fl_scandir(const char *dirname, struct dirent ***namelist, if ((len>1) && (d[-1]=='.') && (d[-2]=='\\')) { d[-1] = '*'; is_dir = 1; } if (!is_dir) { /* this file may still be a directory that we need to list */ DWORD attr = GetFileAttributes(findIn); - if (attr&FILE_ATTRIBUTE_DIRECTORY) + if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY) ) strcpy(d, "\\*"); } { /* Create a block to limit the scope while we find the initial "wide" filename */ @@ -64,55 +112,54 @@ int fl_scandir(const char *dirname, struct dirent ***namelist, h = FindFirstFileW(wbuf, &findw); /* get a handle to the first filename in the search */ free(wbuf); /* release the "wide" buffer before the pointer goes out of scope */ } + if (h==INVALID_HANDLE_VALUE) { free(findIn); ret = GetLastError(); if (ret != ERROR_NO_MORE_FILES) { nDir = -1; + get_ms_errmsg(errmsg, errmsg_sz); /* return OS error msg */ } *namelist = dir; return nDir; } do { - int l = (int) wcslen(findw.cFileName); - int dstlen = l * 5 + 1; - selectDir=(struct dirent*)malloc(sizeof(struct dirent)+dstlen); + int l = (int) wcslen(findw.cFileName); + int dstlen = l * 5 + 1; + selectDir=(struct dirent*)malloc(sizeof(struct dirent)+dstlen); - /* l = fl_unicode2utf(findw.cFileName, l, selectDir->d_name); */ - l = fl_utf8fromwc(selectDir->d_name, dstlen, findw.cFileName, l); + /* l = fl_unicode2utf(findw.cFileName, l, selectDir->d_name); */ + l = fl_utf8fromwc(selectDir->d_name, dstlen, findw.cFileName, l); - selectDir->d_name[l] = 0; - if (findw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - /* Append a trailing slash to directory names... */ - strcat(selectDir->d_name, "/"); - } - if (!select || (*select)(selectDir)) { - if (nDir==NDir) { + selectDir->d_name[l] = 0; + if (findw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + /* Append a trailing slash to directory names... */ + strcat(selectDir->d_name, "/"); + } + if (!select || (*select)(selectDir)) { + if (nDir==NDir) { struct dirent **tempDir = (struct dirent **)calloc(sizeof(struct dirent*), (size_t)(NDir+33)); if (NDir) memcpy(tempDir, dir, sizeof(struct dirent*)*NDir); if (dir) free(dir); dir = tempDir; NDir += 32; - } - dir[nDir] = selectDir; - nDir++; - dir[nDir] = 0; - } else { - free(selectDir); - } - } while (FindNextFileW(h, &findw)); + } + dir[nDir] = selectDir; + nDir++; + dir[nDir] = 0; + } else { + free(selectDir); + } + } while (FindNextFileW(h, &findw)); ret = GetLastError(); if (ret != ERROR_NO_MORE_FILES) { /* don't return an error code, because the dir list may still be valid up to this point */ } FindClose(h); - free (findIn); - if (compar) qsort(dir, (size_t)nDir, sizeof(*dir), (int(*)(const void*, const void*))compar); - *namelist = dir; return nDir; } |
