Fixing and upgrading Fl_Preferences (#374)

* Added filename function to Fl_Preferences

Static function to get filename before opening.
Member to get filename after opening.
Bug fixes for memory mapped preferences.

* ERROR is a macro on Windows, don't use it

* Added Fl_Preferences::dirty().

User can now check if the database will be written
when flushed or destroyed.
Flush returns a crude error code.

* Fl_Preferences::get binary data returns # of bytes read.

* Verified group deletion code

* Fl_Preferences ignores locale.

This will make .prefs files interchangeable
between different computers.

* Updating the Preferences Mode to ignore locale.

* Fixes in docs.
This commit is contained in:
Matthias Melcher
2022-01-19 16:08:29 +01:00
committed by GitHub
parent 793f4b90fa
commit 09eff7243a
19 changed files with 629 additions and 183 deletions
+94 -30
View File
@@ -1,7 +1,7 @@
//
// Preferences implementation for the Fast Light Tool Kit (FLTK).
//
// Copyright 2002-2010 by Matthias Melcher.
// Copyright 2002-2022 by Matthias Melcher.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -24,31 +24,74 @@
# include "Fl_Export.H"
/**
\brief Fl_Preferences provides methods to store user
settings between application starts.
\brief Fl_Preferences store user settings between application starts.
It is similar to the
Registry on Windows and Preferences on MacOS, and provides a
simple configuration mechanism for UNIX.
Fl_Preferences are similar to the Registry on Windows and Preferences on MacOS,
providing a simple method to store customisable user settings between app
launches, i.e. the previous window position or a history of previously
used documents.
Fl_Preferences uses a hierarchy to store data. It
bundles similar data into groups and manages entries in these
groups as name/value pairs.
Preferences are organized in a hierarchy of groups. Every group can contain
more groups and any number of kay/value pairs. Keys can be text strings
containing ASCII letters, digits, periods, and underscores. Forward slashes
in a key name are treated as subgroups, i.e the key 'window/width' would
actually refere to the key 'width' inside the group 'window'.
Preferences are stored in text files that can be edited
manually. The file format is easy to read and relatively
forgiving. Preferences files are the same on all platforms. User
comments in preference files are preserved. Filenames are unique
for each application by using a vendor/application naming
scheme. The user must provide default values for all entries to
ensure proper operation should preferences be corrupted or not
yet exist.
Keys have usually a unique name within their group. Duplicate kays are
possible though and can beaccessed using the index based functions.
Entries can be of any length. However, the size of each
preferences file should be kept small for performance
reasons. One application can have multiple preferences files.
Extensive binary data however should be stored in separate
files: see \a Fl_Preferences::getUserdataPath() .
A value should be an ASCII string. Control characters and utf8 sequences are
stores as octal values. Long strings will wrap at the line ending and will be
reassembled when reading the file back.
Many shortcuts exist to set and get numerical values and binary data.
Preferences are stored in text files that can be edited manually if needed.
The file format is easy to read and relatively forgiving. Preferences files
are the same on all platforms. User comments in preference files are preserved.
Filenames are unique for each application by using a vendor/application naming
scheme. The user must provide default values for all entries to ensure proper
operation should preferences be corrupted or not yet exist.
FLTK preferences are not meant to replace a fully features database. No merging
of data takes place. If several instances of an app access the same database at
the same time, only the most recent changes will persist.
Preferences should no be used to store document data. The .prefs file should
be kept small for performance reasons. One application can have multiple
preferences files. Extensive binary data however should be stored in separate
files: see \a Fl_Preferences::getUserdataPath() .
Fl_Preferences are not thread-safe. They can temprorarily change the locale
on some platforms during read an write access, which is alse observable in
other threads of the same app.
Typically a preferences database is read at startup and close, and then writte
again at app shutdown:
```.cpp
int appWindowWidth, appWindowHeight;
void launch() {
Fl_Preferences app(Fl_Preferences::USER_L, "matthiasm.com", "hello");
// 'app' constructor will be called, reading data from .prefs file
Fl_Preferences window(app, "window");
window.get("width", appWindowWidth, 800);
window.get("height", appWindowHeight, 600);
// 'app' destructor will be called, writing data to .prefs file
}
void quit() {
Fl_Preferences app(Fl_Preferences::USER_L, "matthiasm.com", "hello");
Fl_Preferences window(app, "window");
window.set("width", appWindowWidth);
window.set("height", appWindowHeight);
}
```
\see Fl_Preferences::Fl_Preferences( Root root, const char *vendor, const char *application )
As a special case, Fl_Preferences can be memeory mapped and not be associated
with a file on disk.
\see Fl_Preferences::Fl_Preferences( Fl_Preferences *parent, const char *group )
\note Starting with FLTK 1.3, preference databases are expected to
be in UTF-8 encoding. Previous databases were stored in the
@@ -59,6 +102,14 @@
the preferences files has changed slightly. Please see
Fl_Preferences::Fl_Preferences(Root, const char*, const char*)
for details.
\note Starting with FLTK 1.4, preference files should be created with
`SYSTEM_L` or `USER_L` to be interchangeable between computers with
differing loacale settings. The legacy modes, `LOCAL` and `SYSTEM`, will
read and write floating point values using the decimal point of the
current locale. As a result, a fp-value would be writte '3,1415' on a
German machine, and would be read back as '3.0' on a US machine because
the comma would not be recoginized as an alternative decimal point.
*/
class FL_EXPORT Fl_Preferences {
@@ -67,12 +118,17 @@ public:
Define the scope of the preferences.
*/
enum Root {
SYSTEM = 0, ///< Preferences are used system-wide
USER, ///< Preferences apply only to the current user
UNKNOWN_ROOT_TYPE = -1, ///< Returned if storage could not be determined.
SYSTEM = 0, ///< Preferences are used system-wide, deprecated, see SYSTEM_L
USER, ///< Preferences apply only to the current user, deprecated, see USER_L
MEMORY, ///< Returned if querying runtime prefs
ROOT_MASK = 0xFF, ///< masks for the values above
CORE = 0x100, ///< OR'd by FLTK to read and write core library preferences and options
CORE_SYSTEM = CORE|SYSTEM,
CORE_USER = CORE|USER
CORE_USER = CORE|USER,
C_LOCALE = 0x1000, ///< this flag should always be set, it makes sure that floating point values wre writte correctly independently of the current locale
SYSTEM_L = SYSTEM|C_LOCALE, ///< Preferences are used system-wide
USER_L = USER|C_LOCALE, ///< Preferences apply only to the current user
};
/**
@@ -120,6 +176,7 @@ public:
static void file_access(unsigned int flags);
static unsigned int file_access();
static Root filename( char *buffer, size_t buffer_size, Root root, const char *vendor, const char *application );
Fl_Preferences( Root root, const char *vendor, const char *application );
Fl_Preferences( const char *path, const char *vendor, const char *application );
@@ -131,6 +188,8 @@ public:
Fl_Preferences( ID id );
virtual ~Fl_Preferences();
Root filename( char *buffer, size_t buffer_size);
/** Return an ID that can later be reused to open more references to this dataset.
*/
ID id() { return (ID)node; }
@@ -176,12 +235,15 @@ public:
char get( const char *entry, char *value, const char *defaultValue, int maxSize );
char get( const char *entry, void *&value, const void *defaultValue, int defaultSize );
char get( const char *entry, void *value, const void *defaultValue, int defaultSize, int maxSize );
char get( const char *entry, void *value, const void *defaultValue, int defaultSize, int *size );
int size( const char *entry );
char getUserdataPath( char *path, int pathlen );
void flush();
int flush();
int dirty();
// char export( const char *filename, Type fileFormat );
// char import( const char *filename );
@@ -233,10 +295,10 @@ public: // older Sun compilers need this (public definition of the following cl
class FL_EXPORT Node { // a node contains a list to all its entries
// and all means to manage the tree structure
Node *child_, *next_;
Node *first_child_, *next_;
union { // these two are mutually exclusive
Node *parent_; // top_ bit clear
RootNode *root_; // top_ bit set
RootNode *root_node_; // top_ bit set
};
char *path_;
Entry *entry_;
@@ -265,7 +327,7 @@ public: // older Sun compilers need this (public definition of the following cl
Node *addChild( const char *path );
void setParent( Node *parent );
Node *parent() { return top_?0L:parent_; }
void setRoot(RootNode *r) { root_ = r; top_ = 1; }
void setRoot(RootNode *r) { root_node_ = r; top_ = 1; }
RootNode *findRoot();
char remove();
char dirty();
@@ -290,7 +352,7 @@ public: // older Sun compilers need this (public definition of the following cl
Fl_Preferences *prefs_;
char *filename_;
char *vendor_, *application_;
Root root_;
Root root_type_;
public:
RootNode( Fl_Preferences *, Root root, const char *vendor, const char *application );
RootNode( Fl_Preferences *, const char *path, const char *vendor, const char *application );
@@ -299,6 +361,8 @@ public: // older Sun compilers need this (public definition of the following cl
int read();
int write();
char getPath( char *path, int pathlen );
char *filename() { return filename_; }
Root root() { return root_type_; }
};
friend class RootNode;
+7 -7
View File
@@ -1530,7 +1530,7 @@ static void load_comments_preset(Fl_Preferences &menu) {
"FLTK/Header" };
int i;
menu.set("n", 5);
Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
for (i=0; i<5; i++) {
menu.set(Fl_Preferences::Name(i), predefined_comment[i]);
db.set(predefined_comment[i], comment_text[i]);
@@ -1545,7 +1545,7 @@ void Fl_Comment_Type::open() {
const char *text = name();
{
int i=0, n=0;
Fl_Preferences menu(Fl_Preferences::USER, "fltk.org", "fluid_comments_menu");
Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
comment_predefined->clear();
comment_predefined->add("_Edit/Add current comment...");
comment_predefined->add("_Edit/Remove last selection...");
@@ -1583,9 +1583,9 @@ void Fl_Comment_Type::open() {
char *name = fl_strdup(xname);
for (char*s=name;*s;s++) if (*s==':') *s = ';';
int n;
Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
db.set(name, comment_input->buffer()->text());
Fl_Preferences menu(Fl_Preferences::USER, "fltk.org", "fluid_comments_menu");
Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
menu.get("n", n, 0);
menu.set(Fl_Preferences::Name(n), name);
menu.set("n", ++n);
@@ -1599,10 +1599,10 @@ void Fl_Comment_Type::open() {
} else if (fl_choice("Are you sure that you want to delete the entry\n"
"\"%s\"\nfrom the database?", "Cancel", "Delete",
NULL, itempath)) {
Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
db.deleteEntry(itempath);
comment_predefined->remove(last_selected_item);
Fl_Preferences menu(Fl_Preferences::USER, "fltk.org", "fluid_comments_menu");
Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
int i, n;
for (i=4, n=0; i<comment_predefined->size(); i++) {
const Fl_Menu_Item *mi = comment_predefined->menu()+i;
@@ -1617,7 +1617,7 @@ void Fl_Comment_Type::open() {
// load the selected comment from the database
if (comment_predefined->item_pathname(itempath, 255)==0) {
if (itempath[0]=='/') memmove(itempath, itempath+1, 255);
Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
char *text;
db.get(itempath, text, "(no text found in data base)");
comment_input->buffer()->text(text);
+14 -9
View File
@@ -1,5 +1,10 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0400
i18n_type 1
i18n_include {<libintl.h>}
i18n_conditional FLTK_GETTEXT_FOUND
i18n_function gettext
i18n_static_function gettext_noop
header_name {.h}
code_name {.cxx}
comment {//
@@ -35,7 +40,7 @@ decl {\#include <FL/Fl_Text_Buffer.H>} {public local
decl {\#include <FL/Fl_Text_Display.H>} {public local
}
decl {\#include <FL/filename.H>} {selected public local
decl {\#include <FL/filename.H>} {public local
}
decl {\#include <FL/Fl_Preferences.H>} {private global
@@ -323,7 +328,7 @@ Function {make_shell_window()} {open
tooltip {save the design to the .fl file before running the command} xywh {82 39 136 19} down_box DOWN_BOX labelsize 12
}
Fl_Check_Button shell_writecode_button {
label {save source code}
label {save source code} selected
tooltip {generate the source code and header file before running the command} xywh {82 59 120 19} down_box DOWN_BOX labelsize 12
}
Fl_Check_Button shell_writemsgs_button {
@@ -524,11 +529,11 @@ wShowZoomFactor->value(opt[Fl::OPTION_SHOW_SCALING][mode]);} {}
}
Function {readPrefs()} {
comment {read all preferences and refresh the GUI} private return_type void
comment {read all preferences and refresh the GUI} open private return_type void
} {
code {// read all preferences and refresh the GUI
{
Fl_Preferences prefs(Fl_Preferences::SYSTEM, "fltk.org", "fltk");
Fl_Preferences prefs(Fl_Preferences::SYSTEM_L, "fltk.org", "fltk");
Fl_Preferences opt_prefs(prefs, "options");
opt_prefs.get("ArrowFocus", opt[Fl::OPTION_ARROW_FOCUS][1], 2);
opt_prefs.get("VisibleFocus", opt[Fl::OPTION_VISIBLE_FOCUS][1], 2);
@@ -539,7 +544,7 @@ Function {readPrefs()} {
opt_prefs.get("ShowZoomFactor", opt[Fl::OPTION_SHOW_SCALING ][1], 2);
}
{
Fl_Preferences prefs(Fl_Preferences::USER, "fltk.org", "fltk");
Fl_Preferences prefs(Fl_Preferences::USER_L, "fltk.org", "fltk");
Fl_Preferences opt_prefs(prefs, "options");
opt_prefs.get("ArrowFocus", opt[Fl::OPTION_ARROW_FOCUS][0], 2);
opt_prefs.get("VisibleFocus", opt[Fl::OPTION_VISIBLE_FOCUS][0], 2);
@@ -553,11 +558,11 @@ refreshUI();} {}
}
Function {writePrefs()} {
comment {write all preferences using the array} private return_type void
comment {write all preferences using the array} open private return_type void
} {
code {// write all preferences using the array
{
Fl_Preferences prefs(Fl_Preferences::SYSTEM, "fltk.org", "fltk");
Fl_Preferences prefs(Fl_Preferences::SYSTEM_L, "fltk.org", "fltk");
Fl_Preferences opt_prefs(prefs, "options");
if (opt[Fl::OPTION_ARROW_FOCUS][1]==2) opt_prefs.deleteEntry("ArrowFocus");
else opt_prefs.set("ArrowFocus", opt[Fl::OPTION_ARROW_FOCUS][1]);
@@ -575,7 +580,7 @@ Function {writePrefs()} {
else opt_prefs.set("ShowZoomFactor", opt[Fl::OPTION_SHOW_SCALING][1]);
}
{
Fl_Preferences prefs(Fl_Preferences::USER, "fltk.org", "fltk");
Fl_Preferences prefs(Fl_Preferences::USER_L, "fltk.org", "fltk");
Fl_Preferences opt_prefs(prefs, "options");
if (opt[Fl::OPTION_ARROW_FOCUS][0]==2) opt_prefs.deleteEntry("ArrowFocus");
else opt_prefs.set("ArrowFocus", opt[Fl::OPTION_ARROW_FOCUS][0]);
@@ -594,7 +599,7 @@ Function {writePrefs()} {
}} {}
}
Function {show_global_settings_window()} {return_type void
Function {show_global_settings_window()} {open return_type void
} {
code {if (!global_settings_window)
make_global_settings_window();
+1 -1
View File
@@ -72,7 +72,7 @@ Fl_Menu_Bar *main_menubar = NULL;
Fl_Window *main_window;
/// Fluid application preferences, allways accessible, will be flushed when app closes.
Fl_Preferences fluid_prefs(Fl_Preferences::USER, "fltk.org", "fluid");
Fl_Preferences fluid_prefs(Fl_Preferences::USER_L, "fltk.org", "fluid");
/// Align widget position and size when designing, saved in app preferences and project file.
int gridx = 5;
+335 -122
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -128,6 +128,8 @@ public:
virtual unsigned utf8from_mb(char* dst, unsigned dstlen, const char* src, unsigned srclen);
// implement to shield fprintf() from locale changes in decimal point
virtual int clocale_printf(FILE *output, const char *format, va_list args);
virtual int clocale_snprintf(char *output, size_t output_size, const char *format, va_list args);
virtual int clocale_sscanf(const char *input, const char *format, va_list args);
// implement functions telling whether a key is pressed
virtual int event_key(int) {return 0;}
virtual int get_key(int) {return 0;}
+8
View File
@@ -404,6 +404,14 @@ int Fl_System_Driver::clocale_printf(FILE *output, const char *format, va_list a
return vfprintf(output, format, args);
}
int Fl_System_Driver::clocale_snprintf(char *output, size_t output_size, const char *format, va_list args) {
return vsnprintf(output, output_size, format, args);
}
int Fl_System_Driver::clocale_sscanf(const char *input, const char *format, va_list args) {
return vsscanf(input, format, args);
}
int Fl_System_Driver::filename_expand(char *to,int tolen, const char *from) {
char *temp = new char[tolen];
strlcpy(temp,from, tolen);
+4 -1
View File
@@ -4528,7 +4528,10 @@ int Fl_Darwin_System_Driver::calc_mac_os_version() {
return fl_mac_os_version;
}
char *Fl_Darwin_System_Driver::preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root,
/*
Note: `prefs` can be NULL!
*/
char *Fl_Darwin_System_Driver::preference_rootnode(Fl_Preferences * /*prefs*/, Fl_Preferences::Root root,
const char *vendor, const char *application)
{
static char *filename = 0L;
@@ -69,6 +69,8 @@ public:
virtual unsigned utf8to_mb(const char *src, unsigned srclen, char *dst, unsigned dstlen);
virtual unsigned utf8from_mb(char *dst, unsigned dstlen, const char *src, unsigned srclen);
virtual int clocale_printf(FILE *output, const char *format, va_list args);
virtual int clocale_snprintf(char *output, size_t output_size, const char *format, va_list args);
virtual int clocale_sscanf(const char *input, const char *format, va_list args);
// these 2 are in Fl_get_key_win32.cxx
virtual int event_key(int k);
virtual int get_key(int k);
@@ -487,6 +487,14 @@ int Fl_WinAPI_System_Driver::clocale_printf(FILE *output, const char *format, va
return retval;
}
int Fl_WinAPI_System_Driver::clocale_snprintf(char *output, size_t output_size, const char *format, va_list args) {
//... write me
}
int Fl_WinAPI_System_Driver::clocale_sscanf(const char *input, const char *format, va_list args) {
//... write me
}
int Fl_WinAPI_System_Driver::filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg, int errmsg_sz ) {
@@ -834,6 +842,9 @@ void Fl_WinAPI_System_Driver::newUUID(char *uuidBuffer)
}
}
/*
Note: `prefs` can be NULL!
*/
char *Fl_WinAPI_System_Driver::preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor,
const char *application)
{
@@ -45,6 +45,8 @@ public:
virtual int single_arg(const char *arg);
virtual int arg_and_value(const char *name, const char *value);
virtual int clocale_printf(FILE *output, const char *format, va_list args);
virtual int clocale_snprintf(char *output, size_t output_size, const char *format, va_list args);
virtual int clocale_sscanf(const char *input, const char *format, va_list args);
static void *get_carbon_function(const char *name);
static int calc_mac_os_version(); // computes the fl_mac_os_version global variable
static unsigned short *compute_macKeyLookUp();
+37 -1
View File
@@ -116,10 +116,15 @@ int Fl_Darwin_System_Driver::arg_and_value(const char *name, const char *value)
return strcmp(name, "NSDocumentRevisionsDebugMode") == 0;
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
static locale_t postscript_locale = NULL;
#endif
int Fl_Darwin_System_Driver::clocale_printf(FILE *output, const char *format, va_list args) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (fl_mac_os_version >= 100400) {
static locale_t postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
if (!postscript_locale)
postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
return vfprintf_l(output, postscript_locale, format, args);
}
#endif
@@ -130,6 +135,37 @@ int Fl_Darwin_System_Driver::clocale_printf(FILE *output, const char *format, va
return retval;
}
int Fl_Darwin_System_Driver::clocale_snprintf(char *output, size_t output_size, const char *format, va_list args) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (fl_mac_os_version >= 100400) {
if (!postscript_locale)
postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
return vsnprintf_l(output, output_size, postscript_locale, format, args);
}
#endif
char *saved_locale = setlocale(LC_NUMERIC, NULL);
setlocale(LC_NUMERIC, "C");
int retval = vsnprintf(output, output_size, format, args);
setlocale(LC_NUMERIC, saved_locale);
return retval;
}
int Fl_Darwin_System_Driver::clocale_sscanf(const char *input, const char *format, va_list args) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (fl_mac_os_version >= 100400) {
if (!postscript_locale)
postscript_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
return vsscanf_l(input, postscript_locale, format, args);
}
#endif
char *saved_locale = setlocale(LC_NUMERIC, NULL);
setlocale(LC_NUMERIC, "C");
int retval = vsscanf(input, format, args);
setlocale(LC_NUMERIC, saved_locale);
return retval;
}
/* Returns the address of a Carbon function after dynamically loading the Carbon library if needed.
Supports old Mac OS X versions that may use a couple of Carbon calls:
GetKeys used by OS X 10.3 or before (in Fl::get_key())
@@ -67,6 +67,8 @@ public:
virtual unsigned utf8to_mb(const char *src, unsigned srclen, char *dst, unsigned dstlen);
virtual unsigned utf8from_mb(char *dst, unsigned dstlen, const char *src, unsigned srclen);
virtual int clocale_printf(FILE *output, const char *format, va_list args);
virtual int clocale_snprintf(char *output, size_t output_size, const char *format, va_list args);
virtual int clocale_sscanf(const char *input, const char *format, va_list args);
// these 2 are in Fl_get_key_win32.cxx
virtual int event_key(int k);
virtual int get_key(int k);
+39 -2
View File
@@ -455,9 +455,14 @@ unsigned Fl_WinAPI_System_Driver::utf8from_mb(char *dst, unsigned dstlen, const
return ret;
}
#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/)
static _locale_t c_locale = NULL;
#endif
int Fl_WinAPI_System_Driver::clocale_printf(FILE *output, const char *format, va_list args) {
#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/)
static _locale_t c_locale = _create_locale(LC_NUMERIC, "C");
if (!c_locale)
c_locale = _create_locale(LC_NUMERIC, "C");
int retval = _vfprintf_l(output, format, c_locale, args);
#else
char *saved_locale = setlocale(LC_NUMERIC, NULL);
@@ -468,6 +473,35 @@ int Fl_WinAPI_System_Driver::clocale_printf(FILE *output, const char *format, va
return retval;
}
int Fl_WinAPI_System_Driver::clocale_snprintf(char *output, size_t output_size, const char *format, va_list args) {
#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/)
if (!c_locale)
c_locale = _create_locale(LC_NUMERIC, "C");
int retval = _vsnprintf_l(output, output_size, format, c_locale, args);
#else
char *saved_locale = setlocale(LC_NUMERIC, NULL);
setlocale(LC_NUMERIC, "C");
int retval = vsnprintf(output, output_size, format, args);
setlocale(LC_NUMERIC, saved_locale);
#endif
return retval;
}
int Fl_WinAPI_System_Driver::clocale_sscanf(const char *input, const char *format, va_list args) {
#if defined(_MSC_VER) && (_MSC_VER >= 1400 /*Visual Studio 2005*/)
if (!c_locale)
c_locale = _create_locale(LC_NUMERIC, "C");
int retval = _vsscanf_l(input, format, c_locale, args);
#else
char *saved_locale = setlocale(LC_NUMERIC, NULL);
setlocale(LC_NUMERIC, "C");
int retval = vsscanf(input, format, args);
setlocale(LC_NUMERIC, saved_locale);
#endif
return retval;
}
int Fl_WinAPI_System_Driver::filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg, int errmsg_sz) {
@@ -814,7 +848,10 @@ void Fl_WinAPI_System_Driver::newUUID(char *uuidBuffer)
}
}
char *Fl_WinAPI_System_Driver::preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor,
/*
Note: `prefs` can be NULL!
*/
char *Fl_WinAPI_System_Driver::preference_rootnode(Fl_Preferences * /*prefs*/, Fl_Preferences::Root root, const char *vendor,
const char *application)
{
# define FLPREFS_RESOURCE "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
+2
View File
@@ -31,6 +31,8 @@ public:
virtual void display_arg(const char *arg);
virtual int XParseGeometry(const char*, int*, int*, unsigned int*, unsigned int*);
virtual int clocale_printf(FILE *output, const char *format, va_list args);
virtual int clocale_snprintf(char *output, size_t output_size, const char *format, va_list args);
virtual int clocale_sscanf(const char *input, const char *format, va_list args);
// these 2 are in Fl_get_key.cxx
virtual int event_key(int k);
virtual int get_key(int k);
+39 -2
View File
@@ -79,10 +79,15 @@ Fl_System_Driver *Fl_System_Driver::newSystemDriver()
return new Fl_X11_System_Driver();
}
#if defined(__linux__) && defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700
static locale_t c_locale = NULL;
#endif
int Fl_X11_System_Driver::clocale_printf(FILE *output, const char *format, va_list args) {
#if defined(__linux__) && defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700
static locale_t c_locale = newlocale(LC_NUMERIC_MASK, "C", duplocale(LC_GLOBAL_LOCALE));
if (!c_locale)
c_locale = newlocale(LC_NUMERIC_MASK, "C", duplocale(LC_GLOBAL_LOCALE));
locale_t previous_locale = uselocale(c_locale);
int retval = vfprintf(output, format, args);
uselocale(previous_locale);
@@ -95,6 +100,35 @@ int Fl_X11_System_Driver::clocale_printf(FILE *output, const char *format, va_li
return retval;
}
int Fl_X11_System_Driver::clocale_snprintf(char *output, size_t output_size, const char *format, va_list args) {
#if defined(__linux__) && defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700
if (!c_locale)
c_locale = newlocale(LC_NUMERIC_MASK, "C", duplocale(LC_GLOBAL_LOCALE));
locale_t previous_locale = uselocale(c_locale);
int retval = vsnprintf(output, output_size, format, args);
uselocale(previous_locale);
#else
char *saved_locale = setlocale(LC_NUMERIC, NULL);
setlocale(LC_NUMERIC, "C");
int retval = vsnprintf(output, output_size, format, args);
setlocale(LC_NUMERIC, saved_locale);
#endif
}
int Fl_X11_System_Driver::clocale_sscanf(const char *input, const char *format, va_list args) {
#if defined(__linux__) && defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700
if (!c_locale)
c_locale = newlocale(LC_NUMERIC_MASK, "C", duplocale(LC_GLOBAL_LOCALE));
locale_t previous_locale = uselocale(c_locale);
int retval = vsscanf(input, format, args);
uselocale(previous_locale);
#else
char *saved_locale = setlocale(LC_NUMERIC, NULL);
setlocale(LC_NUMERIC, "C");
int retval = vsscanf(input, format, args);
setlocale(LC_NUMERIC, saved_locale);
#endif
}
// Find a program in the path...
static char *path_find(const char *program, char *filename, int filesize) {
@@ -415,7 +449,10 @@ void Fl_X11_System_Driver::newUUID(char *uuidBuffer)
b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]);
}
char *Fl_X11_System_Driver::preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor,
/*
Note: `prefs` can be NULL!
*/
char *Fl_X11_System_Driver::preference_rootnode(Fl_Preferences * /*prefs*/, Fl_Preferences::Root root, const char *vendor,
const char *application)
{
static char *filename = 0L;
+1 -1
View File
@@ -497,7 +497,7 @@ class BlockWindow : public Fl_Double_Window {
};
Fl_Preferences BlockWindow::prefs_(Fl_Preferences::USER, "fltk.org", "blocks");
Fl_Preferences BlockWindow::prefs_(Fl_Preferences::USER_L, "fltk.org", "blocks");
int main(int argc, char *argv[]) {
+28 -6
View File
@@ -45,7 +45,7 @@ Function {saveAndCloseWindowCB( Fl_Widget*, void* )} {open private return_type v
Fl::delete_widget(myWindow);} {}
}
Function {} {open return_type int
Function {} {open selected return_type int
} {
Fl_Window myWindow {
label {My Preferences}
@@ -78,7 +78,7 @@ Function {} {open return_type int
xywh {0 0 100 20}
}
MenuItem {} {
label {p.m.} selected
label {p.m.}
xywh {0 0 100 20}
}
}
@@ -206,10 +206,32 @@ int intValue;
char buffer[80];
double doubleValue;
Fl_Preferences app( Fl_Preferences::USER, project, application );
char path[ FL_PATH_MAX ];
Fl_Preferences::Root root =
Fl_Preferences::filename(path, FL_PATH_MAX, Fl_Preferences::USER_L, project, application);
if (root == Fl_Preferences::UNKNOWN_ROOT_TYPE) {
printf("Location of future Preferences file not found.\\n");
} else {
printf("Preferences file will be located at:\\n%s\\n", path);
}
char path[ FL_PATH_MAX ];
app.getUserdataPath( path, sizeof(path) );
Fl_Preferences app( Fl_Preferences::USER_L, project, application );
root = app.filename(path, FL_PATH_MAX);
if (root == Fl_Preferences::UNKNOWN_ROOT_TYPE) {
printf("Location of app Preferences file not found.\\n");
} else if (root == Fl_Preferences::MEMORY) {
printf("App Preferences are memory mapped.\\n");
} else {
printf("App Preferences file is actually located at:\\n%s\\n", path);
}
app.getUserdataPath( path, sizeof(path) );
if (path[0]) {
printf("Preferences user data directory is located at:\\n%s\\n", path);
} else {
printf("Location of Preferences user data directory not found.\\n");
}
Fl_Preferences bed( app, "Bed" );
bed.get( "alarm", buffer, "8:00", 79 );
@@ -278,7 +300,7 @@ Fl_Preferences app( Fl_Preferences::USER, project, application );
Function {writePrefs()} {open return_type void
} {
code {Fl_Preferences app( Fl_Preferences::USER, project, application );
code {Fl_Preferences app( Fl_Preferences::USER_L, project, application );
Fl_Preferences bed( app, "Bed" );
+1 -1
View File
@@ -625,7 +625,7 @@ SudokuCell::handle(int event) {
// Sudoku class globals...
Fl_Help_Dialog *Sudoku::help_dialog_ = (Fl_Help_Dialog *)0;
Fl_Preferences Sudoku::prefs_(Fl_Preferences::USER, "fltk.org", "sudoku");
Fl_Preferences Sudoku::prefs_(Fl_Preferences::USER_L, "fltk.org", "sudoku");
// Create a Sudoku game window...