fl_preferences.cxx
来自「SRI international 发布的OAA框架软件」· CXX 代码 · 共 1,121 行 · 第 1/2 页
CXX
1,121 行
int len = s-path;
char *p = (char*)malloc( len+1 );
memcpy( p, path, len );
p[len] = 0;
makePath( p );
free( p );
#if defined(WIN32) && !defined(__CYGWIN__)
return ( mkdir( path ) == 0 );
#else
return ( mkdir( path, 0777 ) == 0 );
#endif // WIN32 && !__CYGWIN__
}
return 1;
}
// strip the filename and create a path
static void makePathForFile( const char *path )
{
const char *s = strrchr( path, '/' );
if ( !s ) return;
int len = s-path;
char *p = (char*)malloc( len+1 );
memcpy( p, path, len );
p[len] = 0;
makePath( p );
free( p );
}
// create the root node
// - construct the name of the file that will hold our preferences
Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char *vendor, const char *application )
{
char filename[ FL_PATH_MAX ]; filename[0] = 0;
#ifdef WIN32
# define FLPREFS_RESOURCE "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
int appDataLen = strlen(vendor) + strlen(application) + 8;
DWORD type, nn;
LONG err;
HKEY key;
switch (root) {
case SYSTEM:
err = RegOpenKey( HKEY_LOCAL_MACHINE, FLPREFS_RESOURCE, &key );
if (err == ERROR_SUCCESS) {
nn = FL_PATH_MAX - appDataLen;
err = RegQueryValueEx( key, "Common AppData", 0L, &type, (BYTE*)filename, &nn );
if ( ( err != ERROR_SUCCESS ) && ( type == REG_SZ ) )
filename[0] = 0;
RegCloseKey(key);
}
break;
case USER:
err = RegOpenKey( HKEY_CURRENT_USER, FLPREFS_RESOURCE, &key );
if (err == ERROR_SUCCESS) {
nn = FL_PATH_MAX - appDataLen;
err = RegQueryValueEx( key, "AppData", 0L, &type, (BYTE*)filename, &nn );
if ( ( err != ERROR_SUCCESS ) && ( type == REG_SZ ) )
filename[0] = 0;
RegCloseKey(key);
}
break;
}
if (!filename[0]) {
strcpy(filename, "C:\\FLTK");
}
snprintf(filename + strlen(filename), sizeof(filename) - strlen(filename),
"/%s/%s.prefs", vendor, application);
for (char *s = filename; *s; s++) if (*s == '\\') *s = '/';
#elif defined ( __APPLE__ )
FSSpec spec = { 0 };
FSRef ref;
OSErr err = fnfErr;
switch (root) {
case SYSTEM:
err = FindFolder( kLocalDomain, kPreferencesFolderType,
1, &spec.vRefNum, &spec.parID );
break;
case USER:
err = FindFolder( kUserDomain, kPreferencesFolderType,
1, &spec.vRefNum, &spec.parID );
break;
}
FSpMakeFSRef( &spec, &ref );
FSRefMakePath( &ref, (UInt8*)filename, FL_PATH_MAX );
snprintf(filename + strlen(filename), sizeof(filename) - strlen(filename),
"/%s/%s.prefs", vendor, application );
#else
const char *e;
switch (root) {
case USER:
if ((e = getenv("HOME")) != NULL) {
strlcpy(filename, e, sizeof(filename));
if (filename[strlen(filename)-1] != '/') {
strlcat(filename, "/.fltk/", sizeof(filename));
} else {
strlcat(filename, ".fltk/", sizeof(filename));
}
break;
}
case SYSTEM:
strcpy(filename, "/etc/fltk/");
break;
}
snprintf(filename + strlen(filename), sizeof(filename) - strlen(filename),
"%s/%s.prefs", vendor, application);
#endif
makePathForFile(filename);
prefs_ = prefs;
filename_ = strdup(filename);
vendor_ = strdup(vendor);
application_ = strdup(application);
read();
}
// create the root node
// - construct the name of the file that will hold our preferences
Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, const char *vendor, const char *application )
{
char filename[ FL_PATH_MAX ]; filename[0] = 0;
snprintf(filename, sizeof(filename), "%s/%s.prefs", path, application);
makePathForFile(filename);
prefs_ = prefs;
filename_ = strdup(filename);
vendor_ = strdup(vendor);
application_ = strdup(application);
read();
}
// destroy the root node and all depending nodes
Fl_Preferences::RootNode::~RootNode()
{
if ( prefs_->node->dirty() )
write();
if ( filename_ )
free( filename_ );
if ( vendor_ )
free( vendor_ );
if ( application_ )
free( application_ );
delete prefs_->node;
}
// read a preferences file and construct the group tree and with all entry leafs
int Fl_Preferences::RootNode::read()
{
char buf[1024];
FILE *f = fopen( filename_, "rb" );
if ( !f ) return 0;
fgets( buf, 1024, f );
fgets( buf, 1024, f );
fgets( buf, 1024, f );
Node *nd = prefs_->node;
for (;;)
{
if ( !fgets( buf, 1024, f ) ) break; // EOF or Error
if ( buf[0]=='[' ) // read a new group
{
int end = strcspn( buf+1, "]\n\r" );
buf[ end+1 ] = 0;
nd = prefs_->node->find( buf+1 );
}
else if ( buf[0]=='+' ) //
{ // value of previous name/value pair spans multiple lines
int end = strcspn( buf+1, "\n\r" );
if ( end != 0 ) // if entry is not empty
{
buf[ end+1 ] = 0;
nd->add( buf+1 );
}
}
else // read a name/value pair
{
int end = strcspn( buf, "\n\r" );
if ( end != 0 ) // if entry is not empty
{
buf[ end ] = 0;
nd->set( buf );
}
}
}
fclose( f );
return 0;
}
// write the group tree and all entry leafs
int Fl_Preferences::RootNode::write()
{
FILE *f = fopen( filename_, "wb" );
if ( !f ) return 1;
fprintf( f, "; FLTK preferences file format 1.0\n" );
fprintf( f, "; vendor: %s\n", vendor_ );
fprintf( f, "; application: %s\n", application_ );
prefs_->node->write( f );
fclose( f );
return 0;
}
// get the path to the preferences directory
char Fl_Preferences::RootNode::getPath( char *path, int pathlen )
{
strlcpy( path, filename_, pathlen);
char *s;
for ( s = path; *s; s++ ) if ( *s == '\\' ) *s = '/';
s = strrchr( path, '.' );
if ( !s ) return 0;
*s = 0;
char ret = makePath( path );
strcpy( s, "/" );
return ret;
}
// create a node that represents a group
// - path must be a single word, prferable alnum(), dot and underscore only. Space is ok.
Fl_Preferences::Node::Node( const char *path )
{
if ( path ) path_ = strdup( path ); else path_ = 0;
child_ = 0; next_ = 0; parent_ = 0;
entry = 0;
nEntry = NEntry = 0;
dirty_ = 0;
}
// delete this and all depending nodes
Fl_Preferences::Node::~Node()
{
Node *nx;
for ( Node *nd = child_; nd; nd = nx )
{
nx = nd->next_;
delete nd;
}
if ( entry )
{
for ( int i = 0; i < nEntry; i++ )
{
if ( entry[i].name )
free( entry[i].name );
if ( entry[i].value )
free( entry[i].value );
}
free( entry );
}
if ( path_ )
free( path_ );
}
// recursively check if any entry is dirty (was changed after loading a fresh prefs file)
char Fl_Preferences::Node::dirty()
{
if ( dirty_ ) return 1;
if ( next_ && next_->dirty() ) return 1;
if ( child_ && child_->dirty() ) return 1;
return 0;
}
// write this node (recursively from the last neighbor back to this)
// write all entries
// write all children
int Fl_Preferences::Node::write( FILE *f )
{
if ( next_ ) next_->write( f );
fprintf( f, "\n[%s]\n\n", path_ );
for ( int i = 0; i < nEntry; i++ )
{
char *src = entry[i].value;
if ( src )
{ // hack it into smaller pieces if needed
fprintf( f, "%s:", entry[i].name );
int cnt;
for ( cnt = 0; cnt < 60; cnt++ )
if ( src[cnt]==0 ) break;
fwrite( src, cnt, 1, f );
fprintf( f, "\n" );
src += cnt;
for (;*src;)
{
for ( cnt = 0; cnt < 80; cnt++ )
if ( src[cnt]==0 ) break;
fputc( '+', f );
fwrite( src, cnt, 1, f );
fputc( '\n', f );
src += cnt;
}
}
else
fprintf( f, "%s\n", entry[i].name );
}
if ( child_ ) child_->write( f );
dirty_ = 0;
return 0;
}
// set the parent node and create the full path
void Fl_Preferences::Node::setParent( Node *pn )
{
parent_ = pn;
next_ = pn->child_;
pn->child_ = this;
sprintf( nameBuffer, "%s/%s", pn->path_, path_ );
free( path_ );
path_ = strdup( nameBuffer );
}
// add a child to this node and set its path (try to find it first...)
Fl_Preferences::Node *Fl_Preferences::Node::addChild( const char *path )
{
sprintf( nameBuffer, "%s/%s", path_, path );
char *name = strdup( nameBuffer );
Node *nd = find( nameBuffer );
free( name );
dirty_ = 1;
return nd;
}
// create and set, or change an entry within this node
void Fl_Preferences::Node::set( const char *name, const char *value )
{
for ( int i=0; i<nEntry; i++ )
{
if ( strcmp( name, entry[i].name ) == 0 )
{
if ( !value ) return; // annotation
if ( strcmp( value, entry[i].value ) != 0 )
{
if ( entry[i].value )
free( entry[i].value );
entry[i].value = strdup( value );
dirty_ = 1;
}
lastEntrySet = i;
return;
}
}
if ( NEntry==nEntry )
{
NEntry = NEntry ? NEntry*2 : 10;
entry = (Entry*)realloc( entry, NEntry * sizeof(Entry) );
}
entry[ nEntry ].name = strdup( name );
entry[ nEntry ].value = value?strdup( value ):0;
lastEntrySet = nEntry;
nEntry++;
dirty_ = 1;
}
// create or set a value (or annotation) from a single line in the file buffer
void Fl_Preferences::Node::set( const char *line )
{
// hmm. If we assume that we always read this file in the beginning,
// we can handle the dirty flag 'quick and dirty'
char dirt = dirty_;
if ( line[0]==';' || line[0]==0 || line[0]=='#' )
{
set( line, 0 );
}
else
{
const char *c = strchr( line, ':' );
if ( c )
{
strlcpy( nameBuffer, line, c-line+1);
set( nameBuffer, c+1 );
}
else
set( line, "" );
}
dirty_ = dirt;
}
// add more data to an existing entry
void Fl_Preferences::Node::add( const char *line )
{
if ( lastEntrySet<0 || lastEntrySet>=nEntry ) return;
char *&dst = entry[ lastEntrySet ].value;
int a = strlen( dst );
int b = strlen( line );
dst = (char*)realloc( dst, a+b+1 );
memcpy( dst+a, line, b+1 );
dirty_ = 1;
}
// get the value for a name, returns 0 if no such name
const char *Fl_Preferences::Node::get( const char *name )
{
int i = getEntry( name );
return i>=0 ? entry[i].value : 0 ;
}
// find the index of an entry, returns -1 if no such entry
int Fl_Preferences::Node::getEntry( const char *name )
{
for ( int i=0; i<nEntry; i++ )
{
if ( strcmp( name, entry[i].name ) == 0 )
{
return i;
}
}
return -1;
}
// remove one entry form this group
char Fl_Preferences::Node::deleteEntry( const char *name )
{
int ix = getEntry( name );
if ( ix == -1 ) return 0;
memmove( entry+ix, entry+ix+1, (nEntry-ix-1) * sizeof(Entry) );
nEntry--;
dirty_ = 1;
return 1;
}
// find a group somewhere in the tree starting here
// - this method will always return a valid node (except for memory allocation problems)
// - if the node was not found, 'find' will create the required branch
Fl_Preferences::Node *Fl_Preferences::Node::find( const char *path )
{
int len = strlen( path_ );
if ( strncmp( path, path_, len ) == 0 )
{
if ( path[ len ] == 0 )
return this;
if ( path[ len ] == '/' )
{
Node *nd;
for ( nd = child_; nd; nd = nd->next_ )
{
Node *nn = nd->find( path );
if ( nn ) return nn;
}
const char *s = path+len+1;
const char *e = strchr( s, '/' );
if (e) strlcpy( nameBuffer, s, e-s+1 );
else strlcpy( nameBuffer, s, sizeof(nameBuffer));
nd = new Node( nameBuffer );
nd->setParent( this );
return nd->find( path );
}
}
return 0;
}
// find a group somewhere in the tree starting here
// caller must not set 'offset' argument
// - if the node does not exist, 'search' returns NULL
// - if the pathname is "." (current node) return this node
// - if the pathname is "./" (root node) return the topmost node
// - if the pathname starts with "./", start the search at the root node instead
Fl_Preferences::Node *Fl_Preferences::Node::search( const char *path, int offset )
{
if ( offset == 0 )
{
if ( path[0] == '.' )
{
if ( path[1] == 0 )
{
return this; // user was searching for current node
}
else if ( path[1] == '/' )
{
Node *nn = this;
while ( nn->parent_ ) nn = nn->parent_;
if ( path[2]==0 )
{ // user is searching for root ( "./" )
return nn;
}
return nn->search( path+2, 2 ); // do a relative search on the root node
}
}
offset = strlen( path_ ) + 1;
}
int len = strlen( path_ );
if ( len < offset-1 ) return 0;
len -= offset;
if ( ( len <= 0 ) || ( strncmp( path, path_+offset, len ) == 0 ) )
{
if ( len > 0 && path[ len ] == 0 )
return this;
if ( len <= 0 || path[ len ] == '/' )
{
for ( Node *nd = child_; nd; nd = nd->next_ )
{
Node *nn = nd->search( path, offset );
if ( nn ) return nn;
}
return 0;
}
}
return 0;
}
// return the number of child nodes (groups)
int Fl_Preferences::Node::nChildren()
{
int cnt = 0;
for ( Node *nd = child_; nd; nd = nd->next_ )
cnt++;
return cnt;
}
// return the n'th child node
const char *Fl_Preferences::Node::child( int ix )
{
Node *nd;
for ( nd = child_; nd; nd = nd->next_ )
{
if ( !ix-- ) break;
}
if ( nd && nd->path_ )
{
char *r = strrchr( nd->path_, '/' );
return r ? r+1 : nd->path_ ;
}
return 0L ;
}
// remove myself from the list and delete me (and all children)
char Fl_Preferences::Node::remove()
{
Node *nd = 0, *np;
if ( parent_ )
{
nd = parent_->child_; np = 0L;
for ( ; nd; nd = nd->next_ )
{
if ( nd == this )
{
if ( np )
np->next_ = nd->next_;
else
parent_->child_ = nd->next_;
break;
}
}
}
delete this;
dirty_ = 1;
return ( nd != 0 );
}
//
// End of "$Id: Fl_Preferences.cxx,v 1.1.1.1 2003/06/03 22:25:43 agno Exp $".
//
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?