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()
This commit is contained in:
Greg Ercolano 2020-07-10 21:49:00 -07:00 committed by Albrecht Schlosser
parent 9925b0f128
commit 0693c70f57
20 changed files with 339 additions and 156 deletions

View File

@ -40,6 +40,7 @@ class FL_EXPORT Fl_File_Browser : public Fl_Browser {
const char *directory_;
uchar iconsize_;
const char *pattern_;
const char *errmsg_;
int full_height() const;
int item_height(void *) const;
@ -50,11 +51,8 @@ class FL_EXPORT Fl_File_Browser : public Fl_Browser {
public:
enum { FILES, DIRECTORIES };
/**
The constructor creates the Fl_File_Browser widget at the specified position and size.
The destructor destroys the widget and frees all memory that has been allocated.
*/
Fl_File_Browser(int, int, int, int, const char * = 0);
~Fl_File_Browser();
/** Sets or gets the size of the icons. The default size is 20 pixels. */
uchar iconsize() const { return (iconsize_); };
@ -73,16 +71,7 @@ public:
function in FLTK.
*/
const char *filter() const { return (pattern_); };
/**
Loads the specified directory into the browser. If icons have been
loaded then the correct icon is associated with each file in the list.
<P>The sort argument specifies a sort function to be used with
fl_filename_list().
*/
int load(const char *directory, Fl_File_Sort_F *sort = fl_numericsort);
Fl_Fontsize textsize() const { return Fl_Browser::textsize(); };
void textsize(Fl_Fontsize s) { Fl_Browser::textsize(s); iconsize_ = (uchar)(3 * s / 2); };
@ -100,6 +89,11 @@ public:
shown.
*/
void filetype(int t) { filetype_ = t; };
void errmsg(const char *emsg);
/**
Returns OS error messages, or NULL if none. Use when advised.
*/
const char* errmsg() const { return errmsg_; }
};
#endif // !_Fl_File_Browser_H_

View File

@ -85,6 +85,7 @@ private:
Fl_File_Browser *fileList;
inline void cb_fileList_i(Fl_File_Browser*, void*);
static void cb_fileList(Fl_File_Browser*, void*);
Fl_Box *errorBox;
Fl_Box *previewBox;
public:
Fl_Check_Button *previewButton;
@ -231,6 +232,8 @@ private:
Fl_Widget* ext_group;
public:
Fl_Widget* add_extra(Fl_Widget* gr);
protected:
void show_error_box(int val);
};
FL_EXPORT char *fl_dir_chooser(const char *message,const char *fname,int relative=0);
FL_EXPORT char *fl_file_chooser(const char *message,const char *pat,const char *fname,int relative=0);

View File

