uniconfroot.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * Defines the root management class for UniConf.  To create any kind of
00006  * UniConf tree, you'll need one of these.
00007  */
00008 #include "uniconfroot.h"
00009 #include "wvlinkerhack.h"
00010 
00011 WV_LINK_TO(UniGenHack);
00012 
00013 UniConfRoot::UniConfRoot() : UniConf(this), watchroot(NULL)
00014 {
00015     mounts.add_callback(this, UniConfGenCallback(this,
00016                           &UniConfRoot::gen_callback));
00017 }
00018 
00019 
00020 UniConfRoot::UniConfRoot(WvStringParm moniker, bool refresh)
00021     : UniConf(this), watchroot(NULL)
00022 {
00023     mounts.mount("/", moniker, refresh);
00024     mounts.add_callback(this, UniConfGenCallback(this,
00025                           &UniConfRoot::gen_callback));
00026 }
00027 
00028 
00029 UniConfRoot::UniConfRoot(UniConfGen *gen, bool refresh)
00030     : UniConf(this), watchroot(NULL)
00031 {
00032     mounts.mountgen("/", gen, refresh);
00033     mounts.add_callback(this, UniConfGenCallback(this,
00034                           &UniConfRoot::gen_callback));
00035 }
00036 
00037 
00038 // make sure the given subtree of callback information is empty
00039 static bool watchout(UniWatchInfoTree *t)
00040 {
00041     bool fail = false;
00042     
00043     UniWatchInfoTree::Iter i(*t);
00044     for (i.rewind(); i.next(); )
00045     {
00046         UniWatchInfoTree *w = i.ptr();
00047         
00048         if (w->haschildren())
00049             if (watchout(w))
00050                 fail = true;
00051         
00052         if (!w->watches.isempty())
00053         {
00054             fail = true;
00055             if (1)
00056                 fprintf(stderr, "Remaining watch: '%s' (%d)\n",
00057                         w->fullkey().printable().cstr(), w->watches.count());
00058         }
00059     }
00060     
00061     return fail;
00062 }
00063 
00064 
00065 UniConfRoot::~UniConfRoot()
00066 {
00067     // first, unmount everything.  Some of the mounts might have waiting
00068     // callbacks.  (I hope not, but... things like UniUnwrapGen might get
00069     // confusing.)
00070     mounts.zap();
00071     
00072     // if the list of callbacks is non-empty, someone is either very buggy
00073     // (they disappeared without deleting their callback, so they could cause
00074     // crashes), or they're not getting what they expected (we disappeared
00075     // before they did, so they won't be getting their callback).
00076     assert(!watchout(&watchroot));
00077     
00078     mounts.del_callback(this);
00079 }
00080 
00081 
00082 void UniConfRoot::add_callback(void *cookie, const UniConfKey &key,
00083                                const UniConfCallback &callback, bool recurse)
00084 {
00085     UniWatchInfo *w = new UniWatchInfo(cookie, recurse, callback);
00086 
00087     UniWatchInfoTree *node = &watchroot;
00088     
00089     UniConfKey::Iter i(key);
00090     for (i.rewind(); i.next(); )
00091     {
00092         UniWatchInfoTree *prev = node;
00093         node = node->findchild(i());
00094         if (!node)
00095             node = new UniWatchInfoTree(prev, i());
00096     }
00097     node->watches.append(w, true);
00098 }
00099 
00100 
00101 void UniConfRoot::del_callback(void *cookie, const UniConfKey &key,
00102                                bool recurse)
00103 {
00104     UniWatchInfoTree *node = watchroot.find(key);
00105     if (node)
00106     {
00107         UniWatchInfoList::Iter i(node->watches);
00108         for (i.rewind(); i.next(); )
00109         {
00110             // remove the watch if it matches
00111             if (i->cookie == cookie && i->recurse == recurse)
00112             {
00113                 i.xunlink();
00114                 break;
00115             }
00116         }
00117         // prune the branch if needed
00118         prune(node);
00119     }
00120 }
00121 
00122 
00123 void UniConfRoot::add_setbool(const UniConfKey &key, bool *flag, bool recurse)
00124 {
00125     add_callback(flag, key,
00126                  WvBoundCallback<UniConfCallback, bool *>
00127                     (&UniConfRoot::setbool_callback, flag),
00128                  recurse);
00129 }
00130 
00131 
00132 void UniConfRoot::del_setbool(const UniConfKey &key, bool *flag, bool recurse)
00133 {
00134     del_callback(flag, key, recurse);
00135 }
00136 
00137 
00138 void UniConfRoot::check(UniWatchInfoTree *node,
00139                         const UniConfKey &key, int segleft)
00140 {
00141     UniWatchInfoList::Iter i(node->watches);
00142     for (i.rewind(); i.next(); )
00143     {
00144         if (!i->recursive() && segleft > 0)
00145             continue;
00146 
00147         i->notify(UniConf(this, key.removelast(segleft)), key.last(segleft));
00148     }
00149 }
00150 
00151 
00152 void UniConfRoot::deletioncheck(UniWatchInfoTree *node, const UniConfKey &key)
00153 {
00154     UniWatchInfoTree::Iter i(*node);
00155     for (i.rewind(); i.next(); )
00156     {
00157         UniWatchInfoTree *w = i.ptr();
00158         UniConfKey subkey(key, w->key());
00159         
00160         // pretend that we wiped out just this key
00161         check(w, subkey, 0);
00162         deletioncheck(w, subkey);
00163     }
00164 }
00165 
00166 
00167 void UniConfRoot::prune(UniWatchInfoTree *node)
00168 {
00169     while (node != & watchroot && ! node->isessential())
00170     {
00171         UniWatchInfoTree *next = node->parent();
00172         delete node;
00173         node = next;
00174     }
00175 }
00176 
00177 
00178 void UniConfRoot::gen_callback(const UniConfKey &key, WvStringParm value)
00179 {
00180     hold_delta();
00181     UniWatchInfoTree *node = & watchroot;
00182     int segs = key.numsegments();
00183 
00184     // check root node
00185     check(node, key, segs);
00186 
00187     // look for watches on key and its ancestors
00188     for (int s = 0; s < segs; )
00189     {
00190         node = node->findchild(key.segment(s));
00191         s++;
00192         if (!node)
00193             goto done; // no descendents so we can stop
00194         check(node, key, segs - s);
00195     }
00196 
00197     // look for watches on descendents of key if node was deleted
00198     if (value.isnull())
00199         deletioncheck(node, key);
00200     
00201 done:
00202     unhold_delta();
00203 }

Generated on Mon Feb 5 10:54:28 2007 for WvStreams by  doxygen 1.5.1