2 // "$Id: Fl_Preferences.cxx 8291 2011-01-19 06:33:48Z manolo $"
4 // Preferences methods for the Fast Light Tool Kit (FLTK).
6 // Copyright 2002-2010 by Matthias Melcher.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
29 #include <FL/Fl_Preferences.H>
30 #include <FL/Fl_Plugin.H>
31 #include <FL/filename.H>
36 #include <FL/fl_utf8.h>
41 #if defined(WIN32) && !defined(__CYGWIN__)
45 // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
46 // on Windows, which is supposed to be POSIX compliant...
47 # define access _access
49 #elif defined (__APPLE__)
50 # include <ApplicationServices/ApplicationServices.h>
61 // function pointer for the UuidCreate Function
62 // RPC_STATUS RPC_ENTRY UuidCreate(UUID __RPC_FAR *Uuid);
63 typedef RPC_STATUS (WINAPI
* uuid_func
)(UUID __RPC_FAR
*Uuid
);
65 # include <sys/time.h>
72 char Fl_Preferences::nameBuffer
[128];
73 char Fl_Preferences::uuidBuffer
[40];
74 Fl_Preferences
*Fl_Preferences::runtimePrefs
= 0;
77 * Returns a UUID as generated by the system.
79 * A UUID is a "universally unique identifier" which is commonly used in
80 * configuration files to create identities. A UUID in ASCII looks like this:
81 * <tt>937C4900-51AA-4C11-8DD3-7AB59944F03E</tt>. It has always 36 bytes plus
84 * \return a pointer to a static buffer containing the new UUID in ASCII format.
85 * The buffer is overwritten during every call to this function!
87 const char *Fl_Preferences::newUUID() {
89 CFUUIDRef theUUID
= CFUUIDCreate(NULL
);
90 CFUUIDBytes b
= CFUUIDGetUUIDBytes(theUUID
);
91 sprintf(uuidBuffer
, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
92 b
.byte0
, b
.byte1
, b
.byte2
, b
.byte3
, b
.byte4
, b
.byte5
, b
.byte6
, b
.byte7
,
93 b
.byte8
, b
.byte9
, b
.byte10
, b
.byte11
, b
.byte12
, b
.byte13
, b
.byte14
, b
.byte15
);
96 // First try and use the win API function UuidCreate(), but if that is not
97 // available, fall back to making something up from scratch.
98 // We do not want to link against the Rpcrt4.dll, as we will rarely use it,
99 // so we load the DLL dynamically, if it is available, and work from there.
100 static HMODULE hMod
= NULL
;
105 if (!hMod
) { // first time in?
106 hMod
= LoadLibrary("Rpcrt4.dll");
109 if (hMod
) { // do we have a usable handle to Rpcrt4.dll?
110 uuid_func uuid_crt
= (uuid_func
)GetProcAddress(hMod
, "UuidCreate");
111 if (uuid_crt
!= NULL
) {
112 RPC_STATUS rpc_res
= uuid_crt(pu
);
113 if ( // is the return status OK for our needs?
114 (rpc_res
== RPC_S_OK
) || // all is well
115 (rpc_res
== RPC_S_UUID_LOCAL_ONLY
) || // only unique to this machine
116 (rpc_res
== RPC_S_UUID_NO_ADDRESS
) // probably only locally unique
119 sprintf(uuidBuffer
, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
120 pu
->Data1
, pu
->Data2
, pu
->Data3
, pu
->Data4
[0], pu
->Data4
[1],
121 pu
->Data4
[2], pu
->Data4
[3], pu
->Data4
[4],
122 pu
->Data4
[5], pu
->Data4
[6], pu
->Data4
[7]);
126 if (got_uuid
== 0) { // did not make a UUID - use fallback logic
128 time_t t
= time(0); // first 4 byte
129 b
[0] = (unsigned char)t
;
130 b
[1] = (unsigned char)(t
>>8);
131 b
[2] = (unsigned char)(t
>>16);
132 b
[3] = (unsigned char)(t
>>24);
133 int r
= rand(); // four more bytes
134 b
[4] = (unsigned char)r
;
135 b
[5] = (unsigned char)(r
>>8);
136 b
[6] = (unsigned char)(r
>>16);
137 b
[7] = (unsigned char)(r
>>24);
138 // Now we try to find 4 more "random" bytes. We extract the
139 // lower 4 bytes from the address of t - it is created on the
140 // stack so *might* be in a different place each time...
141 // This is now done via a union to make it compile OK on 64-bit systems.
142 union { void *pv
; unsigned char a
[sizeof(void*)]; } v
;
144 // NOTE: This assume that all WinXX systems are little-endian
149 TCHAR name
[MAX_COMPUTERNAME_LENGTH
+ 1]; // only used to make last four bytes
150 DWORD nSize
= MAX_COMPUTERNAME_LENGTH
+ 1;
151 // GetComputerName() does not depend on any extra libs, and returns something
152 // analogous to gethostname()
153 GetComputerName(name
, &nSize
);
154 // use the first 4 TCHAR's of the name to create the last 4 bytes of our UUID
155 for (int ii
= 0; ii
< 4; ii
++) {
156 b
[12 + ii
] = (unsigned char)name
[ii
];
158 sprintf(uuidBuffer
, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
159 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7],
160 b
[8], b
[9], b
[10], b
[11], b
[12], b
[13], b
[14], b
[15]);
163 // warning Unix implementation of Fl_Preferences::newUUID() incomplete!
164 // #include <uuid/uuid.h>
165 // void uuid_generate(uuid_t out);
167 time_t t
= time(0); // first 4 byte
168 b
[0] = (unsigned char)t
;
169 b
[1] = (unsigned char)(t
>>8);
170 b
[2] = (unsigned char)(t
>>16);
171 b
[3] = (unsigned char)(t
>>24);
172 int r
= rand(); // four more bytes
173 b
[4] = (unsigned char)r
;
174 b
[5] = (unsigned char)(r
>>8);
175 b
[6] = (unsigned char)(r
>>16);
176 b
[7] = (unsigned char)(r
>>24);
177 unsigned long a
= (unsigned long)&t
; // four more bytes
178 b
[8] = (unsigned char)a
;
179 b
[9] = (unsigned char)(a
>>8);
180 b
[10] = (unsigned char)(a
>>16);
181 b
[11] = (unsigned char)(a
>>24);
182 // Now we try to find 4 more "random" bytes. We extract the
183 // lower 4 bytes from the address of t - it is created on the
184 // stack so *might* be in a different place each time...
185 // This is now done via a union to make it compile OK on 64-bit systems.
186 union { void *pv
; unsigned char a
[sizeof(void*)]; } v
;
188 // NOTE: May need to handle big- or little-endian systems here
190 b
[8] = v
.a
[sizeof(void*) - 1];
191 b
[9] = v
.a
[sizeof(void*) - 2];
192 b
[10] = v
.a
[sizeof(void*) - 3];
193 b
[11] = v
.a
[sizeof(void*) - 4];
194 # else /* data ordered for a little-endian system */
200 char name
[80]; // last four bytes
201 gethostname(name
, 79);
202 memcpy(b
+12, name
, 4);
203 sprintf(uuidBuffer
, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
204 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7],
205 b
[8], b
[9], b
[10], b
[11], b
[12], b
[13], b
[14], b
[15]);
212 The constructor creates a group that manages name/value pairs and
213 child groups. Groups are ready for reading and writing at any time.
214 The root argument is either Fl_Preferences::USER
215 or Fl_Preferences::SYSTEM.
217 This constructor creates the <i>base</i> instance for all
218 following entries and reads existing databases into memory. The
219 vendor argument is a unique text string identifying the
220 development team or vendor of an application. A domain name or
221 an EMail address are great unique names, e.g.
222 "researchATmatthiasm.com" or "fltk.org". The
223 application argument can be the working title or final
224 name of your application. Both vendor and
225 application must be valid relative UNIX pathnames and
226 may contain '/'s to create deeper file structures.
228 A set of Preferences marked "run-time" exists exactly one per application and
229 only as long as the application runs. It can be used as a database for
230 volatile information. FLTK uses it to register plugins at run-time.
232 \param[in] root can be \c USER or \c SYSTEM for user specific or system wide
234 \param[in] vendor unique text describing the company or author of this file
235 \param[in] application unique text describing the application
237 Fl_Preferences::Fl_Preferences( Root root
, const char *vendor
, const char *application
) {
238 node
= new Node( "." );
239 rootNode
= new RootNode( this, root
, vendor
, application
);
240 node
->setRoot(rootNode
);
244 \brief Use this constructor to create or read a preferences file at an
245 arbitrary position in the file system.
247 The file name is generated in the form
248 <tt><i>path</i>/<i>application</i>.prefs</tt>. If \p application
249 is \c NULL, \p path must contain the full file name.
251 \param[in] path path to the directory that contains the preferences file
252 \param[in] vendor unique text describing the company or author of this file
253 \param[in] application unique text describing the application
255 Fl_Preferences::Fl_Preferences( const char *path
, const char *vendor
, const char *application
) {
256 node
= new Node( "." );
257 rootNode
= new RootNode( this, path
, vendor
, application
);
258 node
->setRoot(rootNode
);
262 \brief Generate or read a new group of entries within another group.
264 Use the \p group argument to name the group that you would like to access.
265 \p Group can also contain a path to a group further down the hierarchy by
266 separating group names with a forward slash '/'.
268 \param[in] parent reference object for the new group
269 \param[in] group name of the group to access (may contain '/'s)
271 Fl_Preferences::Fl_Preferences( Fl_Preferences
&parent
, const char *group
) {
272 rootNode
= parent
.rootNode
;
273 node
= parent
.node
->addChild( group
);
277 \brief Create or access a group of preferences using a name.
278 \param[in] parent the parameter parent is a pointer to the parent group.
279 \p Parent may be \p NULL. It then refers to an application internal
280 database which exists only once, and remains in RAM only until the
281 application quits. This database is used to manage plugins and other
282 data indexes by strings.
283 \param[in] group a group name that is used as a key into the database
284 \see Fl_Preferences( Fl_Preferences&, const char *group )
286 Fl_Preferences::Fl_Preferences( Fl_Preferences
*parent
, const char *group
) {
289 runtimePrefs
= new Fl_Preferences();
290 runtimePrefs
->node
= new Node( "." );
291 runtimePrefs
->rootNode
= new RootNode( runtimePrefs
);
292 runtimePrefs
->node
->setRoot(rootNode
);
294 parent
= runtimePrefs
;
296 rootNode
= parent
->rootNode
;
297 node
= parent
->node
->addChild( group
);
301 \brief Open a child group using a given index.
303 Use the \p groupIndex argument to find the group that you would like to access.
304 If the given index is invalid (negative or too high), a new group is created
305 with a UUID as a name.
307 The index needs to be fixed. It is currently backward. Index 0 points
308 to the last member in the 'list' of preferences.
310 \param[in] parent reference object for the new group
311 \param[in] groupIndex zero based index into child groups
313 Fl_Preferences::Fl_Preferences( Fl_Preferences
&parent
, int groupIndex
) {
314 rootNode
= parent
.rootNode
;
315 if (groupIndex
<0 || groupIndex
>=parent
.groups()) {
316 node
= parent
.node
->addChild( newUUID() );
318 node
= parent
.node
->childNode( groupIndex
);
323 \see Fl_Preferences( Fl_Preferences&, int groupIndex )
325 Fl_Preferences::Fl_Preferences( Fl_Preferences
*parent
, int groupIndex
) {
326 rootNode
= parent
->rootNode
;
327 if (groupIndex
<0 || groupIndex
>=parent
->groups()) {
328 node
= parent
->node
->addChild( newUUID() );
330 node
= parent
->node
->childNode( groupIndex
);
335 Create a new dataset access point using a dataset ID.
337 ID's are a great way to remember shortcuts to database entries that are deeply
338 nested in a preferences database, as long as the database root is not deleted.
339 An ID can be retrieved from any Fl_Preferences dataset, and can then be used
340 to create multiple new references to the same dataset.
342 ID's can be put very helpful when put into the <tt>user_data()</tt> field of
345 Fl_Preferences::Fl_Preferences( Fl_Preferences::ID id
) {
347 rootNode
= node
->findRoot();
351 Create another reference to a Preferences group.
353 Fl_Preferences::Fl_Preferences(const Fl_Preferences
&rhs
)
355 rootNode(rhs
.rootNode
)
359 Assign another reference to a Preference group.
361 Fl_Preferences
&Fl_Preferences::operator=(const Fl_Preferences
&rhs
) {
364 rootNode
= rhs
.rootNode
;
370 The destructor removes allocated resources. When used on the
371 \em base preferences group, the destructor flushes all
372 changes to the preferences file and deletes all internal
375 The destructor does not remove any data from the database. It merely
376 deletes your reference to the database.
378 Fl_Preferences::~Fl_Preferences() {
379 if (node
&& !node
->parent()) delete rootNode
;
380 // DO NOT delete nodes! The root node will do that after writing the preferences
381 // zero all pointer to avoid memory errors, even though
382 // Valgrind does not complain (Cygwind does though)
388 Returns the number of groups that are contained within a group.
390 \return 0 for no groups at all
392 int Fl_Preferences::groups() {
393 return node
->nChildren();
397 Returns the name of the Nth (\p num_group) group.
398 There is no guaranteed order of group names. The index must
399 be within the range given by groups().
401 \param[in] num_group number indexing the requested group
402 \return 'C' string pointer to the group name
404 const char *Fl_Preferences::group( int num_group
) {
405 return node
->child( num_group
);
409 Returns non-zero if a group with this name exists.
410 Group names are relative to the Preferences node and can contain a path.
411 "." describes the current node, "./" describes the topmost node.
412 By preceding a groupname with a "./", its path becomes relative to the topmost node.
414 \param[in] key name of group that is searched for
415 \return 0 if no group by that name was found
417 char Fl_Preferences::groupExists( const char *key
) {
418 return node
->search( key
) ? 1 : 0 ;
424 Removes a group and all keys and groups within that group
427 \param[in] group name of the group to delete
428 \return 0 if call failed
430 char Fl_Preferences::deleteGroup( const char *group
) {
431 Node
*nd
= node
->search( group
);
432 if ( nd
) return nd
->remove();
439 char Fl_Preferences::deleteAllGroups() {
440 node
->deleteAllChildren();
445 Returns the number of entries (name/value pairs) in a group.
447 \return number of entries
449 int Fl_Preferences::entries() {
450 return node
->nEntry();
454 Returns the name of an entry. There is no guaranteed order of
455 entry names. The index must be within the range given by
458 \param[in] index number indexing the requested entry
459 \return pointer to value cstring
461 const char *Fl_Preferences::entry( int index
) {
462 return node
->entry(index
).name
;
466 Returns non-zero if an entry with this name exists.
468 \param[in] key name of entry that is searched for
469 \return 0 if entry was not found
471 char Fl_Preferences::entryExists( const char *key
) {
472 return node
->getEntry( key
)>=0 ? 1 : 0 ;
476 Deletes a single name/value pair.
478 This function removes the entry \p key from the database.
480 \param[in] key name of entry to delete
481 \return 0 if deleting the entry failed
483 char Fl_Preferences::deleteEntry( const char *key
) {
484 return node
->deleteEntry( key
);
490 char Fl_Preferences::deleteAllEntries() {
491 node
->deleteAllEntries();
496 Delete all groups and all entries.
498 char Fl_Preferences::clear() {
499 char ret1
= deleteAllGroups();
500 char ret2
= deleteAllEntries();
505 Reads an entry from the group. A default value must be
506 supplied. The return value indicates if the value was available
507 (non-zero) or the default was used (0).
509 \param[in] key name of entry
510 \param[out] value returned from preferences or default value if none was set
511 \param[in] defaultValue default value to be used if no preference was set
512 \return 0 if the default value was used
514 char Fl_Preferences::get( const char *key
, int &value
, int defaultValue
) {
515 const char *v
= node
->get( key
);
516 value
= v
? atoi( v
) : defaultValue
;
521 Sets an entry (name/value pair). The return value indicates if there
522 was a problem storing the data in memory. However it does not
523 reflect if the value was actually stored in the preferences
526 \param[in] key name of entry
527 \param[in] value set this entry to \p value
528 \return 0 if setting the value failed
530 char Fl_Preferences::set( const char *key
, int value
) {
531 sprintf( nameBuffer
, "%d", value
);
532 node
->set( key
, nameBuffer
);
537 Reads an entry from the group. A default value must be
538 supplied. The return value indicates if the value was available
539 (non-zero) or the default was used (0).
541 \param[in] key name of entry
542 \param[out] value returned from preferences or default value if none was set
543 \param[in] defaultValue default value to be used if no preference was set
544 \return 0 if the default value was used
546 char Fl_Preferences::get( const char *key
, float &value
, float defaultValue
) {
547 const char *v
= node
->get( key
);
548 value
= v
? (float)atof( v
) : defaultValue
;
553 Sets an entry (name/value pair). The return value indicates if there
554 was a problem storing the data in memory. However it does not
555 reflect if the value was actually stored in the preferences
558 \param[in] key name of entry
559 \param[in] value set this entry to \p value
560 \return 0 if setting the value failed
562 char Fl_Preferences::set( const char *key
, float value
) {
563 sprintf( nameBuffer
, "%g", value
);
564 node
->set( key
, nameBuffer
);
569 Sets an entry (name/value pair). The return value indicates if there
570 was a problem storing the data in memory. However it does not
571 reflect if the value was actually stored in the preferences
574 \param[in] key name of entry
575 \param[in] value set this entry to \p value
576 \param[in] precision number of decimal digits to represent value
577 \return 0 if setting the value failed
579 char Fl_Preferences::set( const char *key
, float value
, int precision
) {
580 sprintf( nameBuffer
, "%.*g", precision
, value
);
581 node
->set( key
, nameBuffer
);
586 Reads an entry from the group. A default value must be
587 supplied. The return value indicates if the value was available
588 (non-zero) or the default was used (0).
590 \param[in] key name of entry
591 \param[out] value returned from preferences or default value if none was set
592 \param[in] defaultValue default value to be used if no preference was set
593 \return 0 if the default value was used
595 char Fl_Preferences::get( const char *key
, double &value
, double defaultValue
) {
596 const char *v
= node
->get( key
);
597 value
= v
? atof( v
) : defaultValue
;
602 Sets an entry (name/value pair). The return value indicates if there
603 was a problem storing the data in memory. However it does not
604 reflect if the value was actually stored in the preferences
607 \param[in] key name of entry
608 \param[in] value set this entry to \p value
609 \return 0 if setting the value failed
611 char Fl_Preferences::set( const char *key
, double value
) {
612 sprintf( nameBuffer
, "%g", value
);
613 node
->set( key
, nameBuffer
);
618 Sets an entry (name/value pair). The return value indicates if there
619 was a problem storing the data in memory. However it does not
620 reflect if the value was actually stored in the preferences
623 \param[in] key name of entry
624 \param[in] value set this entry to \p value
625 \param[in] precision number of decimal digits to represent value
626 \return 0 if setting the value failed
628 char Fl_Preferences::set( const char *key
, double value
, int precision
) {
629 sprintf( nameBuffer
, "%.*g", precision
, value
);
630 node
->set( key
, nameBuffer
);
634 // remove control sequences from a string
635 static char *decodeText( const char *src
) {
638 for ( ; *s
; s
++, len
++ ) {
640 if ( isdigit( s
[1] ) ) {
647 char *dst
= (char*)malloc( len
+1 ), *d
= dst
;
648 for ( s
= src
; *s
; s
++ ) {
651 if ( s
[1] == '\\' ) { *d
++ = c
; s
++; }
652 else if ( s
[1] == 'n' ) { *d
++ = '\n'; s
++; }
653 else if ( s
[1] == 'r' ) { *d
++ = '\r'; s
++; }
654 else if ( isdigit( s
[1] ) ) { *d
++ = ((s
[1]-'0')<<6) + ((s
[2]-'0')<<3) + (s
[3]-'0'); s
+=3; }
665 Reads an entry from the group. A default value must be
666 supplied. The return value indicates if the value was available
667 (non-zero) or the default was used (0).
668 'maxSize' is the maximum length of text that will be read.
669 The text buffer must allow for one additional byte for a trailling zero.
671 \param[in] key name of entry
672 \param[out] text returned from preferences or default value if none was set
673 \param[in] defaultValue default value to be used if no preference was set
674 \param[in] maxSize maximum length of value plus one byte for a trailing zero
675 \return 0 if the default value was used
677 char Fl_Preferences::get( const char *key
, char *text
, const char *defaultValue
, int maxSize
) {
678 const char *v
= node
->get( key
);
679 if ( v
&& strchr( v
, '\\' ) ) {
680 char *w
= decodeText( v
);
681 strlcpy(text
, w
, maxSize
);
685 if ( !v
) v
= defaultValue
;
686 if ( v
) strlcpy(text
, v
, maxSize
);
688 return ( v
!= defaultValue
);
692 Reads an entry from the group. A default value must be
693 supplied. The return value indicates if the value was available
694 (non-zero) or the default was used (0). get() allocates memory of
695 sufficient size to hold the value. The buffer must be free'd by
696 the developer using 'free(value)'.
698 \param[in] key name of entry
699 \param[out] text returned from preferences or default value if none was set
700 \param[in] defaultValue default value to be used if no preference was set
701 \return 0 if the default value was used
703 char Fl_Preferences::get( const char *key
, char *&text
, const char *defaultValue
) {
704 const char *v
= node
->get( key
);
705 if ( v
&& strchr( v
, '\\' ) ) {
706 text
= decodeText( v
);
709 if ( !v
) v
= defaultValue
;
714 return ( v
!= defaultValue
);
718 Sets an entry (name/value pair). The return value indicates if there
719 was a problem storing the data in memory. However it does not
720 reflect if the value was actually stored in the preferences
723 \param[in] key name of entry
724 \param[in] text set this entry to \p value
725 \return 0 if setting the value failed
727 char Fl_Preferences::set( const char *key
, const char *text
) {
728 const char *s
= text
? text
: "";
730 for ( ; *s
; s
++ ) { n
++; if ( *s
<32 || *s
=='\\' || *s
==0x7f ) ns
+=4; }
732 char *buffer
= (char*)malloc( n
+ns
+1 ), *d
= buffer
;
733 for ( s
=text
; *s
; ) {
735 if ( c
=='\\' ) { *d
++ = '\\'; *d
++ = '\\'; s
++; }
736 else if ( c
=='\n' ) { *d
++ = '\\'; *d
++ = 'n'; s
++; }
737 else if ( c
=='\r' ) { *d
++ = '\\'; *d
++ = 'r'; s
++; }
738 else if ( c
<32 || c
==0x7f )
739 { *d
++ = '\\'; *d
++ = '0'+((c
>>6)&3); *d
++ = '0'+((c
>>3)&7); *d
++ = '0'+(c
&7); s
++; }
743 node
->set( key
, buffer
);
747 node
->set( key
, text
);
751 // convert a hex string to binary data
752 static void *decodeHex( const char *src
, int &size
) {
753 size
= strlen( src
)/2;
754 unsigned char *data
= (unsigned char*)malloc( size
), *d
= data
;
756 for ( int i
=size
; i
>0; i
-- ) {
758 char x
= tolower(*s
++);
759 if ( x
>= 'a' ) v
= x
-'a'+10; else v
= x
-'0';
762 if ( x
>= 'a' ) v
+= x
-'a'+10; else v
+= x
-'0';
769 Reads an entry from the group. A default value must be
770 supplied. The return value indicates if the value was available
771 (non-zero) or the default was used (0).
772 'maxSize' is the maximum length of text that will be read.
774 \param[in] key name of entry
775 \param[out] data value returned from preferences or default value if none was set
776 \param[in] defaultValue default value to be used if no preference was set
777 \param[in] defaultSize size of default value array
778 \param[in] maxSize maximum length of value
779 \return 0 if the default value was used
781 \todo maxSize should receive the number of bytes that were read.
783 char Fl_Preferences::get( const char *key
, void *data
, const void *defaultValue
, int defaultSize
, int maxSize
) {
784 const char *v
= node
->get( key
);
787 void *w
= decodeHex( v
, dsize
);
788 memmove( data
, w
, dsize
>maxSize
?maxSize
:dsize
);
793 memmove( data
, defaultValue
, defaultSize
>maxSize
?maxSize
:defaultSize
);
798 Reads an entry from the group. A default value must be
799 supplied. The return value indicates if the value was available
800 (non-zero) or the default was used (0). get() allocates memory of
801 sufficient size to hold the value. The buffer must be free'd by
802 the developer using 'free(value)'.
804 \param[in] key name of entry
805 \param[out] data returned from preferences or default value if none was set
806 \param[in] defaultValue default value to be used if no preference was set
807 \param[in] defaultSize size of default value array
808 \return 0 if the default value was used
810 char Fl_Preferences::get( const char *key
, void *&data
, const void *defaultValue
, int defaultSize
) {
811 const char *v
= node
->get( key
);
814 data
= decodeHex( v
, dsize
);
817 if ( defaultValue
) {
818 data
= (void*)malloc( defaultSize
);
819 memmove( data
, defaultValue
, defaultSize
);
827 Sets an entry (name/value pair). The return value indicates if there
828 was a problem storing the data in memory. However it does not
829 reflect if the value was actually stored in the preferences
832 \param[in] key name of entry
833 \param[in] data set this entry to \p value
834 \param[in] dsize size of data array
835 \return 0 if setting the value failed
837 char Fl_Preferences::set( const char *key
, const void *data
, int dsize
) {
838 char *buffer
= (char*)malloc( dsize
*2+1 ), *d
= buffer
;;
839 unsigned char *s
= (unsigned char*)data
;
840 for ( ; dsize
>0; dsize
-- ) {
841 static char lu
[] = "0123456789abcdef";
842 unsigned char v
= *s
++;
847 node
->set( key
, buffer
);
853 Returns the size of the value part of an entry.
855 \param[in] key name of entry
856 \return size of value
858 int Fl_Preferences::size( const char *key
) {
859 const char *v
= node
->get( key
);
860 return v
? strlen( v
) : 0 ;
864 \brief Creates a path that is related to the preferences file and
865 that is usable for additional application data.
867 This function creates a directory that is named after the preferences
868 database without the \c .prefs extension and located in the same directory.
869 It then fills the given buffer with the complete path name.
873 Fl_Preferences prefs( USER, "matthiasm.com", "test" );
874 char path[FL_PATH_MAX];
875 prefs.getUserdataPath( path );
877 creates the preferences database in (MS Windows):
879 c:/Documents and Settings/matt/Application Data/matthiasm.com/test.prefs
881 and returns the userdata path:
883 c:/Documents and Settings/matt/Application Data/matthiasm.com/test/
886 \param[out] path buffer for user data path
887 \param[in] pathlen size of path buffer (should be at least \c FL_PATH_MAX)
888 \return 0 if path was not created or pathname can't fit into buffer
890 char Fl_Preferences::getUserdataPath( char *path
, int pathlen
) {
892 return rootNode
->getPath( path
, pathlen
);
897 Writes all preferences to disk. This function works only with
898 the base preferences group. This function is rarely used as
899 deleting the base preferences flushes automatically.
901 void Fl_Preferences::flush() {
902 if ( rootNode
&& node
->dirty() )
906 //-----------------------------------------------------------------------------
907 // helper class to create dynamic group and entry names on the fly
911 Creates a group name or entry name on the fly.
913 This version creates a simple unsigned integer as an entry name.
917 Fl_Preferences prev( appPrefs, "PreviousFiles" );
919 for ( i=0; i<n; i++ )
920 prev.get( Fl_Preferences::Name(i), prevFile[i], "" );
923 Fl_Preferences::Name::Name( unsigned int n
) {
924 data_
= (char*)malloc(20);
925 sprintf(data_
, "%u", n
);
929 Creates a group name or entry name on the fly.
931 This version creates entry names as in 'printf'.
935 Fl_Preferences prefs( USER, "matthiasm.com", "test" );
936 prev.get( "nFiles", 0 );
937 for ( i=0; i<n; i++ )
938 prev.get( Fl_Preferences::Name( "File%d", i ), prevFile[i], "" );
941 Fl_Preferences::Name::Name( const char *format
, ... ) {
942 data_
= (char*)malloc(1024);
944 va_start(args
, format
);
945 vsnprintf(data_
, 1024, format
, args
);
950 Fl_Preferences::Name::~Name() {
957 //-----------------------------------------------------------------------------
958 // internal methods, do not modify or use as they will change without notice
961 int Fl_Preferences::Node::lastEntrySet
= -1;
963 // recursively create a path in the file system
964 static char makePath( const char *path
) {
965 if (access(path
, 0)) {
966 const char *s
= strrchr( path
, '/' );
969 char *p
= (char*)malloc( len
+1 );
970 memcpy( p
, path
, len
);
974 #if defined(WIN32) && !defined(__CYGWIN__)
975 return ( mkdir( path
) == 0 );
977 return ( mkdir( path
, 0777 ) == 0 );
978 #endif // WIN32 && !__CYGWIN__
984 // strip the filename and create a path
985 static void makePathForFile( const char *path
) {
986 const char *s
= strrchr( path
, '/' );
989 char *p
= (char*)malloc( len
+1 );
990 memcpy( p
, path
, len
);
997 // create the root node
998 // - construct the name of the file that will hold our preferences
999 Fl_Preferences::RootNode::RootNode( Fl_Preferences
*prefs
, Root root
, const char *vendor
, const char *application
)
1005 char filename
[ FL_PATH_MAX
]; filename
[0] = 0;
1007 # define FLPREFS_RESOURCE "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
1008 # define FLPREFS_RESOURCEW L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
1009 int appDataLen
= strlen(vendor
) + strlen(application
) + 8;
1016 err
= RegOpenKeyW( HKEY_LOCAL_MACHINE
, FLPREFS_RESOURCEW
, &key
);
1017 if (err
== ERROR_SUCCESS
) {
1018 nn
= FL_PATH_MAX
- appDataLen
;
1019 err
= RegQueryValueExW( key
, L
"Common AppData", 0L, &type
,
1020 (BYTE
*)filename
, &nn
);
1021 if ( ( err
!= ERROR_SUCCESS
) && ( type
== REG_SZ
) ) {
1029 err
= RegOpenKeyW( HKEY_CURRENT_USER
, FLPREFS_RESOURCEW
, &key
);
1030 if (err
== ERROR_SUCCESS
) {
1031 nn
= FL_PATH_MAX
- appDataLen
;
1032 err
= RegQueryValueExW( key
, L
"AppData", 0L, &type
,
1033 (BYTE
*)filename
, &nn
);
1034 if ( ( err
!= ERROR_SUCCESS
) && ( type
== REG_SZ
) ) {
1042 if (!filename
[1] && !filename
[0]) {
1043 strcpy(filename
, "C:\\FLTK");
1046 xchar
*b
= (xchar
*)_wcsdup((xchar
*)filename
);
1048 // cygwin does not come with _wcsdup. Use malloc + wcscpy.
1049 // For implementation of wcsdup functionality See
1050 // - http://linenum.info/p/glibc/2.7/wcsmbs/wcsdup.c
1051 xchar
*b
= (xchar
*) malloc((wcslen((xchar
*) filename
) + 1) * sizeof(xchar
));
1052 wcscpy(b
, (xchar
*) filename
);
1054 // filename[fl_unicode2utf(b, wcslen((xchar*)b), filename)] = 0;
1055 unsigned len
= fl_utf8fromwc(filename
, (FL_PATH_MAX
-1), b
, wcslen(b
));
1059 snprintf(filename
+ strlen(filename
), sizeof(filename
) - strlen(filename
),
1060 "/%s/%s.prefs", vendor
, application
);
1061 for (char *s
= filename
; *s
; s
++) if (*s
== '\\') *s
= '/';
1062 #elif defined ( __APPLE__ )
1063 // TODO: verify that this is the Apple sanctioned way of finding these folders
1064 // (On MSWindows, this frequently leads to issues with internationalized systems)
1065 // Carbon: err = FindFolder( kLocalDomain, kPreferencesFolderType, 1, &spec.vRefNum, &spec.parID );
1068 strcpy(filename
, "/Library/Preferences");
1071 sprintf(filename
, "%s/Library/Preferences", fl_getenv("HOME"));
1074 snprintf(filename
+ strlen(filename
), sizeof(filename
) - strlen(filename
),
1075 "/%s/%s.prefs", vendor
, application
);
1080 if ((e
= fl_getenv("HOME")) != NULL
) {
1081 strlcpy(filename
, e
, sizeof(filename
));
1083 if (filename
[strlen(filename
)-1] != '/') {
1084 strlcat(filename
, "/.fltk/", sizeof(filename
));
1086 strlcat(filename
, ".fltk/", sizeof(filename
));
1091 strcpy(filename
, "/etc/fltk/");
1094 snprintf(filename
+ strlen(filename
), sizeof(filename
) - strlen(filename
),
1095 "%s/%s.prefs", vendor
, application
);
1097 filename_
= strdup(filename
);
1098 vendor_
= strdup(vendor
);
1099 application_
= strdup(application
);
1103 // create the root node
1104 // - construct the name of the file that will hold our preferences
1105 Fl_Preferences::RootNode::RootNode( Fl_Preferences
*prefs
, const char *path
, const char *vendor
, const char *application
)
1114 application
= "unknown";
1115 filename_
= strdup(path
);
1117 char filename
[ FL_PATH_MAX
]; filename
[0] = 0;
1118 snprintf(filename
, sizeof(filename
), "%s/%s.prefs", path
, application
);
1119 filename_
= strdup(filename
);
1121 vendor_
= strdup(vendor
);
1122 application_
= strdup(application
);
1126 // create a root node that exists only on RAM and can not be read or written to
1128 Fl_Preferences::RootNode::RootNode( Fl_Preferences
*prefs
)
1135 // destroy the root node and all depending nodes
1136 Fl_Preferences::RootNode::~RootNode() {
1137 if ( prefs_
->node
->dirty() )
1147 if ( application_
) {
1148 free( application_
);
1151 delete prefs_
->node
;
1155 // read a preferences file and construct the group tree and with all entry leafs
1156 int Fl_Preferences::RootNode::read() {
1157 if (!filename_
) // RUNTIME preferences
1160 FILE *f
= fl_fopen( filename_
, "rb" );
1163 if (fgets( buf
, 1024, f
)==0) { /* ignore */ }
1164 if (fgets( buf
, 1024, f
)==0) { /* ignore */ }
1165 if (fgets( buf
, 1024, f
)==0) { /* ignore */ }
1166 Node
*nd
= prefs_
->node
;
1168 if ( !fgets( buf
, 1024, f
) ) break; // EOF or Error
1169 if ( buf
[0]=='[' ) { // read a new group
1170 int end
= strcspn( buf
+1, "]\n\r" );
1172 nd
= prefs_
->node
->find( buf
+1 );
1173 } else if ( buf
[0]=='+' ) { // value of previous name/value pair spans multiple lines
1174 int end
= strcspn( buf
+1, "\n\r" );
1175 if ( end
!= 0 ) { // if entry is not empty
1179 } else { // read a name/value pair
1180 int end
= strcspn( buf
, "\n\r" );
1181 if ( end
!= 0 ) { // if entry is not empty
1191 // write the group tree and all entry leafs
1192 int Fl_Preferences::RootNode::write() {
1193 if (!filename_
) // RUNTIME preferences
1195 fl_make_path_for_file(filename_
);
1196 FILE *f
= fl_fopen( filename_
, "wb" );
1199 fprintf( f
, "; FLTK preferences file format 1.0\n" );
1200 fprintf( f
, "; vendor: %s\n", vendor_
);
1201 fprintf( f
, "; application: %s\n", application_
);
1202 prefs_
->node
->write( f
);
1204 #if !(defined(__APPLE__) || defined(WIN32))
1205 // unix: make sure that system prefs are user-readable
1206 if (strncmp(filename_
, "/etc/fltk/", 10) == 0) {
1209 do { // for each directory to the pref file
1211 fl_chmod(filename_
, 0755); // rwxr-xr-x
1213 p
= strchr(p
+1, '/');
1215 fl_chmod(filename_
, 0644); // rw-r--r--
1221 // get the path to the preferences directory
1222 char Fl_Preferences::RootNode::getPath( char *path
, int pathlen
) {
1223 if (!filename_
) // RUNTIME preferences
1225 strlcpy( path
, filename_
, pathlen
);
1228 for ( s
= path
; *s
; s
++ ) if ( *s
== '\\' ) *s
= '/';
1229 s
= strrchr( path
, '.' );
1232 char ret
= fl_make_path( path
);
1233 #if !(defined(__APPLE__) || defined(WIN32))
1234 // unix: make sure that system prefs dir. is user-readable
1235 if (strncmp(path
, "/etc/fltk/", 10) == 0) {
1236 fl_chmod(path
, 0755); // rwxr-xr-x
1243 // create a node that represents a group
1244 // - path must be a single word, prferable alnum(), dot and underscore only. Space is ok.
1245 Fl_Preferences::Node::Node( const char *path
) {
1246 if ( path
) path_
= strdup( path
); else path_
= 0;
1247 child_
= 0; next_
= 0; parent_
= 0;
1249 nEntry_
= NEntry_
= 0;
1254 nIndex_
= NIndex_
= 0;
1257 void Fl_Preferences::Node::deleteAllChildren() {
1259 for ( Node
*nd
= child_
; nd
; nd
= nx
) {
1268 void Fl_Preferences::Node::deleteAllEntries() {
1270 for ( int i
= 0; i
< nEntry_
; i
++ ) {
1271 if ( entry_
[i
].name
) {
1272 free( entry_
[i
].name
);
1273 entry_
[i
].name
= 0L;
1275 if ( entry_
[i
].value
) {
1276 free( entry_
[i
].value
);
1277 entry_
[i
].value
= 0L;
1288 // delete this and all depending nodes
1289 Fl_Preferences::Node::~Node() {
1290 deleteAllChildren();
1301 // recursively check if any entry is dirty (was changed after loading a fresh prefs file)
1302 char Fl_Preferences::Node::dirty() {
1303 if ( dirty_
) return 1;
1304 if ( next_
&& next_
->dirty() ) return 1;
1305 if ( child_
&& child_
->dirty() ) return 1;
1309 // write this node (recursively from the last neighbor back to this)
1310 // write all entries
1311 // write all children
1312 int Fl_Preferences::Node::write( FILE *f
) {
1313 if ( next_
) next_
->write( f
);
1314 fprintf( f
, "\n[%s]\n\n", path_
);
1315 for ( int i
= 0; i
< nEntry_
; i
++ ) {
1316 char *src
= entry_
[i
].value
;
1317 if ( src
) { // hack it into smaller pieces if needed
1318 fprintf( f
, "%s:", entry_
[i
].name
);
1320 for ( cnt
= 0; cnt
< 60; cnt
++ )
1321 if ( src
[cnt
]==0 ) break;
1322 written
= fwrite( src
, cnt
, 1, f
);
1326 for ( cnt
= 0; cnt
< 80; cnt
++ )
1327 if ( src
[cnt
]==0 ) break;
1329 written
= fwrite( src
, cnt
, 1, f
);
1335 fprintf( f
, "%s\n", entry_
[i
].name
);
1337 if ( child_
) child_
->write( f
);
1342 // set the parent node and create the full path
1343 void Fl_Preferences::Node::setParent( Node
*pn
) {
1347 sprintf( nameBuffer
, "%s/%s", pn
->path_
, path_
);
1349 path_
= strdup( nameBuffer
);
1352 // find the corresponding root node
1353 Fl_Preferences::RootNode
*Fl_Preferences::Node::findRoot() {
1363 // add a child to this node and set its path (try to find it first...)
1364 Fl_Preferences::Node
*Fl_Preferences::Node::addChild( const char *path
) {
1365 sprintf( nameBuffer
, "%s/%s", path_
, path
);
1366 char *name
= strdup( nameBuffer
);
1367 Node
*nd
= find( name
);
1374 // create and set, or change an entry within this node
1375 void Fl_Preferences::Node::set( const char *name
, const char *value
)
1377 for ( int i
=0; i
<nEntry_
; i
++ ) {
1378 if ( strcmp( name
, entry_
[i
].name
) == 0 ) {
1379 if ( !value
) return; // annotation
1380 if ( strcmp( value
, entry_
[i
].value
) != 0 ) {
1381 if ( entry_
[i
].value
)
1382 free( entry_
[i
].value
);
1383 entry_
[i
].value
= strdup( value
);
1390 if ( NEntry_
==nEntry_
) {
1391 NEntry_
= NEntry_
? NEntry_
*2 : 10;
1392 entry_
= (Entry
*)realloc( entry_
, NEntry_
* sizeof(Entry
) );
1394 entry_
[ nEntry_
].name
= strdup( name
);
1395 entry_
[ nEntry_
].value
= value
?strdup( value
):0;
1396 lastEntrySet
= nEntry_
;
1401 // create or set a value (or annotation) from a single line in the file buffer
1402 void Fl_Preferences::Node::set( const char *line
) {
1403 // hmm. If we assume that we always read this file in the beginning,
1404 // we can handle the dirty flag 'quick and dirty'
1406 if ( line
[0]==';' || line
[0]==0 || line
[0]=='#' ) {
1409 const char *c
= strchr( line
, ':' );
1411 unsigned int len
= c
-line
+1;
1412 if ( len
>= sizeof( nameBuffer
) )
1413 len
= sizeof( nameBuffer
);
1414 strlcpy( nameBuffer
, line
, len
);
1415 set( nameBuffer
, c
+1 );
1423 // add more data to an existing entry
1424 void Fl_Preferences::Node::add( const char *line
) {
1425 if ( lastEntrySet
<0 || lastEntrySet
>=nEntry_
) return;
1426 char *&dst
= entry_
[ lastEntrySet
].value
;
1427 int a
= strlen( dst
);
1428 int b
= strlen( line
);
1429 dst
= (char*)realloc( dst
, a
+b
+1 );
1430 memcpy( dst
+a
, line
, b
+1 );
1434 // get the value for a name, returns 0 if no such name
1435 const char *Fl_Preferences::Node::get( const char *name
) {
1436 int i
= getEntry( name
);
1437 return i
>=0 ? entry_
[i
].value
: 0 ;
1440 // find the index of an entry, returns -1 if no such entry
1441 int Fl_Preferences::Node::getEntry( const char *name
) {
1442 for ( int i
=0; i
<nEntry_
; i
++ ) {
1443 if ( strcmp( name
, entry_
[i
].name
) == 0 ) {
1450 // remove one entry form this group
1451 char Fl_Preferences::Node::deleteEntry( const char *name
) {
1452 int ix
= getEntry( name
);
1453 if ( ix
== -1 ) return 0;
1454 memmove( entry_
+ix
, entry_
+ix
+1, (nEntry_
-ix
-1) * sizeof(Entry
) );
1460 // find a group somewhere in the tree starting here
1461 // - this method will always return a valid node (except for memory allocation problems)
1462 // - if the node was not found, 'find' will create the required branch
1463 Fl_Preferences::Node
*Fl_Preferences::Node::find( const char *path
) {
1464 int len
= strlen( path_
);
1465 if ( strncmp( path
, path_
, len
) == 0 ) {
1466 if ( path
[ len
] == 0 )
1468 if ( path
[ len
] == '/' ) {
1470 for ( nd
= child_
; nd
; nd
= nd
->next_
) {
1471 Node
*nn
= nd
->find( path
);
1472 if ( nn
) return nn
;
1474 const char *s
= path
+len
+1;
1475 const char *e
= strchr( s
, '/' );
1476 if (e
) strlcpy( nameBuffer
, s
, e
-s
+1 );
1477 else strlcpy( nameBuffer
, s
, sizeof(nameBuffer
));
1478 nd
= new Node( nameBuffer
);
1479 nd
->setParent( this );
1480 return nd
->find( path
);
1486 // find a group somewhere in the tree starting here
1487 // caller must not set 'offset' argument
1488 // - if the node does not exist, 'search' returns NULL
1489 // - if the pathname is "." (current node) return this node
1490 // - if the pathname is "./" (root node) return the topmost node
1491 // - if the pathname starts with "./", start the search at the root node instead
1492 Fl_Preferences::Node
*Fl_Preferences::Node::search( const char *path
, int offset
) {
1493 if ( offset
== 0 ) {
1494 if ( path
[0] == '.' ) {
1495 if ( path
[1] == 0 ) {
1496 return this; // user was searching for current node
1497 } else if ( path
[1] == '/' ) {
1499 while ( nn
->parent() ) nn
= nn
->parent();
1500 if ( path
[2]==0 ) { // user is searching for root ( "./" )
1503 return nn
->search( path
+2, 2 ); // do a relative search on the root node
1506 offset
= strlen( path_
) + 1;
1508 int len
= strlen( path_
);
1509 if ( len
< offset
-1 ) return 0;
1511 if ( ( len
<= 0 ) || ( strncmp( path
, path_
+offset
, len
) == 0 ) ) {
1512 if ( len
> 0 && path
[ len
] == 0 )
1514 if ( len
<= 0 || path
[ len
] == '/' ) {
1515 for ( Node
*nd
= child_
; nd
; nd
= nd
->next_
) {
1516 Node
*nn
= nd
->search( path
, offset
);
1517 if ( nn
) return nn
;
1525 // return the number of child nodes (groups)
1526 int Fl_Preferences::Node::nChildren() {
1531 for ( Node
*nd
= child_
; nd
; nd
= nd
->next_
)
1537 // return the node name
1538 const char *Fl_Preferences::Node::name() {
1540 char *r
= strrchr( path_
, '/' );
1541 return r
? r
+1 : path_
;
1547 // return the n'th child node's name
1548 const char *Fl_Preferences::Node::child( int ix
) {
1549 Node
*nd
= childNode( ix
);
1556 // return the n'th child node
1557 Fl_Preferences::Node
*Fl_Preferences::Node::childNode( int ix
) {
1560 // usually faster access in correct order, but needing more memory
1563 // slow access and reverse order
1564 int n
= nChildren();
1567 for ( nd
= child_
; nd
; nd
= nd
->next_
) {
1575 // remove myself from the list and delete me (and all children)
1576 char Fl_Preferences::Node::remove() {
1579 nd
= parent()->child_
; np
= 0L;
1580 for ( ; nd
; np
= nd
, nd
= nd
->next_
) {
1583 np
->next_
= nd
->next_
;
1585 parent()->child_
= nd
->next_
;
1589 parent()->dirty_
= 1;
1590 parent()->updateIndex();
1596 void Fl_Preferences::Node::createIndex() {
1597 if (indexed_
) return;
1598 int n
= nChildren();
1601 index_
= (Node
**)realloc(index_
, NIndex_
*sizeof(Node
**));
1605 for (nd
= child_
; nd
; nd
= nd
->next_
, i
++) {
1612 void Fl_Preferences::Node::updateIndex() {
1616 void Fl_Preferences::Node::deleteIndex() {
1617 if (index_
) free(index_
);
1618 NIndex_
= nIndex_
= 0;
1624 * \brief Create a plugin.
1626 * \param[in] klass plugins are grouped in classes
1627 * \param[in] name every plugin should have a unique name
1629 Fl_Plugin::Fl_Plugin(const char *klass
, const char *name
)
1631 #ifdef FL_PLUGIN_VERBOSE
1632 printf("Fl_Plugin: creating a plugin, class \"%s\", name \"%s\"\n",
1635 Fl_Plugin_Manager
pm(klass
);
1636 id
= pm
.addPlugin(name
, this);
1640 * \brief Clear the plugin and remove it from the database.
1642 Fl_Plugin::~Fl_Plugin() {
1643 #ifdef FL_PLUGIN_VERBOSE
1644 printf("Fl_Plugin: deleting a plugin\n");
1647 Fl_Plugin_Manager::remove(id
);
1651 * \brief Manage all plugins belonging to one class.
1653 Fl_Plugin_Manager::Fl_Plugin_Manager(const char *klass
)
1654 : Fl_Preferences(0, Fl_Preferences::Name("%s/%s", "plugins", klass
)) {
1655 #ifdef FL_PLUGIN_VERBOSE
1656 printf("Fl_Plugin: creating a plugin manager for class \"%s\"\n", klass
);
1661 * \brief Remove the plugin manager.
1663 * Calling this does not remove the database itself or any plugins. It just
1664 * removes the reference to the database.
1666 Fl_Plugin_Manager::~Fl_Plugin_Manager() {
1667 #ifdef FL_PLUGIN_VERBOSE
1668 printf("Fl_Plugin: deleting a plugin manager\n");
1672 static unsigned char x2i(char hi
, char lo
) {
1673 return ((hi
-'A')<<4) | (lo
-'A');
1676 static void i2x(unsigned char v
, char *d
) {
1677 d
[0] = ((v
>>4)&0x0f)+'A'; d
[1] = (v
&0x0f)+'A';
1680 static void *a2p(const char *s
) {
1681 union { void *ret
; unsigned char d
[sizeof(void*)]; } v
;
1683 int i
=0, n
=sizeof(void*);
1684 for (i
=0; i
<n
; i
++) {
1685 v
.d
[i
] = x2i(s
[2*i
], s
[2*i
+1]);
1690 static void p2a(void *vp
, char *d
) {
1691 union { void *vp
; unsigned char s
[sizeof(void*)]; } v
;
1693 int i
=0, n
=sizeof(void*);
1694 for (i
=0; i
<n
; i
++) {
1701 * \brief Return the address of a plugin by index.
1703 Fl_Plugin
*Fl_Plugin_Manager::plugin(int index
) {
1706 Fl_Preferences
pin(this, index
);
1707 pin
.get("address", buf
, "", 34);
1708 if (buf
[0]=='@') ret
= (Fl_Plugin
*)a2p(buf
+1);
1709 #ifdef FL_PLUGIN_VERBOSE
1710 printf("Fl_Plugin: returning plugin at index %d: (%s) %p\n", index
, buf
, ret
);
1716 * \brief Return the address of a plugin by name.
1718 Fl_Plugin
*Fl_Plugin_Manager::plugin(const char *name
) {
1721 if (groupExists(name
)) {
1722 Fl_Preferences
pin(this, name
);
1723 pin
.get("address", buf
, "", 34);
1724 if (buf
[0]=='@') ret
= (Fl_Plugin
*)a2p(buf
+1);
1725 #ifdef FL_PLUGIN_VERBOSE
1726 printf("Fl_Plugin: returning plugin named \"%s\": (%s) %p\n", name
, buf
, ret
);
1730 #ifdef FL_PLUGIN_VERBOSE
1731 printf("Fl_Plugin: no plugin found named \"%s\"\n", name
);
1738 * \brief This function adds a new plugin to the database.
1740 * There is no need to call this function explicitly. Every Fl_Plugin constructor
1741 * will call this function at initialization time.
1743 Fl_Preferences::ID
Fl_Plugin_Manager::addPlugin(const char *name
, Fl_Plugin
*plugin
) {
1745 #ifdef FL_PLUGIN_VERBOSE
1746 printf("Fl_Plugin: adding plugin named \"%s\" at 0x%p\n", name
, plugin
);
1748 Fl_Preferences
pin(this, name
);
1749 buf
[0] = '@'; p2a(plugin
, buf
+1);
1750 pin
.set("address", buf
);
1755 * \brief Remove any plugin.
1757 * There is no need to call this function explicitly. Every Fl_Plugin destructor
1758 * will call this function at destruction time.
1760 void Fl_Plugin_Manager::removePlugin(Fl_Preferences::ID id
) {
1761 Fl_Preferences::remove(id
);
1765 * \brief Load a module from disk.
1767 * A module must be a dynamically linkable file for the given operating system.
1768 * When loading a module, its +init function will be called which in turn calls
1769 * the constructor of all statically initialized Fl_Plugin classes and adds
1770 * them to the database.
1772 int Fl_Plugin_Manager::load(const char *filename
) {
1773 // the functions below will autmaticaly load plugins that are defined:
1774 // Fl_My_Plugin plugin();
1775 #if defined(WIN32) && !defined(__CYGWIN__)
1776 HMODULE dl
= LoadLibrary(filename
);
1778 void * dl
= dlopen(filename
, RTLD_LAZY
);
1780 // There is no way of unloading a plugin!
1781 return (dl
!=0) ? 0 : -1;
1785 * \brief Use this function to load a whole directory full of modules.
1787 int Fl_Plugin_Manager::loadAll(const char *filepath
, const char *pattern
) {
1788 struct dirent
**dir
;
1789 int i
, n
= fl_filename_list(filepath
, &dir
);
1790 for (i
=0; i
<n
; i
++) {
1791 struct dirent
*e
= dir
[i
];
1792 if (pattern
==0 || fl_filename_match(e
->d_name
, pattern
)) {
1793 load(Fl_Preferences::Name("%s%s", filepath
, e
->d_name
));
1802 // End of "$Id: Fl_Preferences.cxx 8291 2011-01-19 06:33:48Z manolo $".