summaryrefslogtreecommitdiff
path: root/src/scandir_win32.c
diff options
context:
space:
mode:
authorGreg Ercolano <erco@seriss.com>2020-07-10 21:49:00 -0700
committerAlbrecht Schlosser <albrechts.fltk@online.de>2020-07-14 12:52:56 +0200
commit0693c70f577624e66fd660a888f2d2bcd3fc180b (patch)
treee3b4161c0516ebacaf84e9b58852f48d4e4b6357 /src/scandir_win32.c
parent9925b0f12852dc37fb7fb773a525486c258d2c62 (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.c101
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;
}