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:
parent
9925b0f128
commit
0693c70f57
@ -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_
|
||||
|
@ -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);
|
||||
|
@ -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) ||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;}
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user