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