00001 /* -*- Mode: C++ -*- 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Defines a hierarchical registry abstraction. 00006 */ 00007 #ifndef __UNICONF_H 00008 #define __UNICONF_H 00009 00010 #ifdef __cplusplus 00011 00012 #include "uniconfkey.h" 00013 #include "uniconfgen.h" 00014 #include "wvcallback.h" 00015 #include "wvvector.h" 00016 00017 class WvStream; 00018 class UniConf; 00019 class UniConfRoot; 00020 00021 /** 00022 * The callback type for signalling key changes from UniConf. 00023 * 00024 * Parameters: cfg, relkey 00025 * cfg - the UniConf config object representing the key that has changed 00026 * relkey - the changed keypath, relative to the config object 00027 */ 00028 typedef WvCallback<void, const UniConf &, const UniConfKey &> UniConfCallback; 00029 00030 /** 00031 * UniConf instances function as handles to subtrees of a UniConf 00032 * tree and expose a high-level interface for clients. 00033 * 00034 * All operations are marked "const" unless they modify the target 00035 * of the handle. In effect, this grants UniConf handles the 00036 * same semantics as pointers where a const pointer may point 00037 * to a non-const object, which simply means that the pointer 00038 * cannot be reassigned. 00039 * 00040 * When handles are returned from functions, they are always marked 00041 * const to guard against accidentally assigning to a temporary by 00042 * an expression such as cfg["foo"] = cfg["bar"]. 00043 * Instead this must be written as 00044 * cfg["foo"].set(cfg["bar"].get()) 00045 * which is slightly 00046 * less elegant but avoids many subtle mistakes. Also for this 00047 * reason, unusual cast operators, assignment operators, 00048 * or copy constructors are not provided. Please do not add any. 00049 * 00050 */ 00051 class UniConf 00052 { 00053 friend class UniConfRoot; 00054 00055 protected: 00056 UniConfRoot *xroot; 00057 UniConfKey xfullkey; 00058 00059 /** 00060 * Creates a handle to the specified subtree of the given root. 00061 * 00062 * You can't create non-NULL UniConf objects yourself - ask UniConfRoot 00063 * or another UniConf object to make one for you. 00064 */ 00065 UniConf(UniConfRoot *root, const UniConfKey &fullkey = UniConfKey::EMPTY) 00066 : xroot(root), xfullkey(fullkey) { } 00067 00068 public: 00069 /** Creates a NULL UniConf handle, useful for reporting errors. */ 00070 UniConf() 00071 : xroot(NULL), xfullkey(UniConfKey::EMPTY) { } 00072 00073 /** 00074 * Copies a UniConf handle. 00075 * "other" is the handle to copy 00076 */ 00077 UniConf(const UniConf &other) 00078 : xroot(other.xroot), xfullkey(other.xfullkey) { } 00079 00080 /** Destroys the UniConf handle. */ 00081 virtual ~UniConf() { } 00082 00083 00084 /***** Handle Manipulation API *****/ 00085 00086 /** Returns a handle to the root of the tree. */ 00087 UniConf root() const 00088 { return UniConf(xroot, UniConfKey::EMPTY); } 00089 00090 /** Returns a handle to the parent of this node. */ 00091 UniConf parent() const 00092 { return UniConf(xroot, xfullkey.removelast()); } 00093 00094 /** 00095 * Returns a pointer to the UniConfRoot that manages this node. 00096 * This may be NULL, to signal an invalid handle. 00097 */ 00098 UniConfRoot *rootobj() const 00099 { return xroot; } 00100 00101 /** Returns true if the handle is invalid (NULL). */ 00102 bool isnull() const 00103 { return xroot == NULL; } 00104 00105 /** Returns the full path of this node, starting at the root. */ 00106 UniConfKey fullkey() const 00107 { return xfullkey; } 00108 00109 /** Returns the full path of this node, starting at the given key. 00110 * Assumes that k is an ancestor of fullkey(). */ 00111 UniConfKey fullkey(const UniConfKey &k) const; 00112 00113 /** Returns the full path of this node, starting at the given handle. */ 00114 UniConfKey fullkey(const UniConf &cfg) const 00115 { return fullkey(cfg.fullkey()); } 00116 00117 /** Returns the path of this node relative to its parent. */ 00118 UniConfKey key() const 00119 { return xfullkey.last(); } 00120 00121 /** 00122 * Returns a handle for a subtree below this key. 'key' is the path 00123 * of the subtree to be appended to the full path of this handle to 00124 * obtain the full path of the new handle. 00125 */ 00126 const UniConf operator[] (const UniConfKey &key) const 00127 { return UniConf(xroot, UniConfKey(xfullkey, key)); } 00128 00129 /** Reassigns the target of this handle to match a different one. */ 00130 UniConf &operator= (const UniConf &other) 00131 { 00132 xroot = other.xroot; 00133 xfullkey = other.xfullkey; 00134 return *this; 00135 } 00136 00137 00138 /***** Key Retrieval API *****/ 00139 00140 /** 00141 * Fetches the string value for this key from the registry. If the 00142 * key is not found, returns 'defvalue' instead. 00143 */ 00144 WvString get(WvStringParm defvalue = WvString::null) const; 00145 00146 /** 00147 * Without fetching its value, returns true if this key exists. 00148 * 00149 * This is provided because it is often more efficient to 00150 * test existance than to actually retrieve the value. 00151 */ 00152 bool exists() const; 00153 00154 /** 00155 * Fetches the integer value for this key from the registry. If the 00156 * key is not found, returns 'defvalue' instead. (This is also used to 00157 * fetch booleans - 'true', 'yes', 'on' and 'enabled' are recognized as 00158 * 1, 'false', 'no', 'off' and 'disabled' as 0. Note that a nonexistant 00159 * key is false by default.) 00160 */ 00161 int getint(int defvalue = 0) const; 00162 00163 00164 /***** Key Storage API *****/ 00165 00166 /** 00167 * Stores a string value for this key into the registry. If the value 00168 * is WvString::null, deletes the key and all of its children. 00169 * Returns true on success. 00170 */ 00171 void set(WvStringParm value) const; 00172 00173 /** 00174 * Stores a string value for this key into the registry. 00175 * Returns true on success. 00176 */ 00177 void set(WVSTRING_FORMAT_DECL) const 00178 { return set(WvString(WVSTRING_FORMAT_CALL)); } 00179 00180 /** 00181 * Stores an integer value for this key into the registry. 00182 * Returns true on success. 00183 */ 00184 void setint(int value) const; 00185 00186 00187 /***** Key Handling API *****/ 00188 00189 /** 00190 * Equivalent to "mv" in a standard unix filesystem. This recursively 00191 * moves a given key and any subkeys to a new point. If the new point 00192 * exists then the key will be left as a subkey at the new point. 00193 * Otherwise, the key will also be renamed to the new point (as when 00194 * using mv). 00195 * 00196 * Don't try to do dumb stuff like making dst a subkey of this one, 00197 * or vice versa, because we won't try to save you. 00198 * 00199 * Unlike unix mv(), this is *not* currently atomic. It's more like 00200 * cp-then-rm. 00201 */ 00202 void move(const UniConf &dst); 00203 00204 /** 00205 * Removes this key and all of its children from the registry. 00206 * Returns true on success. 00207 */ 00208 void remove() const 00209 { set(WvString::null); } 00210 00211 /** 00212 * Equivalent to "cp -r" in a standard unix filesystem. This 00213 * recursively copies a given key to a new location. Any keys that 00214 * already exist at that location will not be overridden unless force 00215 * is true. 00216 * 00217 * Don't try to do dumb stuff like making dst a subkey of this one, 00218 * or vice versa, because we won't try to save you. 00219 */ 00220 void copy(const UniConf &dst, bool force) const; 00221 00222 00223 00224 /***** Key Persistence API *****/ 00225 00226 /** 00227 * Refreshes information about this key recursively. 00228 * May discard uncommitted data. 00229 * Returns true on success. 00230 */ 00231 bool refresh() const; 00232 00233 /** 00234 * Commits information about this key recursively. 00235 */ 00236 void commit() const; 00237 00238 00239 /***** Generator Mounting API *****/ 00240 00241 /** 00242 * Mounts a generator at this key using a moniker. 00243 * 00244 * If 'refresh' is true, automatically refresh()es the generator 00245 * after mounting. 00246 * 00247 * Returns the mounted generator, or NULL on failure. 00248 */ 00249 UniConfGen *mount(WvStringParm moniker, bool refresh = true) const; 00250 00251 /** 00252 * Mounts a generator at this key. 00253 * 00254 * Takes ownership of the supplied generator instance. 00255 * 00256 * If 'refresh' is true, automatically refresh()es the generator 00257 * after mounting. 00258 * 00259 * Returns the mounted generator, or NULL on failure. 00260 */ 00261 UniConfGen *mountgen(UniConfGen *gen, bool refresh = true) const; 00262 00263 /** Unmounts the generator providing this key and destroys it. */ 00264 void unmount(UniConfGen *gen, bool commit) const; 00265 00266 /** Determines if any generators are mounted at this key. */ 00267 bool ismountpoint() const; 00268 00269 /** 00270 * Finds the generator that owns this key. 00271 * 00272 * If the key exists, returns the generator that provides its 00273 * contents. Otherwise returns the generator that would be 00274 * updated if a value were set. 00275 * 00276 * If non-NULL, 'mountpoint' is set to the actual key where the generator 00277 * is mounted. 00278 */ 00279 UniConfGen *whichmount(UniConfKey *mountpoint = NULL) const; 00280 00281 00282 /***** Notification API *****/ 00283 00284 /** 00285 * Requests notification when any of the keys covered by the 00286 * recursive depth specification change by invoking a callback. 00287 */ 00288 void add_callback(void *cookie, const UniConfCallback &callback, 00289 bool recurse = true) const; 00290 00291 /** 00292 * Cancels notification requested using add_callback(). 00293 */ 00294 void del_callback(void *cookie, bool recurse = true) const; 00295 00296 /** 00297 * Requests notification when any of the keys covered by the 00298 * recursive depth specification change by setting a flag. 00299 */ 00300 void add_setbool(bool *flag, bool recurse = true) const; 00301 00302 /** 00303 * Cancels notification requested using add_setbool(). 00304 */ 00305 void del_setbool(bool *flag, bool recurse = true) const; 00306 00307 /** 00308 * Pauses notifications until matched with a call to unhold_delta(). 00309 * 00310 * While paused, notification events are placed into a pending list. 00311 * Redundant notifications may be discarded. 00312 * 00313 * Use this to safeguard non-reentrant code. 00314 */ 00315 void hold_delta(); 00316 00317 /** 00318 * Resumes notifications when each hold_delta() has been matched. 00319 * 00320 * On resumption, dispatches all pending notifications except 00321 * those that were destined to watches that were removed. 00322 * 00323 * Use this to safeguard non-reentrant code. 00324 */ 00325 void unhold_delta(); 00326 00327 /** 00328 * Clears the list of pending notifications without sending them. 00329 * Does not affect the hold nesting count. 00330 */ 00331 void clear_delta(); 00332 00333 /** 00334 * Flushes the list of pending notifications by sending them. 00335 * Does not affect the hold nesting count. 00336 */ 00337 void flush_delta(); 00338 00339 00340 /***** Key Enumeration API *****/ 00341 00342 /** 00343 * Prints the entire contents of this subtree to a stream. 00344 * If 'everything' is true, also prints empty values. 00345 */ 00346 void dump(WvStream &stream, bool everything = false) const; 00347 00348 /** 00349 * Returns true if this key has children. 00350 * 00351 * This is provided because it is often more efficient to 00352 * test existance than to actually retrieve the keys. 00353 */ 00354 bool haschildren() const; 00355 00356 /*** Iterators (see comments in class declaration) ***/ 00357 00358 // internal base class for all of the key iterators 00359 class IterBase; 00360 // iterates over direct children 00361 class Iter; 00362 // iterates over all descendents in preorder traversal 00363 class RecursiveIter; 00364 // iterates over children matching a wildcard 00365 class XIter; 00366 00367 // internal base class for sorted key iterators 00368 class SortedIterBase; 00369 // sorted variant of Iter 00370 class SortedIter; 00371 // sorted variant of RecursiveIter 00372 class SortedRecursiveIter; 00373 // sorted variant of XIter 00374 class SortedXIter; 00375 00376 // lists of iterators 00377 DeclareWvList(Iter); 00378 }; 00379 00380 00381 /** 00382 * An implementation base class for key iterators. 00383 */ 00384 class UniConf::IterBase 00385 { 00386 protected: 00387 UniConf top; 00388 UniConf current; 00389 00390 IterBase(const UniConf &_top) 00391 : top(_top) 00392 { } 00393 00394 public: 00395 const UniConf *ptr() const 00396 { return ¤t; } 00397 WvIterStuff(const UniConf); 00398 }; 00399 00400 00401 /** 00402 * This iterator walks through all immediate children of a UniConf node. 00403 */ 00404 class UniConf::Iter : public UniConf::IterBase 00405 { 00406 UniConfGen::Iter *it; 00407 00408 public: 00409 /** Creates an iterator over the direct children of a branch. */ 00410 Iter(const UniConf &_top); 00411 00412 ~Iter() 00413 { delete it; } 00414 00415 void rewind() 00416 { it->rewind(); } 00417 bool next() 00418 { 00419 if (! it->next()) 00420 return false; 00421 current = top[it->key()]; 00422 return true; 00423 } 00424 }; 00425 00426 00427 /** 00428 * This iterator performs depth-first traversal of a subtree. 00429 */ 00430 class UniConf::RecursiveIter : public UniConf::IterBase 00431 { 00432 UniConf::IterList itlist; 00433 00434 public: 00435 /** Creates a recursive iterator over a branch. */ 00436 RecursiveIter(const UniConf &_top); 00437 00438 void rewind(); 00439 bool next(); 00440 }; 00441 00442 00443 /** 00444 * This iterator walks over all children that match a wildcard 00445 * pattern. 00446 * 00447 * See UniConfKey::matches(const UniConfKey&) for information about patterns. 00448 * 00449 * Example patterns: (where STAR is the asterisk character, '*') 00450 * 00451 * "": a null iterator 00452 * "a": matches only the key "a" if it exists 00453 * "STAR": matches all direct children 00454 * "STAR/foo": matches any existing key "foo" under direct children 00455 * "STAR/STAR": matches all children of depth exactly 2 00456 * "foo/...": matches all keys including and below "foo" 00457 * "foo/STAR/...": matches all keys below "foo" 00458 * ".../foo/STAR": matches all keys below any subkey named "foo" in the tree 00459 */ 00460 class UniConf::XIter : public UniConf::IterBase 00461 { 00462 UniConfKey pathead; 00463 UniConfKey pattail; 00464 UniConf::XIter *subit; 00465 UniConf::Iter *it; /*!< iterator over direct children */ 00466 UniConf::RecursiveIter *recit; /*!< iterator over descendents */ 00467 bool ready; /*!< next key is ready */ 00468 00469 public: 00470 /** Creates a wildcard iterator. */ 00471 XIter(const UniConf &_top, const UniConfKey &pattern); 00472 ~XIter(); 00473 00474 void rewind(); 00475 bool next(); 00476 00477 private: 00478 void cleanup(); 00479 bool qnext(); 00480 void enter(const UniConf &child); 00481 }; 00482 00483 00484 /** 00485 * An implementation base class for sorted key iterators. 00486 * 00487 * Unfortunately WvSorter is too strongly tied down to lists and pointers 00488 * to be of use here. The main problem is that UniConf::Iter and company 00489 * return pointers to temporary objects whereas WvSorter assumes that the 00490 * pointers will remain valid for the lifetime of the iterator. 00491 */ 00492 class UniConf::SortedIterBase : public UniConf::IterBase 00493 { 00494 public: 00495 typedef int (*Comparator)(const UniConf &a, const UniConf &b); 00496 00497 /** Default comparator. Sorts alphabetically by full key. */ 00498 static int defcomparator(const UniConf &a, const UniConf &b); 00499 00500 SortedIterBase(const UniConf &_top, Comparator comparator = defcomparator); 00501 ~SortedIterBase(); 00502 00503 bool next(); 00504 00505 private: 00506 Comparator xcomparator; 00507 int index; 00508 int count; 00509 00510 void _purge(); 00511 void _rewind(); 00512 00513 static int wrapcomparator(const UniConf **a, const UniConf **b); 00514 static Comparator innercomparator; 00515 00516 protected: 00517 typedef WvVector<UniConf> Vector; 00518 Vector xkeys; 00519 00520 template<class Iter> 00521 void populate(Iter &i) 00522 { 00523 _purge(); 00524 for (i.rewind(); i.next(); ) 00525 xkeys.append(new UniConf(*i)); 00526 _rewind(); 00527 } 00528 }; 00529 00530 00531 /** 00532 * A sorted variant of UniConf::Iter. 00533 */ 00534 class UniConf::SortedIter : public UniConf::SortedIterBase 00535 { 00536 UniConf::Iter i; 00537 00538 public: 00539 SortedIter(const UniConf &_top, Comparator comparator = defcomparator) 00540 : SortedIterBase(_top, comparator), i(_top) 00541 { } 00542 00543 void rewind() 00544 { populate(i); } 00545 }; 00546 00547 00548 /** 00549 * A sorted variant of UniConf::RecursiveIter. 00550 */ 00551 class UniConf::SortedRecursiveIter : public UniConf::SortedIterBase 00552 { 00553 UniConf::RecursiveIter i; 00554 00555 public: 00556 SortedRecursiveIter(const UniConf &_top, 00557 Comparator comparator = defcomparator) 00558 : SortedIterBase(_top, comparator), i(_top) 00559 { } 00560 00561 void rewind() 00562 { populate(i); } 00563 }; 00564 00565 00566 /** 00567 * A sorted variant of UniConf::XIter. 00568 */ 00569 class UniConf::SortedXIter : public UniConf::SortedIterBase 00570 { 00571 UniConf::XIter i; 00572 00573 public: 00574 SortedXIter(const UniConf &_top, const UniConfKey &pattern, 00575 Comparator comparator = defcomparator) 00576 : SortedIterBase(_top, comparator), i(_top, pattern) 00577 { } 00578 00579 void rewind() 00580 { populate(i); } 00581 }; 00582 00583 extern "C" { 00584 #endif /* __cplusplus */ 00585 00586 00587 #ifdef SWIG 00588 %module UniConf 00589 00590 %{ 00591 #include "uniconf.h" 00592 %} 00593 00594 //%newobject uniconf_get; 00595 #endif 00596 00597 /* FIXME: put the C binding here. */ 00598 typedef void* uniconf_t; 00599 00600 00601 /* Initialize and destroy UniConf. */ 00602 uniconf_t uniconf_init(const char* _moniker); 00603 00604 00605 void uniconf_free(uniconf_t _uniconf); 00606 00607 00608 /* The string returned has been allocated with malloc() and should 00609 * thus be free()d. */ 00610 const char* uniconf_get(uniconf_t _uniconf, const char* _key); 00611 00612 00613 void uniconf_set(uniconf_t _uniconf, 00614 const char* _key, const char* _value); 00615 00616 00617 #ifdef __cplusplus 00618 } 00619 #endif 00620 00621 #endif // __UNICONF_H