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 
16 UniConf::UniConf(UniConfRoot *root, const UniConfKey &fullkey)
17  : xroot(root), xfullkey(fullkey)
18 {
19  // nothing special
20 }
21 
22 
23 UniConf::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 
50 bool UniConf::exists() const
51 {
52  return xroot->mounts.exists(xfullkey);
53 }
54 
55 
57 {
58  return xroot->mounts.haschildren(xfullkey);
59 }
60 
61 
62 void 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 
77 int UniConf::getmeint(int defvalue) const
78 {
79  return xroot->mounts.str2int(getme(), defvalue);
80 }
81 
82 
83 void UniConf::setme(WvStringParm value) const
84 {
85  xroot->mounts.set(xfullkey, value);
86 }
87 
88 
89 void UniConf::setmeint(int value) const
90 {
91  setme(WvString(value));
92 }
93 
94 
95 void UniConf::move(const UniConf &dst) const
96 {
97  dst.remove();
98  copy(dst, true);
99  remove();
100 }
101 
102 
103 void 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 
119 bool UniConf::refresh() const
120 {
121  return xroot->mounts.refresh();
122 }
123 
124 
125 void UniConf::commit() const
126 {
127  xroot->mounts.commit();
128 }
129 
130 
131 IUniConfGen *UniConf::mount(WvStringParm moniker, bool refresh) const
132 {
133  return xroot->mounts.mount(xfullkey, moniker, refresh);
134 }
135 
136 
137 IUniConfGen *UniConf::mountgen(IUniConfGen *gen, bool refresh) const
138 {
139  return xroot->mounts.mountgen(xfullkey, gen, refresh);
140 }
141 
142 
143 void 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 
161 bool UniConf::isok() const
162 {
163  IUniConfGen *gen = whichmount();
164  return gen && gen->isok();
165 }
166 
167 
168 void UniConf::add_callback(void *cookie, const UniConfCallback &callback,
169  bool recurse) const
170 {
171  xroot->add_callback(cookie, xfullkey, callback, recurse);
172 }
173 
174 
175 void UniConf::del_callback(void *cookie, bool recurse) const
176 {
177  xroot->del_callback(cookie, xfullkey, recurse);
178 }
179 
180 
181 void UniConf::add_setbool(bool *flag, bool recurse) const
182 {
183  xroot->add_setbool(xfullkey, flag, recurse);
184 }
185 
186 
187 void 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 
217 void 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 
253 UniConf::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 
273 UniConf::XIter::~XIter()
274 {
275  cleanup();
276 }
277 
278 
279 void 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 
299 void 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 
344 inline 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 
367 void UniConf::XIter::enter(const UniConf &child)
368 {
369  subit = new UniConf::XIter(child, pattail);
370  subit->rewind();
371 }
372 
373 
374 bool 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 
411 UniConf::SortedIterBase::SortedIterBase(const UniConf &root,
412  UniConf::SortedIterBase::Comparator comparator)
413  : IterBase(root), xcomparator(comparator), xkeys()
414 {
415 }
416 
417 
418 UniConf::SortedIterBase::~SortedIterBase()
419 {
420  _purge();
421 }
422 
423 
425  const UniConf &b)
426 {
427  return a.fullkey().compareto(b.fullkey());
428 }
429 
430 
431 static UniConf::SortedIterBase::Comparator innercomparator = NULL;
432 
433 static bool wrapcomparator(const UniConf &a, const UniConf &b)
434 {
435  return innercomparator(a, b) < 0;
436 }
437 
438 
439 void UniConf::SortedIterBase::_purge()
440 {
441  count = xkeys.size();
442  xkeys.clear();
443 }
444 
445 
446 void 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 
457 bool UniConf::SortedIterBase::next()
458 {
459  if (index >= count)
460  return false;
461  current = xkeys[index];
462  index += 1;
463  return true;
464 }