2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * Defines the root management class for UniConf. To create any kind of
6 * UniConf tree, you'll need one of these.
8 #include "uniconfroot.h"
9 #include "wvlinkerhack.h"
11 WV_LINK_TO(UniGenHack
);
14 UniConfRoot::UniConfRoot():
18 mounts
.add_callback(this, wv::bind(&UniConfRoot::gen_callback
, this,
23 UniConfRoot::UniConfRoot(WvStringParm moniker
, bool refresh
):
27 mounts
.mount("/", moniker
, refresh
);
28 mounts
.add_callback(this, wv::bind(&UniConfRoot::gen_callback
, this,
33 UniConfRoot::UniConfRoot(UniConfGen
*gen
, bool refresh
):
37 mounts
.mountgen("/", gen
, refresh
);
38 mounts
.add_callback(this, wv::bind(&UniConfRoot::gen_callback
, this,
43 // make sure the given subtree of callback information is empty
44 static bool watchout(UniWatchInfoTree
*t
)
48 UniWatchInfoTree::Iter
i(*t
);
49 for (i
.rewind(); i
.next(); )
51 UniWatchInfoTree
*w
= i
.ptr();
57 if (!w
->watches
.isempty())
61 fprintf(stderr
, "Remaining watch: '%s' (%zd)\n",
62 w
->fullkey().printable().cstr(), w
->watches
.count());
70 UniConfRoot::~UniConfRoot()
72 // first, unmount everything. Some of the mounts might have waiting
73 // callbacks. (I hope not, but... things like UniUnwrapGen might get
77 // if the list of callbacks is non-empty, someone is either very buggy
78 // (they disappeared without deleting their callback, so they could cause
79 // crashes), or they're not getting what they expected (we disappeared
80 // before they did, so they won't be getting their callback).
81 assert(!watchout(&watchroot
));
83 mounts
.del_callback(this);
87 void UniConfRoot::add_callback(void *cookie
, const UniConfKey
&key
,
88 const UniConfCallback
&callback
, bool recurse
)
90 UniWatchInfo
*w
= new UniWatchInfo(cookie
, recurse
, callback
);
92 UniWatchInfoTree
*node
= &watchroot
;
94 UniConfKey::Iter
i(key
);
95 for (i
.rewind(); i
.next(); )
97 UniWatchInfoTree
*prev
= node
;
98 node
= node
->findchild(i());
100 node
= new UniWatchInfoTree(prev
, i());
102 node
->watches
.append(w
, true);
106 void UniConfRoot::del_callback(void *cookie
, const UniConfKey
&key
,
109 UniWatchInfoTree
*node
= watchroot
.find(key
);
112 UniWatchInfoList::Iter
i(node
->watches
);
113 for (i
.rewind(); i
.next(); )
115 // remove the watch if it matches
116 if (i
->cookie
== cookie
&& i
->recurse
== recurse
)
122 // prune the branch if needed
128 void UniConfRoot::add_setbool(const UniConfKey
&key
, bool *flag
, bool recurse
)
130 add_callback(flag
, key
, wv::bind(&UniConfRoot::setbool_callback
, flag
,
136 void UniConfRoot::del_setbool(const UniConfKey
&key
, bool *flag
, bool recurse
)
138 del_callback(flag
, key
, recurse
);
142 void UniConfRoot::check(UniWatchInfoTree
*node
,
143 const UniConfKey
&key
, int segleft
)
145 UniWatchInfoList::Iter
i(node
->watches
);
146 for (i
.rewind(); i
.next(); )
148 if (!i
->recursive() && segleft
> 0)
151 i
->notify(UniConf(this, key
.removelast(segleft
)), key
.last(segleft
));
156 void UniConfRoot::deletioncheck(UniWatchInfoTree
*node
, const UniConfKey
&key
)
158 UniWatchInfoTree::Iter
i(*node
);
159 for (i
.rewind(); i
.next(); )
161 UniWatchInfoTree
*w
= i
.ptr();
162 UniConfKey
subkey(key
, w
->key());
164 // pretend that we wiped out just this key
166 deletioncheck(w
, subkey
);
171 void UniConfRoot::prune(UniWatchInfoTree
*node
)
173 while (node
!= & watchroot
&& ! node
->isessential())
175 UniWatchInfoTree
*next
= node
->parent();
182 void UniConfRoot::gen_callback(const UniConfKey
&key
, WvStringParm value
)
185 UniWatchInfoTree
*node
= & watchroot
;
186 int segs
= key
.numsegments();
189 check(node
, key
, segs
);
191 // look for watches on key and its ancestors
192 for (int s
= 0; s
< segs
; )
194 node
= node
->findchild(key
.segment(s
));
197 goto done
; // no descendents so we can stop
198 check(node
, key
, segs
- s
);
201 // look for watches on descendents of key if node was deleted
203 deletioncheck(node
, key
);