WvStreams
uniconfroot.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Defines the root management class for UniConf. To create any kind of
6 * UniConf tree, you'll need one of these.
7 */
8#include "uniconfroot.h"
9#include "wvlinkerhack.h"
10
11WV_LINK_TO(UniGenHack);
12
13
15 UniConf(this),
16 watchroot(NULL)
17{
18 mounts.add_callback(this, wv::bind(&UniConfRoot::gen_callback, this,
19 _1, _2));
20}
21
22
23UniConfRoot::UniConfRoot(WvStringParm moniker, bool refresh):
24 UniConf(this),
25 watchroot(NULL)
26{
27 mounts.mount("/", moniker, refresh);
28 mounts.add_callback(this, wv::bind(&UniConfRoot::gen_callback, this,
29 _1, _2));
30}
31
32
34 UniConf(this),
35 watchroot(NULL)
36{
37 mounts.mountgen("/", gen, refresh);
38 mounts.add_callback(this, wv::bind(&UniConfRoot::gen_callback, this,
39 _1, _2));
40}
41
42
43// make sure the given subtree of callback information is empty
44static bool watchout(UniWatchInfoTree *t)
45{
46 bool fail = false;
47
49 for (i.rewind(); i.next(); )
50 {
51 UniWatchInfoTree *w = i.ptr();
52
53 if (w->haschildren())
54 if (watchout(w))
55 fail = true;
56
57 if (!w->watches.isempty())
58 {
59 fail = true;
60 if (1)
61 fprintf(stderr, "Remaining watch: '%s' (%zd)\n",
62 w->fullkey().printable().cstr(), w->watches.count());
63 }
64 }
65
66 return fail;
67}
68
69
71{
72 // first, unmount everything. Some of the mounts might have waiting
73 // callbacks. (I hope not, but... things like UniUnwrapGen might get
74 // confusing.)
75 mounts.zap();
76
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));
82
83 mounts.del_callback(this);
84}
85
86
87void UniConfRoot::add_callback(void *cookie, const UniConfKey &key,
88 const UniConfCallback &callback, bool recurse)
89{
90 UniWatchInfo *w = new UniWatchInfo(cookie, recurse, callback);
91
92 UniWatchInfoTree *node = &watchroot;
93
95 for (i.rewind(); i.next(); )
96 {
97 UniWatchInfoTree *prev = node;
98 node = node->findchild(i());
99 if (!node)
100 node = new UniWatchInfoTree(prev, i());
101 }
102 node->watches.append(w, true);
103}
104
105
106void UniConfRoot::del_callback(void *cookie, const UniConfKey &key,
107 bool recurse)
108{
109 UniWatchInfoTree *node = watchroot.find(key);
110 if (node)
111 {
112 UniWatchInfoList::Iter i(node->watches);
113 for (i.rewind(); i.next(); )
114 {
115 // remove the watch if it matches
116 if (i->cookie == cookie && i->recurse == recurse)
117 {
118 i.xunlink();
119 break;
120 }
121 }
122 // prune the branch if needed
123 prune(node);
124 }
125}
126
127
128void UniConfRoot::add_setbool(const UniConfKey &key, bool *flag, bool recurse)
129{
130 add_callback(flag, key, wv::bind(&UniConfRoot::setbool_callback, flag,
131 _1, _2),
132 recurse);
133}
134
135
136void UniConfRoot::del_setbool(const UniConfKey &key, bool *flag, bool recurse)
137{
138 del_callback(flag, key, recurse);
139}
140
141
142void UniConfRoot::check(UniWatchInfoTree *node,
143 const UniConfKey &key, int segleft)
144{
145 UniWatchInfoList::Iter i(node->watches);
146 for (i.rewind(); i.next(); )
147 {
148 if (!i->recursive() && segleft > 0)
149 continue;
150
151 i->notify(UniConf(this, key.removelast(segleft)), key.last(segleft));
152 }
153}
154
155
156void UniConfRoot::deletioncheck(UniWatchInfoTree *node, const UniConfKey &key)
157{
158 UniWatchInfoTree::Iter i(*node);
159 for (i.rewind(); i.next(); )
160 {
161 UniWatchInfoTree *w = i.ptr();
162 UniConfKey subkey(key, w->key());
163
164 // pretend that we wiped out just this key
165 check(w, subkey, 0);
166 deletioncheck(w, subkey);
167 }
168}
169
170
171void UniConfRoot::prune(UniWatchInfoTree *node)
172{
173 while (node != & watchroot && ! node->isessential())
174 {
175 UniWatchInfoTree *next = node->parent();
176 delete node;
177 node = next;
178 }
179}
180
181
182void UniConfRoot::gen_callback(const UniConfKey &key, WvStringParm value)
183{
184 hold_delta();
185 UniWatchInfoTree *node = & watchroot;
186 int segs = key.numsegments();
187
188 // check root node
189 check(node, key, segs);
190
191 // look for watches on key and its ancestors
192 for (int s = 0; s < segs; )
193 {
194 node = node->findchild(key.segment(s));
195 s++;
196 if (!node)
197 goto done; // no descendents so we can stop
198 check(node, key, segs - s);
199 }
200
201 // look for watches on descendents of key if node was deleted
202 if (value.isnull())
203 deletioncheck(node, key);
204
205done:
206 unhold_delta();
207}
A default implementation of IUniConfGen, providing various handy features that save trouble when impl...
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
WvString printable() const
Returns the canonical string representation of the path.
UniConfKey removelast(int n=1) const
Returns the path formed by removing the last n segments of this path.
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
void add_callback(void *cookie, const UniConfKey &key, const UniConfCallback &callback, bool recurse=true)
Requests notification when any of the keys covered by the recursive depth specification change by inv...
UniConfRoot()
Creates an empty UniConf tree with no mounted stores.
static void setbool_callback(bool *flag, const UniConf &, const UniConfKey &)
Internal callback for setbool style notifications.
void del_callback(void *cookie, const UniConfKey &key, bool recurse=true)
Cancels notification requested using add_callback().
void del_setbool(const UniConfKey &key, bool *flag, bool recurse=true)
Cancels notification requested using add_setbool().
~UniConfRoot()
Destroys the UniConf tree along with all uncommitted data.
void add_setbool(const UniConfKey &key, bool *flag, bool recurse=true)
Requests notification when any of the keys covered by the recursive depth specification change by set...
UniConfKey fullkey(const Sub *ancestor=NULL) const
Returns full path of this node relative to an ancestor.
Sub * parent() const
Returns a pointer to the parent node, or NULL if there is none.
Sub * find(const UniConfKey &key) const
Finds the sub-node with the specified key.
Sub * findchild(const UniConfKey &key) const
Finds the direct child node with the specified key.
UniConfKey key() const
Returns the path of this node relative to its parent.
UniConf()
Creates a NULL UniConf handle, useful for reporting errors.
Definition uniconf.cc:23
bool refresh() const
Refreshes information about this key recursively.
Definition uniconf.cc:119
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition uniconf.cc:199
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition uniconf.cc:193
const UniConfKey & key() const
Returns the key field.
bool haschildren() const
Returns true if the node has children.
bool isessential()
Returns true if the node should not be pruned.
bool isnull() const
returns true if this string is null
const char * cstr() const
return a (const char *) for this string.