00001
00002
00003
00004
00005
00006
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
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' (%zd)\n",
00062 w->fullkey().printable().cstr(), w->watches.count());
00063 }
00064 }
00065
00066 return fail;
00067 }
00068
00069
00070 UniConfRoot::~UniConfRoot()
00071 {
00072
00073
00074
00075 mounts.zap();
00076
00077
00078
00079
00080
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
00116 if (i->cookie == cookie && i->recurse == recurse)
00117 {
00118 i.xunlink();
00119 break;
00120 }
00121 }
00122
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
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
00189 check(node, key, segs);
00190
00191
00192 for (int s = 0; s < segs; )
00193 {
00194 node = node->findchild(key.segment(s));
00195 s++;
00196 if (!node)
00197 goto done;
00198 check(node, key, segs - s);
00199 }
00200
00201
00202 if (value.isnull())
00203 deletioncheck(node, key);
00204
00205 done:
00206 unhold_delta();
00207 }