@ -354,10 +354,10 @@ Fl_File_Browser::item_draw(void *p, // I - List item data
}
//
// 'Fl_File_Browser::Fl_File_Browser()' - Create a Fl_File_Browser widget.
//
/**
The constructor creates the Fl_File_Browser widget at the specified position and size.
The destructor destroys the widget and frees all memory that has been allocated.
*/
Fl_File_Browser::Fl_File_Browser(int X, // I - Upper-lefthand X coordinate
int Y, // I - Upper-lefthand Y coordinate
int W, // I - Width in pixels
@ -370,13 +370,40 @@ Fl_File_Browser::Fl_File_Browser(int X, // I - Upper-lefthand X coordina
directory_ = "";
iconsize_ = (uchar)(3 * textsize() / 2);
filetype_ = FILES;
errmsg_ = NULL;
}
//
// 'Fl_File_Browser::load()' - Load a directory into the browser.
//
// DTOR
Fl_File_Browser::~Fl_File_Browser() {
errmsg(NULL); // free()s prev errmsg, if any
}
/**
Sets OS error message to a string, which can be NULL.
Frees previous if any.
void errmsg(const char *emsg);
*/
void Fl_File_Browser::errmsg(const char* emsg) {
if ( errmsg_ ) { free((void*)errmsg_); errmsg_ = NULL; }
errmsg_ = emsg ? strdup(emsg) : NULL;
}
/**
Loads the specified directory into the browser. If icons have been
loaded then the correct icon is associated with each file in the list.
If directory is "", all mount points (unix) or drive letters (Windows)
are listed.
The sort argument specifies a sort function to be used with
fl_filename_list().
Return value is the number of filename entries, or 0 if none.
On error, 0 is returned, and errmsg() has OS error string if non-NULL.
*/
int // O - Number of files loaded
Fl_File_Browser::load(const char *directory,// I - Directory to load
Fl_File_Sort_F *sort) // I - Sort function to use
@ -387,6 +414,7 @@ Fl_File_Browser::load(const char *directory,// I - Directory to load
char filename[4096]; // Current file
Fl_File_Icon *icon; // Icon to use
errmsg(NULL); // clear errors first
// printf("Fl_File_Browser::load(\"%s\")\n", directory);
@ -394,11 +422,12 @@ Fl_File_Browser::load(const char *directory,// I - Directory to load
directory_ = directory;
if (!directory)
return (0);
if (!directory) {
errmsg("NULL directory specified");
return 0;
}
if (directory_[0] == '\0')
{
if (directory_[0] == '\0') {
//
// No directory specified; for UNIX list all mount points. For DOS
// list all valid drive letters...
@ -406,21 +435,25 @@ Fl_File_Browser::load(const char *directory,// I - Directory to load
if ((icon = Fl_File_Icon::find("any", Fl_File_Icon::DEVICE)) == NULL)
icon = Fl_File_Icon::find("any", Fl_File_Icon::DIRECTORY);
num_files = Fl::system_driver()->file_browser_load_filesystem(this, filename, (int)sizeof(filename), icon);
}
else
{
dirent **files; // Files in in directory
//
// Build the file list...
//
num_files = Fl::system_driver()->file_browser_load_directory(directory_, filename, sizeof(filename), &files, sort);
if (num_files <= 0)
return (0);
} else {
dirent **files; // Files in in directory
char emsg[1024] = "";
// Build the file list, check for errors
num_files = Fl::system_driver()->file_browser_load_directory(directory_,
filename, sizeof(filename),
&files, sort,
emsg, sizeof(emsg));
// printf("Fl_File_Browser::load(dir='%s',filename='%s'): failed, emsg='%s'\n", directory_, filename, emsg);
if (num_files <= 0) {
errmsg(emsg);
return 0;
}
for (i = 0, num_dirs = 0; i < num_files; i ++) {
if (strcmp(files[i]->d_name, "./")) {
snprintf(filename, sizeof(filename), "%s/%s", directory_,
files[i]->d_name);
fl_snprintf(filename, sizeof(filename), "%s/%s", directory_, files[i]->d_name);
icon = Fl_File_Icon::find(filename);
if ((icon && icon->type() == Fl_File_Icon::DIRECTORY) ||

View File

@ -197,9 +197,18 @@ Fl_File_Chooser::Fl_File_Chooser(const char *d, const char *p, int t, const char
o->callback((Fl_Callback*)cb_);
{ fileList = new Fl_File_Browser(10, 45, 295, 225);
fileList->type(2);
fileList->box(FL_DOWN_BOX);
fileList->callback((Fl_Callback*)cb_fileList);
fileList->window()->hotspot(fileList);
} // Fl_File_Browser* fileList
{ errorBox = new Fl_Box(10, 45, 295, 225, "dynamic error display");
errorBox->box(FL_DOWN_BOX);
errorBox->color(FL_BACKGROUND2_COLOR);
errorBox->labelsize(18);
errorBox->labelcolor((Fl_Color)1);
errorBox->align(Fl_Align(133|FL_ALIGN_INSIDE));
errorBox->hide();
} // Fl_Box* errorBox
{ previewBox = new Fl_Box(305, 45, 175, 225, "?");
previewBox->box(FL_DOWN_BOX);
previewBox->labelsize(100);
@ -471,3 +480,17 @@ Fl_Widget* Fl_File_Chooser::add_extra(Fl_Widget* gr) {
}
return ret;
}
/**
Show error box if val=1, hide if val=0
*/
void Fl_File_Chooser::show_error_box(int val) {
if ( val ) {
errorBox->color(fileList->color()); // inherit fileList's bg color
errorBox->show();
fileList->hide();
} else {
errorBox->hide();
fileList->show();
}
}

View File

@ -66,7 +66,8 @@ class FL_EXPORT Fl_File_Chooser {open
}
decl {void update_preview();} {private local
}
Function {Fl_File_Chooser(const char *d, const char *p, int t, const char *title)} {} {
Function {Fl_File_Chooser(const char *d, const char *p, int t, const char *title)} {open
} {
code {if (!prefs_) {
prefs_ = new Fl_Preferences(Fl_Preferences::CORE_USER, "fltk.org", "filechooser");
}} {}
@ -77,11 +78,11 @@ class FL_EXPORT Fl_File_Chooser {open
fileList->deselect();
Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this);
window->hide();} open
private xywh {507 327 490 380} type Double hide resizable
private xywh {1171 438 490 380} type Double resizable
code0 {if (title) window->label(title);}
code1 {\#include <stdio.h>}
code2 {\#include <stdlib.h>}
code3 {\#include <string.h>} modal
code3 {\#include <string.h>} modal visible
} {
Fl_Group {} {open
private xywh {10 10 470 25}
@ -106,14 +107,18 @@ window->hide();} open
}
}
Fl_Tile {} {
callback {update_preview();}
callback {update_preview();} open
private xywh {10 45 470 225} resizable
} {
Fl_File_Browser fileList {
callback {fileListCB();}
private xywh {10 45 295 225} type Hold hotspot
private xywh {10 45 295 225} type Hold box DOWN_BOX hotspot
code0 {\#include <FL/Fl_File_Browser.H>}
}
Fl_Box errorBox {
label {dynamic error display} selected
private xywh {10 45 295 225} box DOWN_BOX color 7 labelsize 18 labelcolor 1 align 149 hide
}
Fl_Box previewBox {
label {?}
private xywh {305 45 175 225} box DOWN_BOX labelsize 100 align 80
@ -349,7 +354,7 @@ okButton->parent()->init_sizes();} {}
} {
code {fileList->textfont(f);} {}
}
Function {textfont()} {selected return_type Fl_Font
Function {textfont()} {return_type Fl_Font
} {
code {return (fileList->textfont());} {}
}
@ -475,6 +480,18 @@ window->resizable(svres);} {}
}
code {return ret;} {}
}
Function {show_error_box(int val)} {
comment {Show error box if val=1, hide if val=0} open protected return_type void
} {
code {if ( val ) {
errorBox->color(fileList->color()); // inherit fileList's bg color
errorBox->show();
fileList->hide();
} else {
errorBox->hide();
fileList->show();
}} {}
}
}
decl {FL_EXPORT char *fl_dir_chooser(const char *message,const char *fname,int relative=0);} {public local

View File

@ -1020,17 +1020,15 @@ void Fl_File_Chooser::preview(int e)
Fl_Group *p = previewBox->parent();
if (e) {
int w = p->w() * 2 / 3;
fileList->resize(fileList->x(), fileList->y(),
w, fileList->h());
previewBox->resize(fileList->x()+w, previewBox->y(),
p->w()-w, previewBox->h());
fileList->resize(fileList->x(), fileList->y(), w, fileList->h());
errorBox->resize(errorBox->x(), errorBox->y(), w, errorBox->h());
previewBox->resize(fileList->x()+w, previewBox->y(), p->w()-w, previewBox->h());
previewBox->show();
update_preview();
} else {
fileList->resize(fileList->x(), fileList->y(),
p->w(), fileList->h());
previewBox->resize(p->x()+p->w(), previewBox->y(),
0, previewBox->h());
fileList->resize(fileList->x(), fileList->y(), p->w(), fileList->h());
errorBox->resize(errorBox->x(), errorBox->y(), p->w(), errorBox->h());
previewBox->resize(p->x()+p->w(), previewBox->y(), 0, previewBox->h());
previewBox->hide();
}
p->init_sizes();
@ -1070,7 +1068,14 @@ Fl_File_Chooser::rescan()
okButton->deactivate();
// Build the file list...
fileList->load(directory_, sort);
if ( fileList->load(directory_, sort) <= 0 ) {
if ( fileList->errmsg() ) errorBox->label(fileList->errmsg()); // show OS errormsg when possible
else errorBox->label("No files found...");
show_error_box(1);
} else {
show_error_box(0);
}
if (Fl::system_driver()->dot_file_hidden() && !showHiddenButton->value()) remove_hidden_files();
// Update the preview box...
update_preview();
@ -1094,7 +1099,13 @@ void Fl_File_Chooser::rescan_keep_filename()
strlcpy(pathname, fn, sizeof(pathname));
// Build the file list...
fileList->load(directory_, sort);
if (fileList->load(directory_, sort) <= 0) {
if ( fileList->errmsg() ) errorBox->label(fileList->errmsg()); // show OS errormsg when possible
else errorBox->label("No files found...");
show_error_box(1);
} else {
show_error_box(0);
}
if (Fl::system_driver()->dot_file_hidden() && !showHiddenButton->value()) remove_hidden_files();
// Update the preview box...
update_preview();

View File

@ -128,7 +128,9 @@ public:
virtual int event_key(int k) {return 0;}
virtual int get_key(int k) {return 0;}
// implement scandir-like function
virtual int filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) ) {return -1;}
virtual int filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg=NULL, int errmsg_sz=0) {return -1;}
// the default implementation of filename_expand() may be enough
virtual int filename_expand(char *to, int tolen, const char *from);
// to implement
@ -162,7 +164,9 @@ public:
// implement to support Fl_File_Browser::load()
virtual int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon) {return 0;}
// the default implementation of file_browser_load_directory() should be enough
virtual int file_browser_load_directory(const char *directory, char *filename, size_t name_size, dirent ***pfiles, Fl_File_Sort_F *sort);
virtual int file_browser_load_directory(const char *directory, char *filename, size_t name_size,
dirent ***pfiles, Fl_File_Sort_F *sort,
char *errmsg=NULL, int errmsg_sz=0);
// implement to support Fl_Preferences
virtual void newUUID(char *uuidBuffer) { uuidBuffer[0] = 0; }
// implement to support Fl_Preferences

View File

@ -449,9 +449,11 @@ int Fl_System_Driver::filename_expand(char *to,int tolen, const char *from) {
}
int Fl_System_Driver::file_browser_load_directory(const char *directory, char *filename,
size_t name_size, dirent ***pfiles, Fl_File_Sort_F *sort)
size_t name_size, dirent ***pfiles,
Fl_File_Sort_F *sort,
char *errmsg, int errmsg_sz)
{
return filename_list(directory, pfiles, sort);
return filename_list(directory, pfiles, sort, errmsg, errmsg_sz);
}
int Fl_System_Driver::file_type(const char *filename)

View File

@ -70,7 +70,9 @@ public:
// these 2 are in Fl_get_key_win32.cxx
virtual int event_key(int k);
virtual int get_key(int k);
virtual int filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) );
virtual int filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg, int errmsg_sz);
virtual int filename_expand(char *to,int tolen, const char *from);
virtual int filename_relative(char *to, int tolen, const char *from, const char *base);
virtual int filename_absolute(char *to, int tolen, const char *from);
@ -80,7 +82,9 @@ public:
virtual int open_uri(const char *uri, char *msg, int msglen);
virtual int use_recent_tooltip_fix() {return 1;}
virtual int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon);
virtual int file_browser_load_directory(const char *directory, char *filename, size_t name_size, dirent ***pfiles, Fl_File_Sort_F *sort);
virtual int file_browser_load_directory(const char *directory, char *filename, size_t name_size,
dirent ***pfiles, Fl_File_Sort_F *sort,
char *errmsg=NULL, int errmsg_sz=0);
virtual void newUUID(char *uuidBuffer);
virtual char *preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor,
const char *application);

View File

@ -486,11 +486,13 @@ int Fl_WinAPI_System_Driver::clocale_printf(FILE *output, const char *format, va
return retval;
}
int Fl_WinAPI_System_Driver::filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) ) {
int Fl_WinAPI_System_Driver::filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg, int errmsg_sz ) {
// For Windows we have a special scandir implementation that uses
// the Win32 "wide" functions for lookup, avoiding the code page mess
// entirely. It also fixes up the trailing '/'.
return fl_scandir(d, list, 0, sort);
return fl_scandir(d, list, 0, sort, errmsg, errmsg_sz);
}
int Fl_WinAPI_System_Driver::filename_expand(char *to, int tolen, const char *from) {
@ -747,7 +749,9 @@ int Fl_WinAPI_System_Driver::file_browser_load_filesystem(Fl_File_Browser *brows
}
int Fl_WinAPI_System_Driver::file_browser_load_directory(const char *directory, char *filename,
size_t name_size, dirent ***pfiles, Fl_File_Sort_F *sort)
size_t name_size, dirent ***pfiles,
Fl_File_Sort_F *sort,
char *errmsg, int errmsg_sz)
{
strlcpy(filename, directory, name_size);
int i = (int) (strlen(filename) - 1);
@ -756,7 +760,7 @@ int Fl_WinAPI_System_Driver::file_browser_load_directory(const char *directory,
filename[2] = '/';
else if (filename[i] != '/' && filename[i] != '\\')
strlcat(filename, "/", name_size);
return filename_list(filename, pfiles, sort);
return filename_list(filename, pfiles, sort, errmsg, errmsg_sz);
}
void Fl_WinAPI_System_Driver::newUUID(char *uuidBuffer)

View File

@ -52,7 +52,9 @@ public:
// these 2 are in Fl_get_key_mac.cxx
virtual int event_key(int k);
virtual int get_key(int k);
virtual int filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) );
virtual int filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg=NULL, int errmsg_sz=0);
virtual int open_uri(const char *uri, char *msg, int msglen);
virtual int need_test_shortcut_extra() {return 1;}
virtual int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon);

