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)  

Fl_Preferences.cxx

Go to the documentation of this file.
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 //