@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
//
// Preferences methods for the Fast Light Tool Kit (FLTK).
//
// Copyright 2011-2020 by Bill Spitzak and others.
// Copyright 2011-2022 by Bill Spitzak and others.
// Copyright 2002-2010 by Matthias Melcher.
//
// This library is free software. Distribution and use rights are outlined in
@ -34,6 +34,24 @@ char Fl_Preferences::uuidBuffer[40];
@@ -34,6 +34,24 @@ char Fl_Preferences::uuidBuffer[40];
Fl_Preferences * Fl_Preferences : : runtimePrefs = 0 ;
unsigned int Fl_Preferences : : fileAccess_ = Fl_Preferences : : ALL ;
static int clocale_snprintf ( char * buffer , size_t buffer_size , const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
int retval = Fl : : system_driver ( ) - > clocale_snprintf ( buffer , buffer_size , format , args ) ;
va_end ( args ) ;
return retval ;
}
static int clocale_sscanf ( const char * input , const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
int retval = Fl : : system_driver ( ) - > clocale_sscanf ( input , format , args ) ;
va_end ( args ) ;
return retval ;
}
/**
Returns a UUID as generated by the system .
@ -100,69 +118,109 @@ unsigned int Fl_Preferences::file_access()
@@ -100,69 +118,109 @@ unsigned int Fl_Preferences::file_access()
return fileAccess_ ;
}
/**
Determine the file name and path to preferences that would be openend with
these parameters .
Find the possible location of a preference file on disk without touching any
of the pathname componennts . This can be used to check if a preferneces file
already exists .
\ param [ out ] buffer write the reulting path into this buffer
\ param [ in ] buffer_size size of the ` buffer ` in bytes
\ param [ in ] root can be \ c USER_L or \ c SYSTEM_L for user specific or system
wide preferences
\ param [ in ] vendor unique text describing the company or author of this file ,
must be a valid filepath segment
\ param [ in ] application unique text describing the application , must be a
valid filepath segment
\ return the input root value , or Fl_Preferences : : UNKNOWN_ROOT_TYPE if the path
could not be determined .
\ see Fl_Preferences ( Root root , const char * vendor , const char * application )
*/
Fl_Preferences : : Root Fl_Preferences : : filename ( char * buffer , size_t buffer_size , Root root , const char * vendor , const char * application )
{
Root ret = UNKNOWN_ROOT_TYPE ;
if ( buffer & & buffer_size > 0 ) {
char * fn = Fl : : system_driver ( ) - > preference_rootnode ( NULL , root , vendor , application ) ;
if ( fn ) {
fl_strlcpy ( buffer , fn , buffer_size ) ;
// FLTK always returns forward slashes in paths
{ char * s ; for ( s = buffer ; * s ; s + + ) if ( * s = = ' \\ ' ) * s = ' / ' ; }
ret = root ;
} else {
buffer [ 0 ] = 0 ;
}
}
return ret ;
}
/**
The constructor creates a group that manages name / value pairs and
child groups . Groups are ready for reading and writing at any time .
The root argument is either Fl_Preferences : : USER
or Fl_Preferences : : SYSTEM .
This constructor creates the < i > base < / i > instance for all
following entries and reads existing databases into memory . The
vendor argument is a unique text string identifying the
development team or vendor of an application . A domain name or
an EMail address are great unique names , e . g .
" research.matthiasm.com " or " fluid.fltk.org " . The
application argument can be the working title or final
name of your application . Both vendor and
application must be valid UNIX path segments and
may contain forward slashes to create deeper file structures .
A set of Preferences marked " run-time " exists exactly once per application and
only as long as the application runs . It can be used as a database for
volatile information . FLTK uses it to register plugins at run - time .
\ note On \ b Windows , the directory is constructed by querying the < i > Common AppData < / i >
or < i > AppData < / i > key of the < tt > Software \ \ Microsoft \ \ Windows \ \ CurrentVersion \ \ Explorer \ \ Shell Folders < / tt >
registry entry . The filename and path is then constructed as < tt > \ $ ( query ) / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
If the query call fails , data will be stored in RAM only and be lost when the app exits .
\ par In FLTK versions before 1.4 .0 , if querying the registry failed , preferences would be written to
The root argument is either ` Fl_Preferences : : USER_L `
or ` Fl_Preferences : : SYSTEM_L ` .
This constructor creates the < i > base < / i > instance for all following entries
and reads the database from disk into memory if it exists .
The vendor argument is a unique text string identifying the development team
or vendor of an application . A domain name or an EMail address ( replacing
the ' @ ' with a ' . ' ) are great unique names , e . g . " research.matthiasm.com " or
" fluid.fltk.org " .
The application argument can be the working title or final name of your
application .
Both vendor and application must be valid UNIX path segments as they become
parts of the preferences file path and may contain forward slashes to create
deeper file structures .
\ note On \ b Windows , the directory is constructed by querying the
< i > Common AppData < / i > or < i > AppData < / i > key of the
< tt > Software \ \ Microsoft \ \ Windows \ \ CurrentVersion \ \ Explorer \ \ Shell Folders < / tt >
registry entry .
The filename and path is then constructed as
< tt > \ $ ( query ) / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
If the query call fails , data will be stored in RAM only .
It will be lost when the app exits .
\ par In FLTK versions before 1.4 .0 , if querying the registry failed ,
preferences would be written to
< tt > C : \ \ FLTK \ \ \ $ ( vendor ) \ \ \ $ ( application ) . prefs < / tt > .
\ note On \ b Linux , the \ c USER directory is constructed by reading \ c $ HOME . If \ c $ HOME is not set
or not pointing to an existing directory , we are checking the path member of the passwd struct returned by
\ c getpwuid ( getuid ( ) ) . If all attempts fail , data will be stored in RAM only and be lost when the app exits .
The filename and path is then constructed as < tt > \ $ ( directory ) / . fltk / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
The \ c SYSTEM directory is hardcoded as < tt > / etc / fltk / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
\ par In FLTK versions before 1.4 .0 , if \ c $ HOME was not set , the \ c USER path would be empty ,
generating < tt > \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > , which was used relative to the current working directory .
\ note On \ b macOS , the \ c USER directory is constructed by reading \ c $ HOME . If \ c $ HOME is not set
or not pointing to an existing directory , we check the path returned by \ c NSHomeDirectory ( ) , and
finally checking the path member of the passwd struct returned by \ c getpwuid ( getuid ( ) ) .
\ note On \ b Linux , the \ c USER directory is constructed by reading \ c $ HOME .
If \ c $ HOME is not set or not pointing to an existing directory , FLTK will
check the path member of the passwd struct returned by \ c getpwuid ( getuid ( ) ) .
If all attempts fail , data will be stored in RAM only and be lost when the
app exits .
The filename and path is then constructed as
< tt > \ $ ( directory ) / . fltk / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
The \ c SYSTEM directory is hardcoded as
< tt > / etc / fltk / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
\ par In FLTK versions before 1.4 .0 , if \ c $ HOME was not set , the \ c USER path
would be empty , generating < tt > \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > , which
was used relative to the current working directory .
\ note On \ b macOS , the \ c USER directory is constructed by reading \ c $ HOME .
If \ c $ HOME is not set or not pointing to an existing directory , we check the
path returned by \ c NSHomeDirectory ( ) , and finally checking the path member
of the passwd struct returned by \ c getpwuid ( getuid ( ) ) .
If all attempts fail , data will be stored in RAM only and be lost when the app exits .
The filename and path is then constructed as < tt > \ $ ( directory ) / Library / Preferences / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
The \ c SYSTEM directory is hardcoded as < tt > / Library / Preferences / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
The filename and path is then constructed as
< tt > \ $ ( directory ) / Library / Preferences / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
The \ c SYSTEM directory is hardcoded as
< tt > / Library / Preferences / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > .
\ par In FLTK versions before 1.4 .0 , if \ c $ HOME was not set , the \ c USER path would be \ c NULL ,
generating < tt > \ < null \ > / Library / Preferences / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > , which would silently fail to
create a preferences file .
\ par In FLTK versions before 1.4 .0 , if \ c $ HOME was not set , the \ c USER path
would be \ c NULL , generating
< tt > \ < null \ > / Library / Preferences / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > ,
which would silently fail to create a preferences file .
\ param [ in ] root can be \ c USER or \ c SYSTEM for user specific or system wide preferences
\ param [ in ] root can be \ c USER_L or \ c SYSTEM_L for user specific or system wide preferences
\ param [ in ] vendor unique text describing the company or author of this file , must be a valid filepath segment
\ param [ in ] application unique text describing the application , must be a valid filepath segment
\ todo ( Matt ) Before the release of 1.4 .0 , I want to make a further attempt to write a preferences file smarter . I
plan to use a subgroup of the " runtime " preferences to store data and stay accessible until the application
exits . Data would be stored under < tt > . / \ $ ( vendor ) / \ $ ( application ) . prefs < / tt > in RAM , but not on disk .
\ todo ( Matt ) I want a way to access the type of the root preferences ( SYSTEM , USER , MEMORY ) , and the state of
the file access ( OK , FILE_SYSTEM_FAIL , PERMISSION_FAIL , etc . ) , and probably the dirty ( ) flag as well .
\ todo ( Matt ) Also , I need to explain runtime preferences .
\ todo ( Matt ) Lastly , I think I have to put short sample code in the Doxygen docs . The test app ist just not enough .
\ see Fl_Preferences ( Fl_Preferences * parent , const char * group ) with parent set to NULL
*/
Fl_Preferences : : Fl_Preferences ( Root root , const char * vendor , const char * application ) {
node = new Node ( " . " ) ;
@ -203,22 +261,49 @@ Fl_Preferences::Fl_Preferences( Fl_Preferences &parent, const char *group ) {
@@ -203,22 +261,49 @@ Fl_Preferences::Fl_Preferences( Fl_Preferences &parent, const char *group ) {
}
/**
\ brief Create or access a group of preferences using a name .
\ brief Create or access a group of preferences using a name .
Parent should point to a previously created parent preferences group to
create a preferences hierarchy .
If ` parent ` is set to ` NULL ` , an unnamed database will be accessed that exists
only in local memory and is not associated with a file on disk . The root type
of this databse is set to ` Fl_Preferences : : MEMORY ` .
* the memory database is \ em not shared among multiple instances of the same app
* memory databses are \ em not thread safe
* all data will be lost when the app quits
` ` ` { . cpp }
void some_function ( ) {
Fl_Preferences guide ( NULL , " Guide " ) ;
guide . set ( " answer " , 42 ) ;
}
void other_function ( ) {
int x ;
Fl_Preferences guide ( NULL , " Guide " ) ;
guide . get ( " answer " , x , - 1 ) ;
}
` ` `
FLTK uses the memory database to manage plugins . See ` Fl_Plugin ` .
\ param [ in ] parent the parameter parent is a pointer to the parent group .
\ p Parent may be \ p NULL . It then refers to an application internal
database which exists only once , and remains in RAM only until the
application quits . This database is used to manage plugins and other
data indexes by strings .
If \ p Parent is \ p NULL , the new Preferences item refers to an
application internal database ( " runtime prefs " ) which exists only
once , and remains in RAM only until the application quits .
This database is used to manage plugins and other data indexes
by strings . Runtime Prefs are \ em not thread - safe .
\ param [ in ] group a group name that is used as a key into the database
\ see Fl_Preferences ( Fl_Preferences & , const char * group )
*/
Fl_Preferences : : Fl_Preferences ( Fl_Preferences * parent , const char * group ) {
if ( parent = = 0 ) {
if ( parent = = NULL ) {
if ( ! runtimePrefs ) {
runtimePrefs = new Fl_Preferences ( ) ;
runtimePrefs - > node = new Node ( " . " ) ;
runtimePrefs - > rootNode = new RootNode ( runtimePrefs ) ;
runtimePrefs - > node - > setRoot ( rootNode ) ;
runtimePrefs - > node - > setRoot ( runtimePrefs - > r ootNode ) ;
}
parent = runtimePrefs ;
}
@ -313,6 +398,35 @@ Fl_Preferences::~Fl_Preferences() {
@@ -313,6 +398,35 @@ Fl_Preferences::~Fl_Preferences() {
rootNode = 0L ;
}
/**
Return the file name and path to the Preferences file .
If the preferences have not changed or have not been flushed , the file
or directory may not have been created yet .
\ param [ out ] buffer write the reulting path into this buffer
\ param [ in ] buffer_size size of the ` buffer ` in bytes
\ return the root type at creation type , or MEMORY for runtime prefs , it does
not return CORE or LOCALE flags .
*/
Fl_Preferences : : Root Fl_Preferences : : filename ( char * buffer , size_t buffer_size )
{
if ( ! buffer | | buffer_size = = 0 )
return UNKNOWN_ROOT_TYPE ;
RootNode * rn = rootNode ;
if ( ! rn )
return UNKNOWN_ROOT_TYPE ;
if ( rn - > root ( ) = = MEMORY )
return MEMORY ;
char * fn = rn - > filename ( ) ;
if ( ! fn )
return UNKNOWN_ROOT_TYPE ;
fl_strlcpy ( buffer , fn , buffer_size ) ;
if ( buffer [ 0 ] = = 0 )
return UNKNOWN_ROOT_TYPE ;
return ( Root ) ( rn - > root ( ) & ROOT_MASK ) ;
}
/**
Returns the number of groups that are contained within a group .
@ -474,8 +588,16 @@ char Fl_Preferences::set( const char *key, int value ) {
@@ -474,8 +588,16 @@ char Fl_Preferences::set( const char *key, int value ) {
*/
char Fl_Preferences : : get ( const char * key , float & value , float defaultValue ) {
const char * v = node - > get ( key ) ;
value = v ? ( float ) atof ( v ) : defaultValue ;
return ( v ! = 0 ) ;
if ( v ) {
if ( rootNode - > root ( ) & C_LOCALE ) {
clocale_sscanf ( v , " %g " , & value ) ;
} else {
value = ( float ) atof ( v ) ;
}
} else {
value = defaultValue ;
}
return ( v ! = NULL ) ;
}
/**
@ -489,7 +611,11 @@ char Fl_Preferences::get( const char *key, float &value, float defaultValue ) {
@@ -489,7 +611,11 @@ char Fl_Preferences::get( const char *key, float &value, float defaultValue ) {
\ return 0 if setting the value failed
*/
char Fl_Preferences : : set ( const char * key , float value ) {
sprintf ( nameBuffer , " %g " , value ) ;
if ( rootNode - > root ( ) & C_LOCALE ) {
clocale_snprintf ( nameBuffer , sizeof ( nameBuffer ) , " %g " , value ) ;
} else {
snprintf ( nameBuffer , sizeof ( nameBuffer ) , " %g " , value ) ;
}
node - > set ( key , nameBuffer ) ;
return 1 ;
}
@ -506,7 +632,11 @@ char Fl_Preferences::set( const char *key, float value ) {
@@ -506,7 +632,11 @@ char Fl_Preferences::set( const char *key, float value ) {
\ return 0 if setting the value failed
*/
char Fl_Preferences : : set ( const char * key , float value , int precision ) {
sprintf ( nameBuffer , " %.*g " , precision , value ) ;
if ( rootNode - > root ( ) & C_LOCALE ) {
clocale_snprintf ( nameBuffer , sizeof ( nameBuffer ) , " %.*g " , precision , value ) ;
} else {
snprintf ( nameBuffer , sizeof ( nameBuffer ) , " %.*g " , precision , value ) ;
}
node - > set ( key , nameBuffer ) ;
return 1 ;
}
@ -523,8 +653,16 @@ char Fl_Preferences::set( const char *key, float value, int precision ) {
@@ -523,8 +653,16 @@ char Fl_Preferences::set( const char *key, float value, int precision ) {
*/
char Fl_Preferences : : get ( const char * key , double & value , double defaultValue ) {
const char * v = node - > get ( key ) ;
value = v ? atof ( v ) : defaultValue ;
return ( v ! = 0 ) ;
if ( v ) {
if ( rootNode - > root ( ) & C_LOCALE ) {
clocale_sscanf ( v , " %lg " , & value ) ;
} else {
value = atof ( v ) ;
}
} else {
value = defaultValue ;
}
return ( v ! = NULL ) ;
}
/**
@ -538,7 +676,11 @@ char Fl_Preferences::get( const char *key, double &value, double defaultValue )
@@ -538,7 +676,11 @@ char Fl_Preferences::get( const char *key, double &value, double defaultValue )
\ return 0 if setting the value failed
*/
char Fl_Preferences : : set ( const char * key , double value ) {
sprintf ( nameBuffer , " %g " , value ) ;
if ( rootNode - > root ( ) & C_LOCALE ) {
clocale_snprintf ( nameBuffer , sizeof ( nameBuffer ) , " %lg " , value ) ;
} else {
snprintf ( nameBuffer , sizeof ( nameBuffer ) , " %lg " , value ) ;
}
node - > set ( key , nameBuffer ) ;
return 1 ;
}
@ -555,7 +697,11 @@ char Fl_Preferences::set( const char *key, double value ) {
@@ -555,7 +697,11 @@ char Fl_Preferences::set( const char *key, double value ) {
\ return 0 if setting the value failed
*/
char Fl_Preferences : : set ( const char * key , double value , int precision ) {
sprintf ( nameBuffer , " %.*g " , precision , value ) ;
if ( rootNode - > root ( ) & C_LOCALE ) {
clocale_snprintf ( nameBuffer , sizeof ( nameBuffer ) , " %.*lg " , precision , value ) ;
} else {
snprintf ( nameBuffer , sizeof ( nameBuffer ) , " %.*lg " , precision , value ) ;
}
node - > set ( key , nameBuffer ) ;
return 1 ;
}
@ -695,19 +841,17 @@ static void *decodeHex( const char *src, int &size ) {
@@ -695,19 +841,17 @@ static void *decodeHex( const char *src, int &size ) {
}
/**
Reads an entry from the group . A default value must be
supplied . The return value indicates if the value was available
( non - zero ) or the default was used ( 0 ) .
' maxSize ' is the maximum length of text that will be read .
Reads a binary entry from the group , ancoded in hexadecimal blocks .
\ param [ in ] key name of entry
\ param [ out ] data value returned from preferences or default value if none was set
\ param [ in ] defaultValue default value to be used if no preference was set
\ param [ in ] defaultValue default value
\ param [ in ] defaultSize size of default value array
\ param [ in ] maxSize maximum length of value
\ param [ in ] maxSize maximum length of value , to receive the number of bytes
read , use the function below instead .
\ return 0 if the default value was used
\ todo maxSize should receive the number of bytes that were read .
\ see Fl_Preferences : : get ( const char * key , void * data , const void * defaultValue , int defaultSize , int * maxSize )
*/
char Fl_Preferences : : get ( const char * key , void * data , const void * defaultValue , int defaultSize , int maxSize ) {
const char * v = node - > get ( key ) ;
@ -723,6 +867,45 @@ char Fl_Preferences::get( const char *key, void *data, const void *defaultValue,
@@ -723,6 +867,45 @@ char Fl_Preferences::get( const char *key, void *data, const void *defaultValue,
return 0 ;
}
/**
Reads a binary entry from the group , ancoded in hexadecimal blocks .
A binary ( not hex ) default value can be supplied .
The return value indicates if the value was available ( non - zero ) or the
default was used ( 0 ) .
` maxSize ` is the maximum length of text that will be read and returns the
actual number of bytes read .
\ param [ in ] key name of entry
\ param [ out ] data value returned from preferences or default value if none was set
\ param [ in ] defaultValue default value to be used if no preference was set
\ param [ in ] defaultSize size of default value array
\ param [ inout ] maxSize maximum length of value and actual number of bytes set
\ return 0 if the default value was used
*/
char Fl_Preferences : : get ( const char * key , void * data , const void * defaultValue , int defaultSize , int * maxSize ) {
if ( ! maxSize | | ! data )
return - 1 ;
int capacity = * maxSize ;
const char * v = node - > get ( key ) ;
if ( v ) {
int nFound ;
void * w = decodeHex ( v , nFound ) ;
int nWrite = ( nFound > capacity ) ? capacity : nFound ;
memmove ( data , w , nWrite ) ;
free ( w ) ;
* maxSize = nWrite ;
return 1 ;
}
if ( defaultValue ) {
int nWrite = ( defaultSize > capacity ) ? capacity : defaultSize ;
memmove ( data , defaultValue , nWrite ) ;
* maxSize = nWrite ;
} else {
* maxSize = 0 ;
}
return 0 ;
}
/**
Reads an entry from the group . A default value must be
supplied . The return value indicates if the value was available
@ -836,13 +1019,40 @@ char Fl_Preferences::getUserdataPath( char *path, int pathlen ) {
@@ -836,13 +1019,40 @@ char Fl_Preferences::getUserdataPath( char *path, int pathlen ) {
}
/**
Writes all preferences to disk . This function works only with
the base preferences group . This function is rarely used as
deleting the base preferences flushes automatically .
Writes preferences to disk if they were modified .
This method can be used to verify that writing a preferences file went well .
Deleting the base preferences object will also write the contents of the
database to disk .
\ return - 1 if anything went wrong , i . e . file could not be opened , permissions
blocked writing , etc .
\ return 0 if the file was written to disk . This does not check if the disk ran
out of space and the file is truncated .
\ return 1 if there no data written to the database and no write attempt
to disk was made .
*/
void Fl_Preferences : : flush ( ) {
if ( rootNode & & node - > dirty ( ) )
rootNode - > write ( ) ;
int Fl_Preferences : : flush ( ) {
int ret = dirty ( ) ;
if ( ret ! = 1 )
return ret ;
return rootNode - > write ( ) ;
}
/**
Check if there were changes to the database that need to be written to disk .
\ return 1 if the database will be written to disk by ` flush ` or destructor .
\ return 0 if the databse is unchanged since the last write operation .
\ return - 1 f there is an internal database error .
*/
int Fl_Preferences : : dirty ( ) {
Node * n = node ;
while ( n & & n - > parent ( ) )
n = n - > parent ( ) ;
if ( ! n )
return - 1 ;
return n - > dirty ( ) ;
}
//-----------------------------------------------------------------------------
@ -909,7 +1119,7 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char
@@ -909,7 +1119,7 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char
filename_ ( 0L ) ,
vendor_ ( 0L ) ,
application_ ( 0L ) ,
root_ ( root )
root_type_ ( root )
{
char * filename = Fl : : system_driver ( ) - > preference_rootnode ( prefs , root , vendor , application ) ;
filename_ = filename ? fl_strdup ( filename ) : 0L ;
@ -925,7 +1135,7 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, con
@@ -925,7 +1135,7 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, con
filename_ ( 0L ) ,
vendor_ ( 0L ) ,
application_ ( 0L ) ,
root_ ( Fl_Preferences : : USER )
root_type_ ( Fl_Preferences : : USER )
{
if ( ! vendor )
@ -950,7 +1160,7 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs )
@@ -950,7 +1160,7 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs )
filename_ ( 0L ) ,
vendor_ ( 0L ) ,
application_ ( 0L ) ,
root_ ( Fl_Preferences : : USER )
root_type_ ( Fl_Preferences : : MEMORY )
{
}
@ -978,15 +1188,15 @@ Fl_Preferences::RootNode::~RootNode() {
@@ -978,15 +1188,15 @@ Fl_Preferences::RootNode::~RootNode() {
int Fl_Preferences : : RootNode : : read ( ) {
if ( ! filename_ ) // RUNTIME preferences, or filename could not be created
return - 1 ;
if ( ( root_ & Fl_Preferences : : CORE ) & & ! ( fileAccess_ & Fl_Preferences : : CORE_READ_OK ) ) {
if ( ( root_type_ & Fl_Preferences : : CORE ) & & ! ( fileAccess_ & Fl_Preferences : : CORE_READ_OK ) ) {
prefs_ - > node - > clearDirtyFlags ( ) ;
return - 1 ;
}
if ( ( ( root_ & Fl_Preferences : : ROOT_MASK ) = = Fl_Preferences : : USER ) & & ! ( fileAccess_ & Fl_Preferences : : USER_READ_OK ) ) {
if ( ( ( root_type_ & Fl_Preferences : : ROOT_MASK ) = = Fl_Preferences : : USER ) & & ! ( fileAccess_ & Fl_Preferences : : USER_READ_OK ) ) {
prefs_ - > node - > clearDirtyFlags ( ) ;
return - 1 ;
}
if ( ( ( root_ & Fl_Preferences : : ROOT_MASK ) = = Fl_Preferences : : SYSTEM ) & & ! ( fileAccess_ & Fl_Preferences : : SYSTEM_READ_OK ) ) {
if ( ( ( root_type_ & Fl_Preferences : : ROOT_MASK ) = = Fl_Preferences : : SYSTEM ) & & ! ( fileAccess_ & Fl_Preferences : : SYSTEM_READ_OK ) ) {
prefs_ - > node - > clearDirtyFlags ( ) ;
return - 1 ;
}
@ -1027,11 +1237,11 @@ int Fl_Preferences::RootNode::read() {
@@ -1027,11 +1237,11 @@ int Fl_Preferences::RootNode::read() {
int Fl_Preferences : : RootNode : : write ( ) {
if ( ! filename_ ) // RUNTIME preferences, or filename could not be created
return - 1 ;
if ( ( root_ & Fl_Preferences : : CORE ) & & ! ( fileAccess_ & Fl_Preferences : : CORE_WRITE_OK ) )
if ( ( root_type_ & Fl_Preferences : : CORE ) & & ! ( fileAccess_ & Fl_Preferences : : CORE_WRITE_OK ) )
return - 1 ;
if ( ( ( root_ & Fl_Preferences : : ROOT_MASK ) = = Fl_Preferences : : USER ) & & ! ( fileAccess_ & Fl_Preferences : : USER_WRITE_OK ) )
if ( ( ( root_type_ & Fl_Preferences : : ROOT_MASK ) = = Fl_Preferences : : USER ) & & ! ( fileAccess_ & Fl_Preferences : : USER_WRITE_OK ) )
return - 1 ;
if ( ( ( root_ & Fl_Preferences : : ROOT_MASK ) = = Fl_Preferences : : SYSTEM ) & & ! ( fileAccess_ & Fl_Preferences : : SYSTEM_WRITE_OK ) )
if ( ( ( root_type_ & Fl_Preferences : : ROOT_MASK ) = = Fl_Preferences : : SYSTEM ) & & ! ( fileAccess_ & Fl_Preferences : : SYSTEM_WRITE_OK ) )
return - 1 ;
fl_make_path_for_file ( filename_ ) ;
FILE * f = fl_fopen ( filename_ , " wb " ) ;
@ -1111,10 +1321,10 @@ char Fl_Preferences::RootNode::getPath( char *path, int pathlen ) {
@@ -1111,10 +1321,10 @@ char Fl_Preferences::RootNode::getPath( char *path, int pathlen ) {
}
// create a node that represents a group
// - path must be a single word, prferable alnum(), dot and underscore only. Space is ok.
// - path must be a single word, pre ferable alnum(), dot and underscore only. Space is ok.
Fl_Preferences : : Node : : Node ( const char * path ) {
if ( path ) path_ = fl_strdup ( path ) ; else path_ = 0 ;
child_ = 0 ; next_ = 0 ; parent_ = 0 ;
first_ child_ = 0 ; next_ = 0 ; parent_ = 0 ;
entry_ = 0 ;
nEntry_ = NEntry_ = 0 ;
dirty_ = 0 ;
@ -1125,12 +1335,12 @@ Fl_Preferences::Node::Node( const char *path ) {
@@ -1125,12 +1335,12 @@ Fl_Preferences::Node::Node( const char *path ) {
}
void Fl_Preferences : : Node : : deleteAllChildren ( ) {
Node * nx ;
for ( Node * nd = child_ ; nd ; nd = nx ) {
nx = nd - > next_ ;
delete nd ;
Node * ne xt_node = NULL ;
for ( Node * curre nt_no de = first_ child_; curre nt_no de ; curre nt_no de = ne xt_node ) {
ne xt_node = curre nt_no de - > next_ ;
delete curre nt_no de ;
}
child_ = 0 L;
first_ child_ = NUL L;
dirty_ = 1 ;
updateIndex ( ) ;
}
@ -1139,16 +1349,16 @@ void Fl_Preferences::Node::deleteAllEntries() {
@@ -1139,16 +1349,16 @@ void Fl_Preferences::Node::deleteAllEntries() {
if ( entry_ ) {
for ( int i = 0 ; i < nEntry_ ; i + + ) {
if ( entry_ [ i ] . name ) {
free ( entry_ [ i ] . name ) ;
entry_ [ i ] . name = 0 L;
: : free ( entry_ [ i ] . name ) ;
entry_ [ i ] . name = NUL L;
}
if ( entry_ [ i ] . value ) {
free ( entry_ [ i ] . value ) ;
entry_ [ i ] . value = 0 L;
: : free ( entry_ [ i ] . value ) ;
entry_ [ i ] . value = NUL L;
}
}
free ( entry_ ) ;
entry_ = 0 L;
entry_ = NUL L;
nEntry_ = 0 ;
NEntry_ = 0 ;
}
@ -1157,22 +1367,22 @@ void Fl_Preferences::Node::deleteAllEntries() {
@@ -1157,22 +1367,22 @@ void Fl_Preferences::Node::deleteAllEntries() {
// delete this and all depending nodes
Fl_Preferences : : Node : : ~ Node ( ) {
next_ = NULL ;
parent_ = NULL ;
deleteAllChildren ( ) ;
deleteAllEntries ( ) ;
deleteIndex ( ) ;
if ( path_ ) {
free ( path_ ) ;
path_ = 0 L;
: : free ( path_ ) ;
path_ = NUL L;
}
next_ = 0L ;
parent_ = 0L ;
}
// recursively check if any entry is dirty (was changed after loading a fresh prefs file)
char Fl_Preferences : : Node : : dirty ( ) {
if ( dirty_ ) return 1 ;
if ( next_ & & next_ - > dirty ( ) ) return 1 ;
if ( child_ & & child_ - > dirty ( ) ) return 1 ;
if ( first_ child_ & & first_ child_- > dirty ( ) ) return 1 ;
return 0 ;
}
@ -1181,7 +1391,7 @@ void Fl_Preferences::Node::clearDirtyFlags() {
@@ -1181,7 +1391,7 @@ void Fl_Preferences::Node::clearDirtyFlags() {
Fl_Preferences : : Node * nd = this ;
while ( nd ) {
nd - > dirty_ = 0 ;
if ( nd - > child_ ) nd - > child_ - > clearDirtyFlags ( ) ;
if ( nd - > first_ child_ ) nd - > first_ child_- > clearDirtyFlags ( ) ;
nd = nd - > next_ ;
}
}
@ -1214,7 +1424,7 @@ int Fl_Preferences::Node::write( FILE *f ) {
@@ -1214,7 +1424,7 @@ int Fl_Preferences::Node::write( FILE *f ) {
else
fprintf ( f , " %s \n " , entry_ [ i ] . name ) ;
}
if ( child_ ) child_ - > write ( f ) ;
if ( first_ child_ ) first_ child_- > write ( f ) ;
dirty_ = 0 ;
return 0 ;
}
@ -1222,8 +1432,8 @@ int Fl_Preferences::Node::write( FILE *f ) {
@@ -1222,8 +1432,8 @@ int Fl_Preferences::Node::write( FILE *f ) {
// set the parent node and create the full path
void Fl_Preferences : : Node : : setParent ( Node * pn ) {
parent_ = pn ;
next_ = pn - > child_ ;
pn - > child_ = this ;
next_ = pn - > first_ child_;
pn - > first_ child_ = this ;
sprintf ( nameBuffer , " %s/%s " , pn - > path_ , path_ ) ;
free ( path_ ) ;
path_ = fl_strdup ( nameBuffer ) ;
@ -1234,7 +1444,7 @@ Fl_Preferences::RootNode *Fl_Preferences::Node::findRoot() {
@@ -1234,7 +1444,7 @@ Fl_Preferences::RootNode *Fl_Preferences::Node::findRoot() {
Node * n = this ;
do {
if ( n - > top_ )
return n - > root_ ;
return n - > root_node_ ;
n = n - > parent ( ) ;
} while ( n ) ;
return 0L ;
@ -1346,7 +1556,7 @@ Fl_Preferences::Node *Fl_Preferences::Node::find( const char *path ) {
@@ -1346,7 +1556,7 @@ Fl_Preferences::Node *Fl_Preferences::Node::find( const char *path ) {
return this ;
if ( path [ len ] = = ' / ' ) {
Node * nd ;
for ( nd = child_ ; nd ; nd = nd - > next_ ) {
for ( nd = first_ child_; nd ; nd = nd - > next_ ) {
Node * nn = nd - > find ( path ) ;
if ( nn ) return nn ;
}
@ -1392,7 +1602,7 @@ Fl_Preferences::Node *Fl_Preferences::Node::search( const char *path, int offset
@@ -1392,7 +1602,7 @@ Fl_Preferences::Node *Fl_Preferences::Node::search( const char *path, int offset
if ( len > 0 & & path [ len ] = = 0 )
return this ;
if ( len < = 0 | | path [ len ] = = ' / ' ) {
for ( Node * nd = child_ ; nd ; nd = nd - > next_ ) {
for ( Node * nd = first_ child_; nd ; nd = nd - > next_ ) {
Node * nn = nd - > search ( path , offset ) ;
if ( nn ) return nn ;
}
@ -1408,7 +1618,7 @@ int Fl_Preferences::Node::nChildren() {
@@ -1408,7 +1618,7 @@ int Fl_Preferences::Node::nChildren() {
return nIndex_ ;
} else {
int cnt = 0 ;
for ( Node * nd = child_ ; nd ; nd = nd - > next_ )
for ( Node * nd = first_ child_; nd ; nd = nd - > next_ )
cnt + + ;
return cnt ;
}
@ -1444,7 +1654,7 @@ Fl_Preferences::Node *Fl_Preferences::Node::childNode( int ix ) {
@@ -1444,7 +1654,7 @@ Fl_Preferences::Node *Fl_Preferences::Node::childNode( int ix ) {
int n = nChildren ( ) ;
ix = n - ix - 1 ;
Node * nd ;
for ( nd = child_ ; nd ; nd = nd - > next_ ) {
for ( nd = first_ child_; nd ; nd = nd - > next_ ) {
if ( ! ix - - ) break ;
if ( ! nd ) break ;
}
@ -1454,23 +1664,25 @@ Fl_Preferences::Node *Fl_Preferences::Node::childNode( int ix ) {
@@ -1454,23 +1664,25 @@ Fl_Preferences::Node *Fl_Preferences::Node::childNode( int ix ) {
// remove myself from the list and delete me (and all children)
char Fl_Preferences : : Node : : remove ( ) {
Node * nd = 0 , * np ;
if ( parent ( ) ) {
nd = parent ( ) - > child_ ; np = 0L ;
Node * nd = NULL , * np = NULL ;
Node * parent_node = parent ( ) ;
if ( parent_node ) {
nd = parent_node - > first_child_ ; np = NULL ;
for ( ; nd ; np = nd , nd = nd - > next_ ) {
if ( nd = = this ) {
if ( np )
np - > next_ = nd - > n ext_ ;
np - > next_ = next_ ;
else
parent ( ) - > child_ = nd - > next_ ;
parent_node - > first_child_ = next_ ;
next_ = NULL ;
break ;
}
}
parent ( ) - > dirty_ = 1 ;
parent ( ) - > updateIndex ( ) ;
parent_node - > dirty_ = 1 ;
parent_node - > updateIndex ( ) ;
}
delete this ;
return ( nd ! = 0 ) ;
return ( nd ! = NULL ) ;
}
void Fl_Preferences : : Node : : createIndex ( ) {
@ -1482,7 +1694,7 @@ void Fl_Preferences::Node::createIndex() {
@@ -1482,7 +1694,7 @@ void Fl_Preferences::Node::createIndex() {
}
Node * nd ;
int i = 0 ;
for ( nd = child_ ; nd ; nd = nd - > next_ , i + + ) {
for ( nd = first_ child_; nd ; nd = nd - > next_ , i + + ) {
index_ [ n - i - 1 ] = nd ;
}
nIndex_ = n ;
@ -1494,9 +1706,10 @@ void Fl_Preferences::Node::updateIndex() {
@@ -1494,9 +1706,10 @@ void Fl_Preferences::Node::updateIndex() {
}
void Fl_Preferences : : Node : : deleteIndex ( ) {
if ( index_ ) free ( index_ ) ;
if ( index_ )
: : free ( index_ ) ;
index_ = NULL ;
NIndex_ = nIndex_ = 0 ;
index_ = 0 ;
indexed_ = 0 ;
}