View File

@ -15,6 +15,7 @@
//
#include "Fl_Darwin_System_Driver.H"
#include <src/flstring.h>
#include <FL/platform.H>
#include <FL/Fl.H>
#include <FL/Fl_File_Browser.H>
@ -139,7 +140,9 @@ void *Fl_Darwin_System_Driver::get_carbon_function(const char *function_name) {
return (carbon ? dlsym(carbon, function_name) : NULL);
}
int Fl_Darwin_System_Driver::filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) ) {
int Fl_Darwin_System_Driver::filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg, int errmsg_sz) {
int dirlen;
char *dirloc;
// Assume that locale encoding is no less dense than UTF-8
@ -150,6 +153,10 @@ int Fl_Darwin_System_Driver::filename_list(const char *d, dirent ***list, int (*
# else
int n = scandir(dirloc, list, 0, (int(*)(const void*,const void*))sort);
# endif
if (n==-1) {
if (errmsg) fl_snprintf(errmsg, errmsg_sz, "%s", strerror(errno));
return -1;
}
// convert every filename to UTF-8, and append a '/' to all
// filenames that are directories
int i;

View File

@ -68,7 +68,9 @@ public:
// these 2 are in Fl_get_key_win32.cxx
virtual int event_key(int k);
virtual int get_key(int k);
virtual int filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) );
virtual int filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg=NULL, int errmsg_sz=0);
virtual int filename_expand(char *to,int tolen, const char *from);
virtual int filename_relative(char *to, int tolen, const char *from, const char *base);
virtual int filename_absolute(char *to, int tolen, const char *from);
@ -78,7 +80,9 @@ public:
virtual int open_uri(const char *uri, char *msg, int msglen);
virtual int use_recent_tooltip_fix() {return 1;}
virtual int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon);
virtual int file_browser_load_directory(const char *directory, char *filename, size_t name_size, dirent ***pfiles, Fl_File_Sort_F *sort);
virtual int file_browser_load_directory(const char *directory, char *filename, size_t name_size,
dirent ***pfiles, Fl_File_Sort_F *sort,
char *errmsg=NULL, int errmsg_sz=0);
virtual void newUUID(char *uuidBuffer);
virtual char *preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor,
const char *application);

