|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_Preferences.cxx 8173 2011-01-03 16:50:34Z manolo $" 00003 // 00004 // Preferences methods for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 2002-2010 by Matthias Melcher. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 #include <FL/Fl.H> 00029 #include <FL/Fl_Preferences.H> 00030 #include <FL/Fl_Plugin.H> 00031 #include <FL/filename.H> 00032 00033 #include <stdio.h> 00034 #include <stdlib.h> 00035 #include <stdarg.h> 00036 #include <FL/fl_utf8.h> 00037 #include "flstring.h" 00038 #include <sys/stat.h> 00039 #include <time.h> 00040 00041 #if defined(WIN32) && !defined(__CYGWIN__) 00042 # include <windows.h> 00043 # include <direct.h> 00044 # include <io.h> 00045 // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs 00046 // on Windows, which is supposed to be POSIX compliant... 00047 # define access _access 00048 # define mkdir _mkdir 00049 #elif defined (__APPLE__) 00050 # include <ApplicationServices/ApplicationServices.h> 00051 # include <unistd.h> 00052 # include <dlfcn.h> 00053 #else 00054 # include <unistd.h> 00055 # include <dlfcn.h> 00056 #endif 00057 00058 #ifdef WIN32 00059 # include <windows.h> 00060 # include <rpc.h> 00061 // function pointer for the UuidCreate Function 00062 // RPC_STATUS RPC_ENTRY UuidCreate(UUID __RPC_FAR *Uuid); 00063 typedef RPC_STATUS (WINAPI* uuid_func)(UUID __RPC_FAR *Uuid); 00064 #else 00065 # include <sys/time.h> 00066 #endif // WIN32 00067 00068 #ifdef __CYGWIN__ 00069 # include <wchar.h> 00070 #endif 00071 00072 char Fl_Preferences::nameBuffer[128]; 00073 char Fl_Preferences::uuidBuffer[40]; 00074 Fl_Preferences *Fl_Preferences::runtimePrefs = 0; 00075 00087 const char *Fl_Preferences::newUUID() { 00088 #ifdef __APPLE__ 00089 CFUUIDRef theUUID = CFUUIDCreate(NULL); 00090 CFUUIDBytes b = CFUUIDGetUUIDBytes(theUUID); 00091 sprintf(uuidBuffer, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", 00092 b.byte0, b.byte1, b.byte2, b.byte3, b.byte4, b.byte5, b.byte6, b.byte7, 00093 b.byte8, b.byte9, b.byte10, b.byte11, b.byte12, b.byte13, b.byte14, b.byte15); 00094 CFRelease(theUUID); 00095 #elif defined (WIN32) 00096 // First try and use the win API function UuidCreate(), but if that is not 00097 // available, fall back to making something up from scratch. 00098 // We do not want to link against the Rpcrt4.dll, as we will rarely use it, 00099 // so we load the DLL dynamically, if it is available, and work from there. 00100 static HMODULE hMod = NULL; 00101 UUID ud; 00102 UUID *pu = &ud; 00103 int got_uuid = 0; 00104 00105 if (!hMod) { // first time in? 00106 hMod = LoadLibrary("Rpcrt4.dll"); 00107 } 00108 00109 if (hMod) { // do we have a usable handle to Rpcrt4.dll? 00110 uuid_func uuid_crt = (uuid_func)GetProcAddress(hMod, "UuidCreate"); 00111 if (uuid_crt != NULL) { 00112 RPC_STATUS rpc_res = uuid_crt(pu); 00113 if ( // is the return status OK for our needs? 00114 (rpc_res == RPC_S_OK) || // all is well 00115 (rpc_res == RPC_S_UUID_LOCAL_ONLY) || // only unique to this machine 00116 (rpc_res == RPC_S_UUID_NO_ADDRESS) // probably only locally unique 00117 ) { 00118 got_uuid = -1; 00119 sprintf(uuidBuffer, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", 00120 pu->Data1, pu->Data2, pu->Data3, pu->Data4[0], pu->Data4[1], 00121 pu->Data4[2], pu->Data4[3], pu->Data4[4], 00122 pu->Data4[5], pu->Data4[6], pu->Data4[7]); 00123 } 00124 } 00125 } 00126 if (got_uuid == 0) { // did not make a UUID - use fallback logic 00127 unsigned char b[16]; 00128 time_t t = time(0); // first 4 byte 00129 b[0] = (unsigned char)t; 00130 b[1] = (unsigned char)(t>>8); 00131 b[2] = (unsigned char)(t>>16); 00132 b[3] = (unsigned char)(t>>24); 00133 int r = rand(); // four more bytes 00134 b[4] = (unsigned char)r; 00135 b[5] = (unsigned char)(r>>8); 00136 b[6] = (unsigned char)(r>>16); 00137 b[7] = (unsigned char)(r>>24); 00138 // Now we try to find 4 more "random" bytes. We extract the 00139 // lower 4 bytes from the address of t - it is created on the 00140 // stack so *might* be in a different place each time... 00141 // This is now done via a union to make it compile OK on 64-bit systems. 00142 union { void *pv; unsigned char a[sizeof(void*)]; } v; 00143 v.pv = (void *)(&t); 00144 // NOTE: This assume that all WinXX systems are little-endian 00145 b[8] = v.a[0]; 00146 b[9] = v.a[1]; 00147 b[10] = v.a[2]; 00148 b[11] = v.a[3]; 00149 TCHAR name[MAX_COMPUTERNAME_LENGTH + 1]; // only used to make last four bytes 00150 DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1; 00151 // GetComputerName() does not depend on any extra libs, and returns something 00152 // analogous to gethostname() 00153 GetComputerName(name, &nSize); 00154 // use the first 4 TCHAR's of the name to create the last 4 bytes of our UUID 00155 for (int ii = 0; ii < 4; ii++) { 00156 b[12 + ii] = (unsigned char)name[ii]; 00157 } 00158 sprintf(uuidBuffer, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", 00159 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], 00160 b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]); 00161 } 00162 #else 00163 // warning Unix implementation of Fl_Preferences::newUUID() incomplete! 00164 // #include <uuid/uuid.h> 00165 // void uuid_generate(uuid_t out); 00166 unsigned char b[16]; 00167 time_t t = time(0); // first 4 byte 00168 b[0] = (unsigned char)t; 00169 b[1] = (unsigned char)(t>>8); 00170 b[2] = (unsigned char)(t>>16); 00171 b[3] = (unsigned char)(t>>24); 00172 int r = rand(); // four more bytes 00173 b[4] = (unsigned char)r; 00174 b[5] = (unsigned char)(r>>8); 00175 b[6] = (unsigned char)(r>>16); 00176 b[7] = (unsigned char)(r>>24); 00177 unsigned long a = (unsigned long)&t; // four more bytes 00178 b[8] = (unsigned char)a; 00179 b[9] = (unsigned char)(a>>8); 00180 b[10] = (unsigned char)(a>>16); 00181 b[11] = (unsigned char)(a>>24); 00182 // Now we try to find 4 more "random" bytes. We extract the 00183 // lower 4 bytes from the address of t - it is created on the 00184 // stack so *might* be in a different place each time... 00185 // This is now done via a union to make it compile OK on 64-bit systems. 00186 union { void *pv; unsigned char a[sizeof(void*)]; } v; 00187 v.pv = (void *)(&t); 00188 // NOTE: May need to handle big- or little-endian systems here 00189 # if WORDS_BIGENDIAN 00190 b[8] = v.a[sizeof(void*) - 1]; 00191 b[9] = v.a[sizeof(void*) - 2]; 00192 b[10] = v.a[sizeof(void*) - 3]; 00193 b[11] = v.a[sizeof(void*) - 4]; 00194 # else /* data ordered for a little-endian system */ 00195 b[8] = v.a[0]; 00196 b[9] = v.a[1]; 00197 b[10] = v.a[2]; 00198 b[11] = v.a[3]; 00199 # endif 00200 char name[80]; // last four bytes 00201 gethostname(name, 79); 00202 memcpy(b+12, name, 4); 00203 sprintf(uuidBuffer, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", 00204 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], 00205 b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]); 00206 #endif 00207 00208 return uuidBuffer; 00209 } 00210 00237 Fl_Preferences::Fl_Preferences( Root root, const char *vendor, const char *application ) { 00238 node = new Node( "." ); 00239 rootNode = new RootNode( this, root, vendor, application ); 00240 node->setRoot(rootNode); 00241 } 00242 00255 Fl_Preferences::Fl_Preferences( const char *path, const char *vendor, const char *application ) { 00256 node = new Node( "." ); 00257 rootNode = new RootNode( this, path, vendor, application ); 00258 node->setRoot(rootNode); 00259 } 00260 00271 Fl_Preferences::Fl_Preferences( Fl_Preferences &parent, const char *group ) { 00272 rootNode = parent.rootNode; 00273 node = parent.node->addChild( group ); 00274 } 00275 00286 Fl_Preferences::Fl_Preferences( Fl_Preferences *parent, const char *group ) { 00287 if (parent==0) { 00288 if (!runtimePrefs) { 00289 runtimePrefs = new Fl_Preferences(); 00290 runtimePrefs->node = new Node( "." ); 00291 runtimePrefs->rootNode = new RootNode( runtimePrefs ); 00292 runtimePrefs->node->setRoot(rootNode); 00293 } 00294 parent = runtimePrefs; 00295 } 00296 rootNode = parent->rootNode; 00297 node = parent->node->addChild( group ); 00298 } 00299 00313 Fl_Preferences::Fl_Preferences( Fl_Preferences &parent, int groupIndex ) { 00314 rootNode = parent.rootNode; 00315 if (groupIndex<0 || groupIndex>=parent.groups()) { 00316 node = parent.node->addChild( newUUID() ); 00317 } else { 00318 node = parent.node->childNode( groupIndex ); 00319 } 00320 } 00321 00325 Fl_Preferences::Fl_Preferences( Fl_Preferences *parent, int groupIndex ) { 00326 rootNode = parent->rootNode; 00327 if (groupIndex<0 || groupIndex>=parent->groups()) { 00328 node = parent->node->addChild( newUUID() ); 00329 } else { 00330 node = parent->node->childNode( groupIndex ); 00331 } 00332 } 00333 00345 Fl_Preferences::Fl_Preferences( Fl_Preferences::ID id ) { 00346 node = (Node*)id; 00347 rootNode = node->findRoot(); 00348 } 00349 00353 Fl_Preferences::Fl_Preferences(const Fl_Preferences &rhs) 00354 : node(rhs.node), 00355 rootNode(rhs.rootNode) 00356 { } 00357 00361 Fl_Preferences &Fl_Preferences::operator=(const Fl_Preferences &rhs) { 00362 if (&rhs != this) { 00363 node = rhs.node; 00364 rootNode = rhs.rootNode; 00365 } 00366 return *this; 00367 } 00368 00378 Fl_Preferences::~Fl_Preferences() { 00379 if (node && !node->parent()) delete rootNode; 00380 // DO NOT delete nodes! The root node will do that after writing the preferences 00381 // zero all pointer to avoid memory errors, even though 00382 // Valgrind does not complain (Cygwind does though) 00383 node = 0L; 00384 rootNode = 0L; 00385 } 00386 00392 int Fl_Preferences::groups() { 00393 return node->nChildren(); 00394 } 00395 00404 const char *Fl_Preferences::group( int num_group ) { 00405 return node->child( num_group ); 00406 } 00407 00417 char Fl_Preferences::groupExists( const char *key ) { 00418 return node->search( key ) ? 1 : 0 ; 00419 } 00420 00430 char Fl_Preferences::deleteGroup( const char *group ) { 00431 Node *nd = node->search( group ); 00432 if ( nd ) return nd->remove(); 00433 return 0; 00434 } 00435 00439 char Fl_Preferences::deleteAllGroups() { 00440 node->deleteAllChildren(); 00441 return 1; 00442 } 00443 00449 int Fl_Preferences::entries() { 00450 return node->nEntry(); 00451 } 00452 00461 const char *Fl_Preferences::entry( int index ) { 00462 return node->entry(index).name; 00463 } 00464 00471 char Fl_Preferences::entryExists( const char *key ) { 00472 return node->getEntry( key )>=0 ? 1 : 0 ; 00473 } 00474 00483 char Fl_Preferences::deleteEntry( const char *key ) { 00484 return node->deleteEntry( key ); 00485 } 00486 00490 char Fl_Preferences::deleteAllEntries() { 00491 node->deleteAllEntries(); 00492 return 1; 00493 } 00494 00498 char Fl_Preferences::clear() { 00499 char ret1 = deleteAllGroups(); 00500 char ret2 = deleteAllEntries(); 00501 return ret1 & ret2; 00502 } 00503 00514 char Fl_Preferences::get( const char *key, int &value, int defaultValue ) { 00515 const char *v = node->get( key ); 00516 value = v ? atoi( v ) : defaultValue; 00517 return ( v != 0 ); 00518 } 00519 00530 char Fl_Preferences::set( const char *key, int value ) { 00531 sprintf( nameBuffer, "%d", value ); 00532 node->set( key, nameBuffer ); 00533 return 1; 00534 } 00535 00546 char Fl_Preferences::get( const char *key, float &value, float defaultValue ) { 00547 const char *v = node->get( key ); 00548 value = v ? (float)atof( v ) : defaultValue; 00549 return ( v != 0 ); 00550 } 00551 00562 char Fl_Preferences::set( const char *key, float value ) { 00563 sprintf( nameBuffer, "%g", value ); 00564 node->set( key, nameBuffer ); 00565 return 1; 00566 } 00567 00579 char Fl_Preferences::set( const char *key, float value, int precision ) { 00580 sprintf( nameBuffer, "%.*g", precision, value ); 00581 node->set( key, nameBuffer ); 00582 return 1; 00583 } 00584 00595 char Fl_Preferences::get( const char *key, double &value, double defaultValue ) { 00596 const char *v = node->get( key ); 00597 value = v ? atof( v ) : defaultValue; 00598 return ( v != 0 ); 00599 } 00600 00611 char Fl_Preferences::set( const char *key, double value ) { 00612 sprintf( nameBuffer, "%g", value ); 00613 node->set( key, nameBuffer ); 00614 return 1; 00615 } 00616 00628 char Fl_Preferences::set( const char *key, double value, int precision ) { 00629 sprintf( nameBuffer, "%.*g", precision, value ); 00630 node->set( key, nameBuffer ); 00631 return 1; 00632 } 00633 00634 // remove control sequences from a string 00635 static char *decodeText( const char *src ) { 00636 int len = 0; 00637 const char *s = src; 00638 for ( ; *s; s++, len++ ) { 00639 if ( *s == '\\' ) { 00640 if ( isdigit( s[1] ) ) { 00641 s+=3; 00642 } else { 00643 s+=1; 00644 } 00645 } 00646 } 00647 char *dst = (char*)malloc( len+1 ), *d = dst; 00648 for ( s = src; *s; s++ ) { 00649 char c = *s; 00650 if ( c == '\\' ) { 00651 if ( s[1] == '\\' ) { *d++ = c; s++; } 00652 else if ( s[1] == 'n' ) { *d++ = '\n'; s++; } 00653 else if ( s[1] == 'r' ) { *d++ = '\r'; s++; } 00654 else if ( isdigit( s[1] ) ) { *d++ = ((s[1]-'0')<<6) + ((s[2]-'0')<<3) + (s[3]-'0'); s+=3; } 00655 else s++; // error 00656 } 00657 else 00658 *d++ = c; 00659 } 00660 *d = 0; 00661 return dst; 00662 } 00663 00677 char Fl_Preferences::get( const char *key, char *text, const char *defaultValue, int maxSize ) { 00678 const char *v = node->get( key ); 00679 if ( v && strchr( v, '\\' ) ) { 00680 char *w = decodeText( v ); 00681 strlcpy(text, w, maxSize); 00682 free( w ); 00683 return 1; 00684 } 00685 if ( !v ) v = defaultValue; 00686 if ( v ) strlcpy(text, v, maxSize); 00687 else text = 0; 00688 return ( v != defaultValue ); 00689 } 00690 00703 char Fl_Preferences::get( const char *key, char *&text, const char *defaultValue ) { 00704 const char *v = node->get( key ); 00705 if ( v && strchr( v, '\\' ) ) { 00706 text = decodeText( v ); 00707 return 1; 00708 } 00709 if ( !v ) v = defaultValue; 00710 if ( v ) 00711 text = strdup( v ); 00712 else 00713 text = 0; 00714 return ( v != defaultValue ); 00715 } 00716 00727 char Fl_Preferences::set( const char *key, const char *text ) { 00728 const char *s = text ? text : ""; 00729 int n=0, ns=0; 00730 for ( ; *s; s++ ) { n++; if ( *s<32 || *s=='\\' || *s==0x7f ) ns+=4; } 00731 if ( ns ) { 00732 char *buffer = (char*)malloc( n+ns+1 ), *d = buffer; 00733 for ( s=text; *s; ) { 00734 char c = *s; 00735 if ( c=='\\' ) { *d++ = '\\'; *d++ = '\\'; s++; } 00736 else if ( c=='\n' ) { *d++ = '\\'; *d++ = 'n'; s++; } 00737 else if ( c=='\r' ) { *d++ = '\\'; *d++ = 'r'; s++; } 00738 else if ( c<32 || c==0x7f ) 00739 { *d++ = '\\'; *d++ = '0'+((c>>6)&3); *d++ = '0'+((c>>3)&7); *d++ = '0'+(c&7); s++; } 00740 else *d++ = *s++; 00741 } 00742 *d = 0; 00743 node->set( key, buffer ); 00744 free( buffer ); 00745 } 00746 else 00747 node->set( key, text ); 00748 return 1; 00749 } 00750 00751 // convert a hex string to binary data 00752 static void *decodeHex( const char *src, int &size ) { 00753 size = strlen( src )/2; 00754 unsigned char *data = (unsigned char*)malloc( size ), *d = data; 00755 const char *s = src; 00756 for ( int i=size; i>0; i-- ) { 00757 int v; 00758 char x = tolower(*s++); 00759 if ( x >= 'a' ) v = x-'a'+10; else v = x-'0'; 00760 v = v<<4; 00761 x = tolower(*s++); 00762 if ( x >= 'a' ) v += x-'a'+10; else v += x-'0'; 00763 *d++ = (uchar)v; 00764 } 00765 return (void*)data; 00766 } 00767 00783 char Fl_Preferences::get( const char *key, void *data, const void *defaultValue, int defaultSize, int maxSize ) { 00784 const char *v = node->get( key ); 00785 if ( v ) { 00786 int dsize; 00787 void *w = decodeHex( v, dsize ); 00788 memmove( data, w, dsize>maxSize?maxSize:dsize ); 00789 free( w ); 00790 return 1; 00791 } 00792 if ( defaultValue ) 00793 memmove( data, defaultValue, defaultSize>maxSize?maxSize:defaultSize ); 00794 return 0; 00795 } 00796 00810 char Fl_Preferences::get( const char *key, void *&data, const void *defaultValue, int defaultSize ) { 00811 const char *v = node->get( key ); 00812 if ( v ) { 00813 int dsize; 00814 data = decodeHex( v, dsize ); 00815 return 1; 00816 } 00817 if ( defaultValue ) { 00818 data = (void*)malloc( defaultSize ); 00819 memmove( data, defaultValue, defaultSize ); 00820 } 00821 else 00822 data = 0; 00823 return 0; 00824 } 00825 00837 char Fl_Preferences::set( const char *key, const void *data, int dsize ) { 00838 char *buffer = (char*)malloc( dsize*2+1 ), *d = buffer;; 00839 unsigned char *s = (unsigned char*)data; 00840 for ( ; dsize>0; dsize-- ) { 00841 static char lu[] = "0123456789abcdef"; 00842 unsigned char v = *s++; 00843 *d++ = lu[v>>4]; 00844 *d++ = lu[v&0xf]; 00845 } 00846 *d = 0; 00847 node->set( key, buffer ); 00848 free( buffer ); 00849 return 1; 00850 } 00851 00858 int Fl_Preferences::size( const char *key ) { 00859 const char *v = node->get( key ); 00860 return v ? strlen( v ) : 0 ; 00861 } 00862 00890 char Fl_Preferences::getUserdataPath( char *path, int pathlen ) { 00891 if ( rootNode ) 00892 return rootNode->getPath( path, pathlen ); 00893 return 0; 00894 } 00895 00901 void Fl_Preferences::flush() { 00902 if ( rootNode && node->dirty() ) 00903 rootNode->write(); 00904 } 00905 00906 //----------------------------------------------------------------------------- 00907 // helper class to create dynamic group and entry names on the fly 00908 // 00909 00923 Fl_Preferences::Name::Name( unsigned int n ) { 00924 data_ = (char*)malloc(20); 00925 sprintf(data_, "%u", n); 00926 } 00927 00941 Fl_Preferences::Name::Name( const char *format, ... ) { 00942 data_ = (char*)malloc(1024); 00943 va_list args; 00944 va_start(args, format); 00945 vsnprintf(data_, 1024, format, args); 00946 va_end(args); 00947 } 00948 00949 // delete the name 00950 Fl_Preferences::Name::~Name() { 00951 if (data_) { 00952 free(data_); 00953 data_ = 0L; 00954 } 00955 } 00956 00957 //----------------------------------------------------------------------------- 00958 // internal methods, do not modify or use as they will change without notice 00959 // 00960 00961 int Fl_Preferences::Node::lastEntrySet = -1; 00962 00963 // recursively create a path in the file system 00964 static char makePath( const char *path ) { 00965 if (access(path, 0)) { 00966 const char *s = strrchr( path, '/' ); 00967 if ( !s ) return 0; 00968 int len = s-path; 00969 char *p = (char*)malloc( len+1 ); 00970 memcpy( p, path, len ); 00971 p[len] = 0; 00972 makePath( p ); 00973 free( p ); 00974 #if defined(WIN32) && !defined(__CYGWIN__) 00975 return ( mkdir( path ) == 0 ); 00976 #else 00977 return ( mkdir( path, 0777 ) == 0 ); 00978 #endif // WIN32 && !__CYGWIN__ 00979 } 00980 return 1; 00981 } 00982 00983 #if 0 00984 // strip the filename and create a path 00985 static void makePathForFile( const char *path ) { 00986 const char *s = strrchr( path, '/' ); 00987 if ( !s ) return; 00988 int len = s-path; 00989 char *p = (char*)malloc( len+1 ); 00990 memcpy( p, path, len ); 00991 p[len] = 0; 00992 makePath( p ); 00993 free( p ); 00994 } 00995 #endif 00996 00997 // create the root node 00998 // - construct the name of the file that will hold our preferences 00999 Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char *vendor, const char *application ) 01000 : prefs_(prefs), 01001 filename_(0L), 01002 vendor_(0L), 01003 application_(0L) { 01004 01005 char filename[ FL_PATH_MAX ]; filename[0] = 0; 01006 #ifdef WIN32 01007 # define FLPREFS_RESOURCE "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" 01008 # define FLPREFS_RESOURCEW L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" 01009 int appDataLen = strlen(vendor) + strlen(application) + 8; 01010 DWORD type, nn; 01011 LONG err; 01012 HKEY key; 01013 01014 switch (root) { 01015 case SYSTEM: 01016 err = RegOpenKeyW( HKEY_LOCAL_MACHINE, FLPREFS_RESOURCEW, &key ); 01017 if (err == ERROR_SUCCESS) { 01018 nn = FL_PATH_MAX - appDataLen; 01019 err = RegQueryValueExW( key, L"Common AppData", 0L, &type, 01020 (BYTE*)filename, &nn ); 01021 if ( ( err != ERROR_SUCCESS ) && ( type == REG_SZ ) ) { 01022 filename[0] = 0; 01023 filename[1] = 0; 01024 } 01025 RegCloseKey(key); 01026 } 01027 break; 01028 case USER: 01029 err = RegOpenKeyW( HKEY_CURRENT_USER, FLPREFS_RESOURCEW, &key ); 01030 if (err == ERROR_SUCCESS) { 01031 nn = FL_PATH_MAX - appDataLen; 01032 err = RegQueryValueExW( key, L"AppData", 0L, &type, 01033 (BYTE*)filename, &nn ); 01034 if ( ( err != ERROR_SUCCESS ) && ( type == REG_SZ ) ) { 01035 filename[0] = 0; 01036 filename[1] = 0; 01037 } 01038 RegCloseKey(key); 01039 } 01040 break; 01041 } 01042 if (!filename[1] && !filename[0]) { 01043 strcpy(filename, "C:\\FLTK"); 01044 } else { 01045 #if 0 01046 xchar *b = (xchar*)_wcsdup((xchar *)filename); 01047 #else 01048 // cygwin does not come with _wcsdup. Use malloc + wcscpy. 01049 // For implementation of wcsdup functionality See 01050 // - http://linenum.info/p/glibc/2.7/wcsmbs/wcsdup.c 01051 xchar *b = (xchar*) malloc((wcslen((xchar *) filename) + 1) * sizeof(xchar)); 01052 wcscpy(b, (xchar *) filename); 01053 #endif 01054 // filename[fl_unicode2utf(b, wcslen((xchar*)b), filename)] = 0; 01055 unsigned len = fl_utf8fromwc(filename, (FL_PATH_MAX-1), b, wcslen(b)); 01056 filename[len] = 0; 01057 free(b); 01058 } 01059 snprintf(filename + strlen(filename), sizeof(filename) - strlen(filename), 01060 "/%s/%s.prefs", vendor, application); 01061 for (char *s = filename; *s; s++) if (*s == '\\') *s = '/'; 01062 #elif defined ( __APPLE__ ) 01063 // TODO: verify that this is the Apple sanctioned way of finding these folders 01064 // (On MSWindows, this frequently leads to issues with internationalized systems) 01065 // Carbon: err = FindFolder( kLocalDomain, kPreferencesFolderType, 1, &spec.vRefNum, &spec.parID ); 01066 switch (root) { 01067 case SYSTEM: 01068 strcpy(filename, "/Library/Preferences"); 01069 break; 01070 case USER: 01071 sprintf(filename, "%s/Library/Preferences", fl_getenv("HOME")); 01072 break; 01073 } 01074 snprintf(filename + strlen(filename), sizeof(filename) - strlen(filename), 01075 "/%s/%s.prefs", vendor, application ); 01076 #else 01077 const char *e; 01078 switch (root) { 01079 case USER: 01080 if ((e = fl_getenv("HOME")) != NULL) { 01081 strlcpy(filename, e, sizeof(filename)); 01082 01083 if (filename[strlen(filename)-1] != '/') { 01084 strlcat(filename, "/.fltk/", sizeof(filename)); 01085 } else { 01086 strlcat(filename, ".fltk/", sizeof(filename)); 01087 } 01088 break; 01089 } 01090 case SYSTEM: 01091 strcpy(filename, "/etc/fltk/"); 01092 break; 01093 } 01094 snprintf(filename + strlen(filename), sizeof(filename) - strlen(filename), 01095 "%s/%s.prefs", vendor, application); 01096 #endif 01097 filename_ = strdup(filename); 01098 vendor_ = strdup(vendor); 01099 application_ = strdup(application); 01100 read(); 01101 } 01102 01103 // create the root node 01104 // - construct the name of the file that will hold our preferences 01105 Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, const char *vendor, const char *application ) 01106 : prefs_(prefs), 01107 filename_(0L), 01108 vendor_(0L), 01109 application_(0L) { 01110 01111 if (!vendor) 01112 vendor = "unknown"; 01113 if (!application) { 01114 application = "unknown"; 01115 filename_ = strdup(path); 01116 } else { 01117 char filename[ FL_PATH_MAX ]; filename[0] = 0; 01118 snprintf(filename, sizeof(filename), "%s/%s.prefs", path, application); 01119 filename_ = strdup(filename); 01120 } 01121 vendor_ = strdup(vendor); 01122 application_ = strdup(application); 01123 read(); 01124 } 01125 01126 // create a root node that exists only on RAM and can not be read or written to 01127 // a file 01128 Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs ) 01129 : prefs_(prefs), 01130 filename_(0L), 01131 vendor_(0L), 01132 application_(0L) { 01133 } 01134 01135 // destroy the root node and all depending nodes 01136 Fl_Preferences::RootNode::~RootNode() { 01137 if ( prefs_->node->dirty() ) 01138 write(); 01139 if ( filename_ ) { 01140 free( filename_ ); 01141 filename_ = 0L; 01142 } 01143 if ( vendor_ ) { 01144 free( vendor_ ); 01145 vendor_ = 0L; 01146 } 01147 if ( application_ ) { 01148 free( application_ ); 01149 application_ = 0L; 01150 } 01151 delete prefs_->node; 01152 prefs_->node = 0L; 01153 } 01154 01155 // read a preferences file and construct the group tree and with all entry leafs 01156 int Fl_Preferences::RootNode::read() { 01157 if (!filename_) // RUNTIME preferences 01158 return -1; 01159 char buf[1024]; 01160 FILE *f = fl_fopen( filename_, "rb" ); 01161 if ( !f ) 01162 return -1; 01163 if (fgets( buf, 1024, f )==0) { /* ignore */ } 01164 if (fgets( buf, 1024, f )==0) { /* ignore */ } 01165 if (fgets( buf, 1024, f )==0) { /* ignore */ } 01166 Node *nd = prefs_->node; 01167 for (;;) { 01168 if ( !fgets( buf, 1024, f ) ) break; // EOF or Error 01169 if ( buf[0]=='[' ) { // read a new group 01170 int end = strcspn( buf+1, "]\n\r" ); 01171 buf[ end+1 ] = 0; 01172 nd = prefs_->node->find( buf+1 ); 01173 } else if ( buf[0]=='+' ) { // value of previous name/value pair spans multiple lines 01174 int end = strcspn( buf+1, "\n\r" ); 01175 if ( end != 0 ) { // if entry is not empty 01176 buf[ end+1 ] = 0; 01177 nd->add( buf+1 ); 01178 } 01179 } else { // read a name/value pair 01180 int end = strcspn( buf, "\n\r" ); 01181 if ( end != 0 ) { // if entry is not empty 01182 buf[ end ] = 0; 01183 nd->set( buf ); 01184 } 01185 } 01186 } 01187 fclose( f ); 01188 return 0; 01189 } 01190 01191 // write the group tree and all entry leafs 01192 int Fl_Preferences::RootNode::write() { 01193 if (!filename_) // RUNTIME preferences 01194 return -1; 01195 fl_make_path_for_file(filename_); 01196 FILE *f = fl_fopen( filename_, "wb" ); 01197 if ( !f ) 01198 return -1; 01199 fprintf( f, "; FLTK preferences file format 1.0\n" ); 01200 fprintf( f, "; vendor: %s\n", vendor_ ); 01201 fprintf( f, "; application: %s\n", application_ ); 01202 prefs_->node->write( f ); 01203 fclose( f ); 01204 #if !(defined(__APPLE__) || defined(WIN32)) 01205 // unix: make sure that system prefs are user-readable 01206 if (strncmp(filename_, "/etc/fltk/", 10) == 0) { 01207 char *p; 01208 p = filename_ + 9; 01209 do { // for each directory to the pref file 01210 *p = 0; 01211 fl_chmod(filename_, 0755); // rwxr-xr-x 01212 *p = '/'; 01213 p = strchr(p+1, '/'); 01214 } while (p); 01215 fl_chmod(filename_, 0644); // rw-r--r-- 01216 } 01217 #endif 01218 return 0; 01219 } 01220 01221 // get the path to the preferences directory 01222 char Fl_Preferences::RootNode::getPath( char *path, int pathlen ) { 01223 if (!filename_) // RUNTIME preferences 01224 return -1; 01225 strlcpy( path, filename_, pathlen); 01226 01227 char *s; 01228 for ( s = path; *s; s++ ) if ( *s == '\\' ) *s = '/'; 01229 s = strrchr( path, '.' ); 01230 if ( !s ) return 0; 01231 *s = 0; 01232 char ret = fl_make_path( path ); 01233 #if !(defined(__APPLE__) || defined(WIN32)) 01234 // unix: make sure that system prefs dir. is user-readable 01235 if (strncmp(path, "/etc/fltk/", 10) == 0) { 01236 fl_chmod(path, 0755); // rwxr-xr-x 01237 } 01238 #endif 01239 strcpy( s, "/" ); 01240 return ret; 01241 } 01242 01243 // create a node that represents a group 01244 // - path must be a single word, prferable alnum(), dot and underscore only. Space is ok. 01245 Fl_Preferences::Node::Node( const char *path ) { 01246 if ( path ) path_ = strdup( path ); else path_ = 0; 01247 child_ = 0; next_ = 0; parent_ = 0; 01248 entry_ = 0; 01249 nEntry_ = NEntry_ = 0; 01250 dirty_ = 0; 01251 top_ = 0; 01252 indexed_ = 0; 01253 index_ = 0; 01254 nIndex_ = NIndex_ = 0; 01255 } 01256 01257 void Fl_Preferences::Node::deleteAllChildren() { 01258 Node *nx; 01259 for ( Node *nd = child_; nd; nd = nx ) { 01260 nx = nd->next_; 01261 delete nd; 01262 } 01263 child_ = 0L; 01264 dirty_ = 1; 01265 updateIndex(); 01266 } 01267 01268 void Fl_Preferences::Node::deleteAllEntries() { 01269 if ( entry_ ) { 01270 for ( int i = 0; i < nEntry_; i++ ) { 01271 if ( entry_[i].name ) { 01272 free( entry_[i].name ); 01273 entry_[i].name = 0L; 01274 } 01275 if ( entry_[i].value ) { 01276 free( entry_[i].value ); 01277 entry_[i].value = 0L; 01278 } 01279 } 01280 free( entry_ ); 01281 entry_ = 0L; 01282 nEntry_ = 0; 01283 NEntry_ = 0; 01284 } 01285 dirty_ = 1; 01286 } 01287 01288 // delete this and all depending nodes 01289 Fl_Preferences::Node::~Node() { 01290 deleteAllChildren(); 01291 deleteAllEntries(); 01292 deleteIndex(); 01293 if ( path_ ) { 01294 free( path_ ); 01295 path_ = 0L; 01296 } 01297 next_ = 0L; 01298 parent_ = 0L; 01299 } 01300 01301 // recursively check if any entry is dirty (was changed after loading a fresh prefs file) 01302 char Fl_Preferences::Node::dirty() { 01303 if ( dirty_ ) return 1; 01304 if ( next_ && next_->dirty() ) return 1; 01305 if ( child_ && child_->dirty() ) return 1; 01306 return 0; 01307 } 01308 01309 // write this node (recursively from the last neighbor back to this) 01310 // write all entries 01311 // write all children 01312 int Fl_Preferences::Node::write( FILE *f ) { 01313 if ( next_ ) next_->write( f ); 01314 fprintf( f, "\n[%s]\n\n", path_ ); 01315 for ( int i = 0; i < nEntry_; i++ ) { 01316 char *src = entry_[i].value; 01317 if ( src ) { // hack it into smaller pieces if needed 01318 fprintf( f, "%s:", entry_[i].name ); 01319 int cnt; 01320 for ( cnt = 0; cnt < 60; cnt++ ) 01321 if ( src[cnt]==0 ) break; 01322 fwrite( src, cnt, 1, f ); 01323 fprintf( f, "\n" ); 01324 src += cnt; 01325 for (;*src;) { 01326 for ( cnt = 0; cnt < 80; cnt++ ) 01327 if ( src[cnt]==0 ) break; 01328 fputc( '+', f ); 01329 fwrite( src, cnt, 1, f ); 01330 fputc( '\n', f ); 01331 src += cnt; 01332 } 01333 } 01334 else 01335 fprintf( f, "%s\n", entry_[i].name ); 01336 } 01337 if ( child_ ) child_->write( f ); 01338 dirty_ = 0; 01339 return 0; 01340 } 01341 01342 // set the parent node and create the full path 01343 void Fl_Preferences::Node::setParent( Node *pn ) { 01344 parent_ = pn; 01345 next_ = pn->child_; 01346 pn->child_ = this; 01347 sprintf( nameBuffer, "%s/%s", pn->path_, path_ ); 01348 free( path_ ); 01349 path_ = strdup( nameBuffer ); 01350 } 01351 01352 // find the corresponding root node 01353 Fl_Preferences::RootNode *Fl_Preferences::Node::findRoot() { 01354 Node *n = this; 01355 do { 01356 if (n->top_) 01357 return n->root_; 01358 n = n->parent(); 01359 } while (n); 01360 return 0L; 01361 } 01362 01363 // add a child to this node and set its path (try to find it first...) 01364 Fl_Preferences::Node *Fl_Preferences::Node::addChild( const char *path ) { 01365 sprintf( nameBuffer, "%s/%s", path_, path ); 01366 char *name = strdup( nameBuffer ); 01367 Node *nd = find( name ); 01368 free( name ); 01369 dirty_ = 1; 01370 updateIndex(); 01371 return nd; 01372 } 01373 01374 // create and set, or change an entry within this node 01375 void Fl_Preferences::Node::set( const char *name, const char *value ) 01376 { 01377 for ( int i=0; i<nEntry_; i++ ) { 01378 if ( strcmp( name, entry_[i].name ) == 0 ) { 01379 if ( !value ) return; // annotation 01380 if ( strcmp( value, entry_[i].value ) != 0 ) { 01381 if ( entry_[i].value ) 01382 free( entry_[i].value ); 01383 entry_[i].value = strdup( value ); 01384 dirty_ = 1; 01385 } 01386 lastEntrySet = i; 01387 return; 01388 } 01389 } 01390 if ( NEntry_==nEntry_ ) { 01391 NEntry_ = NEntry_ ? NEntry_*2 : 10; 01392 entry_ = (Entry*)realloc( entry_, NEntry_ * sizeof(Entry) ); 01393 } 01394 entry_[ nEntry_ ].name = strdup( name ); 01395 entry_[ nEntry_ ].value = value?strdup( value ):0; 01396 lastEntrySet = nEntry_; 01397 nEntry_++; 01398 dirty_ = 1; 01399 } 01400 01401 // create or set a value (or annotation) from a single line in the file buffer 01402 void Fl_Preferences::Node::set( const char *line ) { 01403 // hmm. If we assume that we always read this file in the beginning, 01404 // we can handle the dirty flag 'quick and dirty' 01405 char dirt = dirty_; 01406 if ( line[0]==';' || line[0]==0 || line[0]=='#' ) { 01407 set( line, 0 ); 01408 } else { 01409 const char *c = strchr( line, ':' ); 01410 if ( c ) { 01411 unsigned int len = c-line+1; 01412 if ( len >= sizeof( nameBuffer ) ) 01413 len = sizeof( nameBuffer ); 01414 strlcpy( nameBuffer, line, len ); 01415 set( nameBuffer, c+1 ); 01416 } else { 01417 set( line, "" ); 01418 } 01419 } 01420 dirty_ = dirt; 01421 } 01422 01423 // add more data to an existing entry 01424 void Fl_Preferences::Node::add( const char *line ) { 01425 if ( lastEntrySet<0 || lastEntrySet>=nEntry_ ) return; 01426 char *&dst = entry_[ lastEntrySet ].value; 01427 int a = strlen( dst ); 01428 int b = strlen( line ); 01429 dst = (char*)realloc( dst, a+b+1 ); 01430 memcpy( dst+a, line, b+1 ); 01431 dirty_ = 1; 01432 } 01433 01434 // get the value for a name, returns 0 if no such name 01435 const char *Fl_Preferences::Node::get( const char *name ) { 01436 int i = getEntry( name ); 01437 return i>=0 ? entry_[i].value : 0 ; 01438 } 01439 01440 // find the index of an entry, returns -1 if no such entry 01441 int Fl_Preferences::Node::getEntry( const char *name ) { 01442 for ( int i=0; i<nEntry_; i++ ) { 01443 if ( strcmp( name, entry_[i].name ) == 0 ) { 01444 return i; 01445 } 01446 } 01447 return -1; 01448 } 01449 01450 // remove one entry form this group 01451 char Fl_Preferences::Node::deleteEntry( const char *name ) { 01452 int ix = getEntry( name ); 01453 if ( ix == -1 ) return 0; 01454 memmove( entry_+ix, entry_+ix+1, (nEntry_-ix-1) * sizeof(Entry) ); 01455 nEntry_--; 01456 dirty_ = 1; 01457 return 1; 01458 } 01459 01460 // find a group somewhere in the tree starting here 01461 // - this method will always return a valid node (except for memory allocation problems) 01462 // - if the node was not found, 'find' will create the required branch 01463 Fl_Preferences::Node *Fl_Preferences::Node::find( const char *path ) { 01464 int len = strlen( path_ ); 01465 if ( strncmp( path, path_, len ) == 0 ) { 01466 if ( path[ len ] == 0 ) 01467 return this; 01468 if ( path[ len ] == '/' ) { 01469 Node *nd; 01470 for ( nd = child_; nd; nd = nd->next_ ) { 01471 Node *nn = nd->find( path ); 01472 if ( nn ) return nn; 01473 } 01474 const char *s = path+len+1; 01475 const char *e = strchr( s, '/' ); 01476 if (e) strlcpy( nameBuffer, s, e-s+1 ); 01477 else strlcpy( nameBuffer, s, sizeof(nameBuffer)); 01478 nd = new Node( nameBuffer ); 01479 nd->setParent( this ); 01480 return nd->find( path ); 01481 } 01482 } 01483 return 0; 01484 } 01485 01486 // find a group somewhere in the tree starting here 01487 // caller must not set 'offset' argument 01488 // - if the node does not exist, 'search' returns NULL 01489 // - if the pathname is "." (current node) return this node 01490 // - if the pathname is "./" (root node) return the topmost node 01491 // - if the pathname starts with "./", start the search at the root node instead 01492 Fl_Preferences::Node *Fl_Preferences::Node::search( const char *path, int offset ) { 01493 if ( offset == 0 ) { 01494 if ( path[0] == '.' ) { 01495 if ( path[1] == 0 ) { 01496 return this; // user was searching for current node 01497 } else if ( path[1] == '/' ) { 01498 Node *nn = this; 01499 while ( nn->parent() ) nn = nn->parent(); 01500 if ( path[2]==0 ) { // user is searching for root ( "./" ) 01501 return nn; 01502 } 01503 return nn->search( path+2, 2 ); // do a relative search on the root node 01504 } 01505 } 01506 offset = strlen( path_ ) + 1; 01507 } 01508 int len = strlen( path_ ); 01509 if ( len < offset-1 ) return 0; 01510 len -= offset; 01511 if ( ( len <= 0 ) || ( strncmp( path, path_+offset, len ) == 0 ) ) { 01512 if ( len > 0 && path[ len ] == 0 ) 01513 return this; 01514 if ( len <= 0 || path[ len ] == '/' ) { 01515 for ( Node *nd = child_; nd; nd = nd->next_ ) { 01516 Node *nn = nd->search( path, offset ); 01517 if ( nn ) return nn; 01518 } 01519 return 0; 01520 } 01521 } 01522 return 0; 01523 } 01524 01525 // return the number of child nodes (groups) 01526 int Fl_Preferences::Node::nChildren() { 01527 if (indexed_) { 01528 return nIndex_; 01529 } else { 01530 int cnt = 0; 01531 for ( Node *nd = child_; nd; nd = nd->next_ ) 01532 cnt++; 01533 return cnt; 01534 } 01535 } 01536 01537 // return the node name 01538 const char *Fl_Preferences::Node::name() { 01539 if ( path_ ) { 01540 char *r = strrchr( path_, '/' ); 01541 return r ? r+1 : path_ ; 01542 } else { 01543 return 0L ; 01544 } 01545 } 01546 01547 // return the n'th child node's name 01548 const char *Fl_Preferences::Node::child( int ix ) { 01549 Node *nd = childNode( ix ); 01550 if ( nd ) 01551 return nd->name(); 01552 else 01553 return 0L ; 01554 } 01555 01556 // return the n'th child node 01557 Fl_Preferences::Node *Fl_Preferences::Node::childNode( int ix ) { 01558 createIndex(); 01559 if (indexed_) { 01560 // usually faster access in correct order, but needing more memory 01561 return index_[ix]; 01562 } else { 01563 // slow access and reverse order 01564 int n = nChildren(); 01565 ix = n - ix -1; 01566 Node *nd; 01567 for ( nd = child_; nd; nd = nd->next_ ) { 01568 if ( !ix-- ) break; 01569 if ( !nd ) break; 01570 } 01571 return nd; 01572 } 01573 } 01574 01575 // remove myself from the list and delete me (and all children) 01576 char Fl_Preferences::Node::remove() { 01577 Node *nd = 0, *np; 01578 if ( parent() ) { 01579 nd = parent()->child_; np = 0L; 01580 for ( ; nd; np = nd, nd = nd->next_ ) { 01581 if ( nd == this ) { 01582 if ( np ) 01583 np->next_ = nd->next_; 01584 else 01585 parent()->child_ = nd->next_; 01586 break; 01587 } 01588 } 01589 parent()->dirty_ = 1; 01590 parent()->updateIndex(); 01591 } 01592 delete this; 01593 return ( nd != 0 ); 01594 } 01595 01596 void Fl_Preferences::Node::createIndex() { 01597 if (indexed_) return; 01598 int n = nChildren(); 01599 if (n>NIndex_) { 01600 NIndex_ = n + 16; 01601 index_ = (Node**)realloc(index_, NIndex_*sizeof(Node**)); 01602 } 01603 Node *nd; 01604 int i = 0; 01605 for (nd = child_; nd; nd = nd->next_, i++) { 01606 index_[n-i-1] = nd; 01607 } 01608 nIndex_ = n; 01609 indexed_ = 1; 01610 } 01611 01612 void Fl_Preferences::Node::updateIndex() { 01613 indexed_ = 0; 01614 } 01615 01616 void Fl_Preferences::Node::deleteIndex() { 01617 if (index_) free(index_); 01618 NIndex_ = nIndex_ = 0; 01619 index_ = 0; 01620 indexed_ = 0; 01621 } 01622 01629 Fl_Plugin::Fl_Plugin(const char *klass, const char *name) 01630 : id(0) { 01631 #ifdef FL_PLUGIN_VERBOSE 01632 printf("Fl_Plugin: creating a plugin, class \"%s\", name \"%s\"\n", 01633 klass, name); 01634 #endif 01635 Fl_Plugin_Manager pm(klass); 01636 id = pm.addPlugin(name, this); 01637 } 01638 01642 Fl_Plugin::~Fl_Plugin() { 01643 #ifdef FL_PLUGIN_VERBOSE 01644 printf("Fl_Plugin: deleting a plugin\n"); 01645 #endif 01646 if (id) 01647 Fl_Plugin_Manager::remove(id); 01648 } 01649 01653 Fl_Plugin_Manager::Fl_Plugin_Manager(const char *klass) 01654 : Fl_Preferences(0, Fl_Preferences::Name("%s/%s", "plugins", klass)) { 01655 #ifdef FL_PLUGIN_VERBOSE 01656 printf("Fl_Plugin: creating a plugin manager for class \"%s\"\n", klass); 01657 #endif 01658 } 01659 01666 Fl_Plugin_Manager::~Fl_Plugin_Manager() { 01667 #ifdef FL_PLUGIN_VERBOSE 01668 printf("Fl_Plugin: deleting a plugin manager\n"); 01669 #endif 01670 } 01671 01672 static unsigned char x2i(char hi, char lo) { 01673 return ((hi-'A')<<4) | (lo-'A'); 01674 } 01675 01676 static void i2x(unsigned char v, char *d) { 01677 d[0] = ((v>>4)&0x0f)+'A'; d[1] = (v&0x0f)+'A'; 01678 } 01679 01680 static void *a2p(const char *s) { 01681 union { void *ret; unsigned char d[sizeof(void*)]; } v; 01682 v.ret = 0L; 01683 int i=0, n=sizeof(void*); 01684 for (i=0; i<n; i++) { 01685 v.d[i] = x2i(s[2*i], s[2*i+1]); 01686 } 01687 return v.ret; 01688 } 01689 01690 static void p2a(void *vp, char *d) { 01691 union { void *vp; unsigned char s[sizeof(void*)]; } v; 01692 v.vp = vp; 01693 int i=0, n=sizeof(void*); 01694 for (i=0; i<n; i++) { 01695 i2x(v.s[i], d+i*2); 01696 } 01697 d[2*i] = 0; 01698 } 01699 01703 Fl_Plugin *Fl_Plugin_Manager::plugin(int index) { 01704 char buf[34]; 01705 Fl_Plugin *ret = 0; 01706 Fl_Preferences pin(this, index); 01707 pin.get("address", buf, "", 34); 01708 if (buf[0]=='@') ret = (Fl_Plugin*)a2p(buf+1); 01709 #ifdef FL_PLUGIN_VERBOSE 01710 printf("Fl_Plugin: returning plugin at index %d: (%s) %p\n", index, buf, ret); 01711 #endif 01712 return ret; 01713 } 01714 01718 Fl_Plugin *Fl_Plugin_Manager::plugin(const char *name) { 01719 char buf[34]; 01720 Fl_Plugin *ret = 0; 01721 if (groupExists(name)) { 01722 Fl_Preferences pin(this, name); 01723 pin.get("address", buf, "", 34); 01724 if (buf[0]=='@') ret = (Fl_Plugin*)a2p(buf+1); 01725 #ifdef FL_PLUGIN_VERBOSE 01726 printf("Fl_Plugin: returning plugin named \"%s\": (%s) %p\n", name, buf, ret); 01727 #endif 01728 return ret; 01729 } else { 01730 #ifdef FL_PLUGIN_VERBOSE 01731 printf("Fl_Plugin: no plugin found named \"%s\"\n", name); 01732 #endif 01733 return 0L; 01734 } 01735 } 01736 01743 Fl_Preferences::ID Fl_Plugin_Manager::addPlugin(const char *name, Fl_Plugin *plugin) { 01744 char buf[34]; 01745 #ifdef FL_PLUGIN_VERBOSE 01746 printf("Fl_Plugin: adding plugin named \"%s\" at 0x%p\n", name, plugin); 01747 #endif 01748 Fl_Preferences pin(this, name); 01749 buf[0] = '@'; p2a(plugin, buf+1); 01750 pin.set("address", buf); 01751 return pin.id(); 01752 } 01753 01760 void Fl_Plugin_Manager::removePlugin(Fl_Preferences::ID id) { 01761 Fl_Preferences::remove(id); 01762 } 01763 01772 int Fl_Plugin_Manager::load(const char *filename) { 01773 // the functions below will autmaticaly load plugins that are defined: 01774 // Fl_My_Plugin plugin(); 01775 #if defined(WIN32) && !defined(__CYGWIN__) 01776 HMODULE dl = LoadLibrary(filename); 01777 #else 01778 void * dl = dlopen(filename, RTLD_LAZY); 01779 #endif 01780 // There is no way of unloading a plugin! 01781 return (dl!=0) ? 0 : -1; 01782 } 01783 01787 int Fl_Plugin_Manager::loadAll(const char *filepath, const char *pattern) { 01788 struct dirent **dir; 01789 int i, n = fl_filename_list(filepath, &dir); 01790 for (i=0; i<n; i++) { 01791 struct dirent *e = dir[i]; 01792 if (pattern==0 || fl_filename_match(e->d_name, pattern)) { 01793 load(Fl_Preferences::Name("%s%s", filepath, e->d_name)); 01794 } 01795 free(e); 01796 } 01797 free(dir); 01798 return 0; 01799 } 01800 01801 // 01802 // End of "$Id: Fl_Preferences.cxx 8173 2011-01-03 16:50:34Z manolo $". 01803 //