00001
00002
00003
00004
00005
00006
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
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
00068
00069
00070 mounts.zap();
00071
00072
00073
00074
00075
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
00111 if (i->cookie == cookie && i->recurse == recurse)
00112 {
00113 i.xunlink();
00114 break;
00115 }
00116 }
00117
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
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
00185 check(node, key, segs);
00186
00187
00188 for (int s = 0; s < segs; )
00189 {
00190 node = node->findchild(key.segment(s));
00191 s++;
00192 if (!node)
00193 goto done;
00194 check(node, key, segs - s);
00195 }
00196
00197
00198 if (value.isnull())
00199 deletioncheck(node, key);
00200
00201 done:
00202 unhold_delta();
00203 }