View File

@ -61,7 +61,8 @@ static wchar_t *wbuf1 = NULL;
extern "C" {
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_len);
}
/*
@ -488,11 +489,13 @@ int Fl_WinAPI_System_Driver::clocale_printf(FILE *output, const char *format, va
return retval;
}
int Fl_WinAPI_System_Driver::filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) ) {
int Fl_WinAPI_System_Driver::filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg, int errmsg_sz) {
// For Windows we have a special scandir implementation that uses
// the Win32 "wide" functions for lookup, avoiding the code page mess
// entirely. It also fixes up the trailing '/'.
return fl_scandir(d, list, 0, sort);
return fl_scandir(d, list, 0, sort, errmsg, errmsg_sz);
}
int Fl_WinAPI_System_Driver::filename_expand(char *to, int tolen, const char *from) {
@ -749,7 +752,9 @@ int Fl_WinAPI_System_Driver::file_browser_load_filesystem(Fl_File_Browser *brows
}
int Fl_WinAPI_System_Driver::file_browser_load_directory(const char *directory, char *filename,
size_t name_size, dirent ***pfiles, Fl_File_Sort_F *sort)
size_t name_size, dirent ***pfiles,
Fl_File_Sort_F *sort,
char *errmsg, int errmsg_sz)
{
strlcpy(filename, directory, name_size);
int i = (int) (strlen(filename) - 1);
@ -758,7 +763,7 @@ int Fl_WinAPI_System_Driver::file_browser_load_directory(const char *directory,
filename[2] = '/';
else if (filename[i] != '/' && filename[i] != '\\')
strlcat(filename, "/", name_size);
return filename_list(filename, pfiles, sort);
return filename_list(filename, pfiles, sort, errmsg, errmsg_sz);
}
void Fl_WinAPI_System_Driver::newUUID(char *uuidBuffer)

View File

@ -34,7 +34,9 @@ public:
// these 2 are in Fl_get_key.cxx
virtual int event_key(int k);
virtual int get_key(int k);
virtual int filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) );
virtual int filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg=NULL, int errmsg_sz=0);
virtual int need_menu_handle_part1_extra() {return 1;}
virtual int open_uri(const char *uri, char *msg, int msglen);
virtual int use_tooltip_timeout_condition() {return 1;}

View File

@ -25,7 +25,8 @@
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h> // strerror(errno)
#include <errno.h> // errno
#if defined(_AIX)
extern "C" {
@ -56,7 +57,8 @@ extern "C" {
extern "C" {
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);
}
#endif
@ -444,10 +446,19 @@ int Fl_X11_System_Driver::XParseGeometry(const char* string, int* x, int* y,
return ::XParseGeometry(string, x, y, width, height);
}
int Fl_X11_System_Driver::filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) ) {
//
// Needs some docs
// Returns -1 on error, errmsg will contain OS error if non-NULL.
//
int Fl_X11_System_Driver::filename_list(const char *d,
dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg, int errmsg_sz) {
int dirlen;
char *dirloc;
if (errmsg && errmsg_sz>0) errmsg[0] = '\0';
// Assume that locale encoding is no less dense than UTF-8
dirlen = strlen(d);
dirloc = (char *)malloc(dirlen + 1);
@ -476,6 +487,11 @@ int Fl_X11_System_Driver::filename_list(const char *d, dirent ***list, int (*sor
free(dirloc);
if (n==-1) {
if (errmsg) fl_snprintf(errmsg, errmsg_sz, "%s", strerror(errno));
return -1;
}
// convert every filename to UTF-8, and append a '/' to all
// filenames that are directories
int i;

View File

@ -57,6 +57,7 @@ int Fl_System_Driver::filename_isdir_quick(const char* n) {
}
// TODO: This should probably handle errors better (like permission denied) -erco
int Fl_System_Driver::filename_isdir(const char* n) {
struct stat s;
char fn[FL_PATH_MAX];

View File

@ -63,9 +63,10 @@ int fl_casealphasort(struct dirent **a, struct dirent **b) {
to put unpadded numbers in consecutive order; upper and lowercase letters are compared
according to their ASCII ordering - uppercase before lowercase.
\return the number of entries if no error, a negative value otherwise.
\todo should support returning OS error messages
*/
int fl_filename_list(const char *d, dirent ***list, Fl_File_Sort_F *sort) {
return Fl::system_driver()->filename_list(d, list, sort);
return Fl::system_driver()->filename_list(d, list, sort, NULL, 0);
}
/**

View File

@ -128,11 +128,16 @@ readentry(DIR *dirp, struct dirent **entryp, size_t *len)
}
/* ========================================================================== */
/*
* This could use some docs.
*
* Returns -1 on error, errmsg returns error string (if non-NULL)
*/
int
fl_scandir(const char *dir, struct dirent ***namelist,
int (*sel)(struct dirent *),
int (*compar)(struct dirent **, struct dirent **))
int (*compar)(struct dirent **, struct dirent **),
char *errmsg, int errmsg_sz) {
{
int result = -1;
DIR *dirp;
@ -140,64 +145,62 @@ fl_scandir(const char *dir, struct dirent ***namelist,
struct dirent *entryp, **entries, **p;
entries = (struct dirent **) malloc(sizeof(*entries) * max);
if (NULL != entries)
{
/* Open directory 'dir' (and verify that it really is a directory) */
dirp = opendir(dir);
if (NULL != dirp)
{
/* Read next directory entry */
while (!readentry(dirp, &entryp, &len))
{
if (NULL == entryp)
{
/* EOD => Return number of directory entries */
result = (int) num;
break;
}
/* Apply select function if there is one provided */
if (NULL != sel) { if (!sel(entryp)) continue; }
entries[num++] = entryp;
if (num >= max)
{
/* Allocate exponentially increasing sized memory chunks */
if (INT_MAX / 2 >= (int) max) { max *= (size_t) 2; }
else
{
errno = ENOMEM;
break;
}
p = (struct dirent **) realloc((void *) entries,
sizeof(*entries) * max);
if (NULL != p) { entries = p; }
else break;
}
}
closedir(dirp);
/*
* A standard compliant 'closedir()' is allowed to fail with 'EINTR',
* but the state of the directory structure is undefined in this case.
* Therefore we ignore the return value because we can't call 'closedir()'
* again and must hope that the system has released all resources.
*/
}
/* Sort entries in array if there is a compare function provided */
if (NULL != compar)
{
qsort((void *) entries, num, sizeof(*entries),
(int (*)(const void *, const void *)) compar);
}
*namelist = entries;
if (NULL == entries) {
if (errmsg) fl_snprintf(errmsg, errmsg_sz, "out of memory");
return -1;
}
/* Check for error */
if (-1 == result)
/* Open directory 'dir' (and verify that it really is a directory) */
dirp = opendir(dir);
if (NULL == dirp) {
if (errmsg) fl_snprintf(errmsg, errmsg_sz, "%s", strerror(errno));
return -1;
}
/* Read next directory entry */
while (!readentry(dirp, &entryp, &len))
{
if (NULL == entryp)
{
/* EOD => Return number of directory entries */
result = (int) num;
break;
}
/* Apply select function if there is one provided */
if (NULL != sel) { if (!sel(entryp)) continue; }
entries[num++] = entryp;
if (num >= max) {
/* Allocate exponentially increasing sized memory chunks */
if (INT_MAX / 2 >= (int) max) { max *= (size_t) 2; }
else {
errno = ENOMEM;
break;
}
p = (struct dirent **) realloc((void *)entries, sizeof(*entries)*max);
if (NULL != p) { entries = p; }
else break;
}
}
closedir(dirp);
/*
* A standard compliant 'closedir()' is allowed to fail with 'EINTR',
* but the state of the directory structure is undefined in this case.
* Therefore we ignore the return value because we can't call 'closedir()'
* again and must hope that the system has released all resources.
*/
/* Sort entries in array if there is a compare function provided */
if (NULL != compar) {
qsort((void *) entries, num, sizeof(*entries),
(int (*)(const void *, const void *)) compar);
}
*namelist = entries;
/* Check for error */
if (-1 == result) {
/* Free all memory we have allocated */
while (num--) { free(entries[num]); }
free(entries);
}
return result;
}

View File

@ -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;
}