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
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...
Definition: uniconfgen.h:200
virtual void add_callback(void *cookie, const UniConfGenCallback &callback)
Adds a callback for change notification.
Definition: uniconfgen.cc:158
virtual void del_callback(void *cookie)
Removes a callback for change notification.
Definition: uniconfgen.cc:165
An iterator over the segments of a key.
Definition: uniconfkey.h:464
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:39
WvString printable() const
Returns the canonical string representation of the path.
Definition: uniconfkey.cc:212
UniConfKey removelast(int n=1) const
Returns the path formed by removing the last n segments of this path.
Definition: uniconfkey.h:346
int numsegments() const
Returns the number of segments in this path.
Definition: uniconfkey.h:287
UniConfKey segment(int n) const
Returns the specified segment of the path.
Definition: uniconfkey.h:297
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
Definition: uniconfkey.h:324
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...
Definition: uniconfroot.cc:87
UniConfRoot()
Creates an empty UniConf tree with no mounted stores.
Definition: uniconfroot.cc:14
static void setbool_callback(bool *flag, const UniConf &, const UniConfKey &)
Internal callback for setbool style notifications.
Definition: uniconfroot.h:157
void del_callback(void *cookie, const UniConfKey &key, bool recurse=true)
Cancels notification requested using add_callback().
Definition: uniconfroot.cc:106
void del_setbool(const UniConfKey &key, bool *flag, bool recurse=true)
Cancels notification requested using add_setbool().
Definition: uniconfroot.cc:136
~UniConfRoot()
Destroys the UniConf tree along with all uncommitted data.
Definition: uniconfroot.cc:70
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...
Definition: uniconfroot.cc:128
UniConfKey fullkey(const Sub *ancestor=NULL) const
Returns full path of this node relative to an ancestor.
Definition: uniconftree.h:55
Sub * parent() const
Returns a pointer to the parent node, or NULL if there is none.
Definition: uniconftree.h:40
Sub * find(const UniConfKey &key) const
Finds the sub-node with the specified key.
Definition: uniconftree.h:62
Sub * findchild(const UniConfKey &key) const
Finds the direct child node with the specified key.
Definition: uniconftree.h:71
UniConf instances function as handles to subtrees of a UniConf tree and expose a high-level interface...
Definition: uniconf.h:51
UniConfKey key() const
Returns the path of this node relative to its parent.
Definition: uniconf.h:111
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.
Definition: unihashtree.h:40
bool haschildren() const
Returns true if the node has children.
Definition: unihashtree.cc:114
virtual IUniConfGen * mountgen(const UniConfKey &key, IUniConfGen *gen, bool refresh)
Mounts a generator at a key.
Definition: unimountgen.cc:191
virtual IUniConfGen * mount(const UniConfKey &key, WvStringParm moniker, bool refresh)
Mounts a generator at a key using a moniker.
Definition: unimountgen.cc:176
bool isessential()
Returns true if the node should not be pruned.
Definition: uniconfroot.h:58
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
const char * cstr() const
return a (const char *) for this string.
Definition: wvstring.h:267