WvStreams
uniconf.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Defines a hierarchical registry abstraction. See uniconf.h.
6 */
7#include "uniconf.h"
8#include "uniconfroot.h"
9#include "uniconfgen.h"
10#include "wvstream.h"
11#include <climits>
12#include <algorithm>
13#include <assert.h>
14
15
17 : xroot(root), xfullkey(fullkey)
18{
19 // nothing special
20}
21
22
23UniConf::UniConf() : xroot(NULL), xfullkey(UniConfKey::EMPTY)
24{
25 // nothing special
26}
27
28
30 : xroot(other.xroot), xfullkey(other.xfullkey)
31{
32 // nothing special
33}
34
35
37{
38 // nothing special
39}
40
41
42
43
45{
46 return k.subkey(xfullkey);
47}
48
49
50bool UniConf::exists() const
51{
52 return xroot->mounts.exists(xfullkey);
53}
54
55
57{
58 return xroot->mounts.haschildren(xfullkey);
59}
60
61
62void UniConf::prefetch(bool recursive) const
63{
64 xroot->mounts.prefetch(xfullkey, recursive);
65}
66
67
69{
70 WvString value = xroot->mounts.get(xfullkey);
71 if (value.isnull())
72 return defvalue;
73 return value;
74}
75
76
77int UniConf::getmeint(int defvalue) const
78{
79 return xroot->mounts.str2int(getme(), defvalue);
80}
81
82
84{
85 xroot->mounts.set(xfullkey, value);
86}
87
88
89void UniConf::setmeint(int value) const
90{
91 setme(WvString(value));
92}
93
94
95void UniConf::move(const UniConf &dst) const
96{
97 dst.remove();
98 copy(dst, true);
99 remove();
100}
101
102
103void UniConf::copy(const UniConf &dst, bool force) const
104{
105 // do the main key first
106 dst.setme(getme());
107
108 // now all the children
109 RecursiveIter i(*this);
110 for (i.rewind(); i.next(); )
111 {
112 UniConf dst2 = dst[i->fullkey(*this)];
113 if (force || dst2.getme().isnull())
114 dst2.setme(i->getme());
115 }
116}
117
118
120{
121 return xroot->mounts.refresh();
122}
123
124
125void UniConf::commit() const
126{
127 xroot->mounts.commit();
128}
129
130
131IUniConfGen *UniConf::mount(WvStringParm moniker, bool refresh) const
132{
133 return xroot->mounts.mount(xfullkey, moniker, refresh);
134}
135
136
137IUniConfGen *UniConf::mountgen(IUniConfGen *gen, bool refresh) const
138{
139 return xroot->mounts.mountgen(xfullkey, gen, refresh);
140}
141
142
143void UniConf::unmount(IUniConfGen *gen, bool commit) const
144{
145 return xroot->mounts.unmount(gen, commit);
146}
147
148
150{
151 return xroot->mounts.ismountpoint(xfullkey);
152}
153
154
156{
157 return xroot->mounts.whichmount(xfullkey, mountpoint);
158}
159
160
161bool UniConf::isok() const
162{
163 IUniConfGen *gen = whichmount();
164 return gen && gen->isok();
165}
166
167
168void UniConf::add_callback(void *cookie, const UniConfCallback &callback,
169 bool recurse) const
170{
171 xroot->add_callback(cookie, xfullkey, callback, recurse);
172}
173
174
175void UniConf::del_callback(void *cookie, bool recurse) const
176{
177 xroot->del_callback(cookie, xfullkey, recurse);
178}
179
180
181void UniConf::add_setbool(bool *flag, bool recurse) const
182{
183 xroot->add_setbool(xfullkey, flag, recurse);
184}
185
186
187void UniConf::del_setbool(bool *flag, bool recurse) const
188{
189 xroot->del_setbool(xfullkey, flag, recurse);
190}
191
192
194{
195 xroot->mounts.hold_delta();
196}
197
198
200{
201 xroot->mounts.unhold_delta();
202}
203
204
206{
207 xroot->mounts.clear_delta();
208}
209
210
212{
213 xroot->mounts.flush_delta();
214}
215
216
217void UniConf::dump(WvStream &stream, bool everything) const
218{
219 UniConf::RecursiveIter it(*this);
220 for (it.rewind(); it.next(); )
221 {
222 WvString value(it->getme());
223 if (everything || !!value)
224 stream.print("%s = %s\n", it->fullkey(), value);
225 }
226}
227
228
229
230/***** UniConf::Iter *****/
231
233 : IterBase(_top)
234{
235 it = _top.rootobj()->mounts.iterator(top.fullkey());
236 if (!it) it = new UniConfGen::NullIter;
237}
238
239
240
241/***** UniConf::RecursiveIter *****/
242
244 : IterBase(_top)
245{
246 it = _top.rootobj()->mounts.recursiveiterator(top.fullkey());
247 if (!it) it = new UniConfGen::NullIter;
248}
249
250
251/***** UniConf::XIter *****/
252
253UniConf::XIter::XIter(const UniConf &_top, const UniConfKey &pattern)
254 : IterBase(_top), pathead(pattern.first()),
255 pattail(pattern.removefirst()), subit(NULL), it(NULL), recit(NULL)
256{
257 if (! pathead.iswild())
258 {
259 // optimization to collect as many consecutive non-wildcard
260 // segments as possible in one go
261 while (! pattail.isempty())
262 {
263 UniConfKey patnext(pattail.first());
264 if (patnext.iswild())
265 break;
266 pathead.append(patnext);
267 pattail = pattail.removefirst();
268 }
269 }
270}
271
272
273UniConf::XIter::~XIter()
274{
275 cleanup();
276}
277
278
279void UniConf::XIter::cleanup()
280{
281 if (subit)
282 {
283 delete subit;
284 subit = NULL;
285 }
286 if (it)
287 {
288 delete it;
289 it = NULL;
290 }
291 if (recit)
292 {
293 delete recit;
294 recit = NULL;
295 }
296}
297
298
299void UniConf::XIter::rewind()
300{
301 cleanup();
302 ready = false;
303
304 if (pathead.isempty())
305 {
306 current = top;
307 ready = current.exists();
308 }
309 else if (pathead == UniConfKey::RECURSIVE_ANY)
310 {
311 recit = new UniConf::RecursiveIter(top);
312 recit->rewind();
313 if (UniConfKey::EMPTY.matches(pattail))
314 {
315 // pattern includes self
316 current = top;
317 ready = current.exists();
318 }
319 }
320 else if (pathead == UniConfKey::ANY)
321 {
322 it = new UniConf::Iter(top);
323 it->rewind();
324 }
325 else
326 {
327 // non-wildcard segment
328 current = top[pathead];
329 if (pattail.isempty())
330 {
331 // don't bother recursing if there are no deeper wildcard
332 // elements (works together with optimization in constructor)
333 ready = current.exists();
334 }
335 else
336 {
337 // more wildcards, setup recursion
338 enter(current);
339 }
340 }
341}
342
343
344inline bool UniConf::XIter::qnext()
345{
346 if (subit) // currently in a sub-iterator
347 {
348 bool found = subit->next();
349 if (found)
350 {
351 current = **subit;
352 return true;
353 }
354 else
355 {
356 // end of this sub-iterator
357 delete subit;
358 subit = NULL;
359 return false;
360 }
361 }
362 else // no sub-iterator at all
363 return false;
364}
365
366
367void UniConf::XIter::enter(const UniConf &child)
368{
369 subit = new UniConf::XIter(child, pattail);
370 subit->rewind();
371}
372
373
374bool UniConf::XIter::next()
375{
376 if (ready)
377 {
378 ready = false;
379 return true;
380 }
381 while (!qnext())
382 {
383 // UniConfKey::ANY
384 if (it && it->next())
385 {
386 /* Not needed for now since we don't match partial keys
387 if (! pathead.matches(it->key()))
388 break;
389 */
390 enter(**it);
391 continue;
392 }
393 // UniConfKey::RECURSIVE_ANY
394 if (recit && recit->next())
395 {
396 enter(**recit);
397 continue;
398 }
399 // anything else or finished
400 return false;
401 }
402
403 // if we get here, qnext() returned true
404 return true;
405}
406
407
408
409/***** UniConf::SortedIterBase *****/
410
411UniConf::SortedIterBase::SortedIterBase(const UniConf &root,
412 UniConf::SortedIterBase::Comparator comparator)
413 : IterBase(root), xcomparator(comparator), xkeys()
414{
415}
416
417
418UniConf::SortedIterBase::~SortedIterBase()
419{
420 _purge();
421}
422
423
425 const UniConf &b)
426{
427 return a.fullkey().compareto(b.fullkey());
428}
429
430
431static UniConf::SortedIterBase::Comparator innercomparator = NULL;
432
433static bool wrapcomparator(const UniConf &a, const UniConf &b)
434{
435 return innercomparator(a, b) < 0;
436}
437
438
439void UniConf::SortedIterBase::_purge()
440{
441 count = xkeys.size();
442 xkeys.clear();
443}
444
445
446void UniConf::SortedIterBase::_rewind()
447{
448 index = 0;
449 count = xkeys.size();
450
451 // This code is NOT reentrant because qsort makes it too hard
452 innercomparator = xcomparator;
453 std::sort(xkeys.begin(), xkeys.end(), wrapcomparator);
454}
455
456
457bool UniConf::SortedIterBase::next()
458{
459 if (index >= count)
460 return false;
461 current = xkeys[index];
462 index += 1;
463 return true;
464}
An abstract data container that backs a UniConf tree.
virtual bool isok()=0
Determines if the generator is usable and working properly.
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
UniConfKey subkey(const UniConfKey &key) const
If this UniConfKey is a subkey of 'key', then return the subkey portion.
UniConfKey removefirst(int n=1) const
Returns the path formed by removing the first n segments of this path.
int compareto(const UniConfKey &other) const
Compares two paths lexicographically.
bool iswild() const
Returns true if the key contains a wildcard.
void append(const UniConfKey &other)
Appends a path to this path.
bool isempty() const
Returns true if this path has zero segments (also known as root).
UniConfKey first(int n=1) const
Returns the path formed by the n first segments of this path.
Represents the root of a hierarhical registry consisting of pairs of UniConfKeys and associated strin...
An implementation base class for key iterators.
This iterator walks through all immediate children of a UniConf node.
Iter(const UniConf &_top)
Creates an iterator over the direct children of a branch.
Definition uniconf.cc:232
This iterator performs depth-first traversal of a subtree.
RecursiveIter(const UniConf &_top)
Creates a recursive iterator over a branch.
Definition uniconf.cc:243
static int defcomparator(const UniConf &a, const UniConf &b)
Default comparator.
Definition uniconf.cc:424
This iterator walks over all children that match a wildcard pattern.
XIter(const UniConf &_top, const UniConfKey &pattern)
Creates a wildcard iterator.
Definition uniconf.cc:253
UniConf instances function as handles to subtrees of a UniConf tree and expose a high-level interface...
void commit() const
Commits information about this key recursively.
Definition uniconf.cc:125
void add_callback(void *cookie, const UniConfCallback &callback, bool recurse=true) const
Requests notification when any of the keys covered by the recursive depth specification change by inv...
Definition uniconf.cc:168
void remove() const
Removes this key and all of its children from the registry.
void prefetch(bool recursive) const
See UniConfGen::prefetch().
Definition uniconf.cc:62
UniConf root() const
Returns a handle to the root of the tree.
void clear_delta()
Clears the list of pending notifications without sending them.
Definition uniconf.cc:205
void move(const UniConf &dst) const
Equivalent to "mv" in a standard unix filesystem.
Definition uniconf.cc:95
int getmeint(int defvalue=0) const
Fetches the integer value for this key from the registry.
Definition uniconf.cc:77
bool haschildren() const
Returns true if this key has children.
Definition uniconf.cc:56
void setme(WvStringParm value) const
Stores a string value for this key into the registry.
Definition uniconf.cc:83
bool exists() const
Without fetching its value, returns true if this key exists.
Definition uniconf.cc:50
void unmount(IUniConfGen *gen, bool commit) const
Unmounts the generator providing this key and destroys it.
Definition uniconf.cc:143
UniConf()
Creates a NULL UniConf handle, useful for reporting errors.
Definition uniconf.cc:23
void add_setbool(bool *flag, bool recurse=true) const
Requests notification when any of the keys covered by the recursive depth specification change by set...
Definition uniconf.cc:181
void del_setbool(bool *flag, bool recurse=true) const
Cancels notification requested using add_setbool().
Definition uniconf.cc:187
bool refresh() const
Refreshes information about this key recursively.
Definition uniconf.cc:119
IUniConfGen * mount(WvStringParm moniker, bool refresh=true) const
Mounts a generator at this key using a moniker.
Definition uniconf.cc:131
IUniConfGen * whichmount(UniConfKey *mountpoint=NULL) const
Finds the generator that owns this key.
Definition uniconf.cc:155
UniConfKey fullkey() const
Returns the full path of this node, starting at the root.
void flush_delta()
Flushes the list of pending notifications by sending them.
Definition uniconf.cc:211
void del_callback(void *cookie, bool recurse=true) const
Cancels notification requested using add_callback().
Definition uniconf.cc:175
UniConfRoot * rootobj() const
Returns a pointer to the UniConfRoot that manages this node.
void copy(const UniConf &dst, bool force) const
Equivalent to "cp -r" in a standard unix filesystem.
Definition uniconf.cc:103
bool isok() const
Returns true if the generator at this key isok().
Definition uniconf.cc:161
void dump(WvStream &stream, bool everything=false) const
Prints the entire contents of this subtree to a stream.
Definition uniconf.cc:217
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition uniconf.cc:199
void setmeint(int value) const
Stores an integer value for this key into the registry.
Definition uniconf.cc:89
virtual ~UniConf()
Destroys the UniConf handle.
Definition uniconf.cc:36
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition uniconf.cc:193
bool ismountpoint() const
Determines if any generators are mounted at this key.
Definition uniconf.cc:149
WvString getme(WvStringParm defvalue=WvString::null) const
Fetches the string value for this key from the registry.
Definition uniconf.cc:68
IUniConfGen * mountgen(IUniConfGen *gen, bool refresh=true) const
Mounts a generator at this key.
Definition uniconf.cc:137
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
bool isnull() const
returns true if this string is null
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
WvString is an implementation of a simple and efficient printable-string class.