WvStreams
unitransactiongen.cc
1 #include "unitransactiongen.h"
2 #include "uniconftree.h"
3 #include "unilistiter.h"
4 #include "wvmoniker.h"
5 
6 static IUniConfGen *creator(WvStringParm s, IObject *_obj)
7 {
8  IUniConfGen *base = wvcreate<IUniConfGen>(s, _obj);
9  if (base)
10  return new UniTransactionGen(base);
11  else
12  return NULL;
13 }
14 
15 static WvMoniker<IUniConfGen> moniker("transaction", creator);
16 
17 /* This enum is a field of UniConfChangeTree. It indicates the type of
18  change represented by a node in a UniConfChangeTree. */
19 enum changeMode
20 {
21  /* This indicates that "newvalue" is valid and that
22  its value should be written to the underlying generator at commit
23  time. This tree *might* have children, which must be applied.
24  "newvalue" will be a non-null pointer to a non-null WvString. */
25  NEWVALUE,
26  /* This indicates that "newtree" is valid (but possibly NULL) and that
27  the underlying generator's corresponding subtree should be made
28  identical at commit time. This tree will *not* have children (though
29  newtree might). */
30  NEWTREE,
31  /* This indicates that "was_null_or_empty" is valid and that the key
32  in the underlying generator should be created at commit time if it
33  does not already exist at commit time. This tree *will* have
34  children, which must be applied, and at least one of which will
35  be non-BLANK. "was_null_or_empty" will be the return value of the
36  WvString negation operation on the last known value of the
37  corresponding key in the underlying generator; it is necessary
38  in order to filter callbacks in certain cases. */
39  NEWNODE,
40  /* This indicates that none of the fields are valid and that
41  nothing should be done for this tree. This tree *will* have children,
42  which must be applied, but they will all have mode of NEWTREE with
43  newtree == NULL. */
44  BLANK
45 };
46 
47 class UniConfChangeTree : public UniConfTree<UniConfChangeTree>
48 {
49 public:
50  changeMode mode;
51 
52  // This used to be a union, but it was causing memory errors that were
53  // extremely difficult to track down. Some of this code might serve no
54  // purpose without this being a union, but I'd rather have it still work
55  // and not leak than break it. -- mrwise
56  WvString newvalue;
57  UniConfValueTree *newtree;
58  bool was_null_or_empty;
59 
60  // Constructs a tree and links it to a parent.
62  : UniConfTree<UniConfChangeTree>(parent, key), newtree(0) {}
63 
64  // Destroys a tree and everything it owns.
66  {
67  if (newtree)
68  delete newtree;
69  }
70 };
71 
72 // Constructed by UniTransactionGen::iterator() to iterate over a section that
73 // is to be completely replaced by a particular UniConfValueTree.
75 {
76 public:
78  : i(*node)
79  {
80  // printf("GenStyleValueTreeIter\n");
81  }
82 
84  {
85  // printf("~GenStyleValueTreeIter\n");
86  }
87 
88  void rewind() { i.rewind(); }
89  bool next() { return i.next(); }
90  UniConfKey key() const { return i->key(); }
91  WvString value() const { return i->value(); }
92 
93 private:
95 };
96 
97 // Constructed by UniTransactionGen::iterator() to iterate over a section that
98 // is being modified but not replaced. We iterate first over all of the values
99 // that we're changing, except those we're deleting, and second over all
100 // existing values not iterated over in the first stage, except those we're
101 // deleting.
103 {
104 public:
106  const UniConfKey &_section,
107  IUniConfGen *_base)
108  : root(_root), section(_section), base(_base),
109  doing_i1(true), i1(*root), i2(base->iterator(section))
110  {
111  // printf("GenStyleChangeTreeIter(%s)\n", WvString(section).cstr());
112  }
113 
115  {
116  // printf("~GenStyleChangeTreeIter(%s)\n", WvString(section).cstr());
117  if (i2) delete i2;
118  }
119 
120  void rewind()
121  {
122  i1.rewind();
123  doing_i1 = true;
124  }
125 
126  bool next()
127  {
128  if (doing_i1)
129  {
130  for (;;)
131  {
132  if (i1.next())
133  {
134  if (i1->mode == NEWVALUE ||
135  i1->mode == NEWNODE ||
136  (i1->mode == NEWTREE && i1->newtree))
137  return true;
138  }
139  else
140  break;
141  }
142  doing_i1 = false;
143  if (i2) i2->rewind();
144  }
145  if (i2)
146  {
147  for (;;)
148  {
149  if (i2->next())
150  {
151  UniConfChangeTree *node = root->findchild(i2->key());
152  if (!node || node->mode == BLANK)
153  return true;
154  }
155  else
156  break;
157  }
158  }
159  return false;
160  }
161 
162  UniConfKey key() const
163  {
164  if (doing_i1)
165  return i1->key();
166  else if (i2)
167  return i2->key();
168  else
169  return UniConfKey();
170  }
171 
172  WvString value() const
173  {
174  if (doing_i1)
175  {
176  if (i1->mode == NEWVALUE)
177  return i1->newvalue;
178  else if (i1->mode == NEWTREE)
179  return i1->newtree->value();
180  else // i.e. i1->mode == NEWNODE
181  {
182  WvString value(base->get(UniConfKey(section, i1->key())));
183  return !value ? WvString::empty : value;
184  }
185  }
186  else
187  {
188  return i2->value();
189  }
190  }
191 
192 private:
193  UniConfChangeTree *root;
194  UniConfKey section;
195  IUniConfGen *base;
196 
197  bool doing_i1;
199  UniConfGen::Iter *i2;
200 };
201 
203  : root(NULL), base(_base)
204 {
205  base->add_callback(this, wv::bind(&UniTransactionGen::gencallback, this,
206  _1, _2));
207 }
208 
210 {
211  base->del_callback(this);
212  WVRELEASE(base);
213  WVDELETE(root);
214 }
215 
217 {
218  UniConfChangeTree *node = root;
219  for (int seg = 0;; node = node->findchild(key.segment(seg++)))
220  {
221  if (!node)
222  // If we couldn't find the next node, then we aren't
223  // changing the requested key, and so the value is whatever
224  // it currently is.
225  return base->get(key);
226  else if (node->mode == NEWTREE)
227  {
228  // Else if the next node has mode of NEWTREE, then we're changing
229  // the requested key to whatever its value is in the stored
230  // tree.
231  if (node->newtree)
232  {
233  UniConfValueTree *subnode = node->newtree->find(
234  key.last(key.numsegments() - seg));
235  if (subnode)
236  return subnode->value();
237  }
238  return WvString::null;
239  }
240  else if (seg == key.numsegments())
241  {
242  // Else if this is the last node, then figure out what the node
243  // would do and return the appropriate value. (The node's mode
244  // will be either NEWVALUE, NEWNODE, or BLANK.)
245  if (node->mode == NEWVALUE)
246  return node->newvalue;
247  WvString value(base->get(key.first(seg)));
248  return (node->mode == NEWNODE && !value) ? WvString::empty : value;
249  }
250  }
251 }
252 
254 {
255  hold_delta();
256  root = set_change(root, key, 0, value);
257  unhold_delta();
258 }
259 
260 void UniTransactionGen::setv(const UniConfPairList &pairs)
261 {
262  hold_delta();
263  UniConfPairList::Iter i(pairs);
264  for (i.rewind(); i.next(); )
265  root = set_change(root, i->key(), 0, i->value());
266  unhold_delta();
267 }
268 
270 {
271  if (root)
272  {
273  // Apply our changes to the inner generator. We can't optimise
274  // away callbacks at this point, because we may get notified of
275  // changes caused by our changes.
276  hold_delta();
277  apply_changes(root, UniConfKey());
278 
279  // make sure the inner generator also commits
280  base->commit();
281 
282  // save deleting the root till now so we can hide any
283  // redundant notifications caused by the base->commit()
284  delete root;
285  root = NULL;
286  unhold_delta();
287  }
288 
289  // no need to base->commit() if we know we haven't changed anything!
290 }
291 
293 {
294  if (root)
295  {
296  hold_delta();
297  cancel_changes(root, UniConfKey());
298  delete root;
299  root = NULL;
300  unhold_delta();
301 
302  // no need to base->commit() here, since the inner generator never
303  // saw any changes
304  }
305 
306  // must always base->refresh(), even if we didn't change anything
307  return base->refresh();
308 }
309 
311 {
312  UniConfChangeTree *node = root;
313  for (int seg = 0;; node = node->findchild(key.segment(seg++)))
314  {
315  if (!node)
316  // If we couldn't find the next node, then we aren't changing the
317  // children of the requested key, so they're whatever they
318  // currently are.
319  return base->iterator(key);
320  else if (node->mode == NEWTREE)
321  {
322  // Else if the next node has mode of NEWTREE, then we're changing
323  // the children of the requested key to whatever they are in the
324  // stored tree.
325  if (node->newtree)
326  {
327  UniConfValueTree *subnode = node->newtree->find(
328  key.last(key.numsegments() - seg));
329  if (subnode)
330  {
331  UniConfGen::Iter *i = new GenStyleValueTreeIter(subnode);
332  UniListIter *i2 = new UniListIter(this);
333  i2->autofill(i);
334  delete i;
335  return i2;
336  }
337  }
338  return new UniConfGen::NullIter();
339  }
340  else if (seg == key.numsegments())
341  {
342  // Else if this is the last node, then iterate over its direct
343  // children.
344  UniConfGen::Iter *i = new GenStyleChangeTreeIter(node, key, base);
345  UniListIter *i2 = new UniListIter(this);
346  i2->autofill(i);
347  delete i;
348  return i2;
349  }
350  }
351 }
352 
354  const UniConfKey &section)
355 {
356  base->set(section, newcontents->value());
357 
358  UniConfGen::Iter *j = base->iterator(section);
359  if (j)
360  {
361  for (j->rewind(); j->next();)
362  {
363  if (newcontents->findchild(j->key()) == NULL)
364  // Delete all children of the current value in the
365  // underlying generator that do not exist in our
366  // replacement tree.
367  base->set(UniConfKey(section, j->key()), WvString::null);
368  }
369  delete j;
370  }
371 
372  // Repeat for each child in the replacement tree.
373  UniConfValueTree::Iter i(*newcontents);
374  for (i.rewind(); i.next();)
375  apply_values(i.ptr(), UniConfKey(section, i->key()));
376 }
377 
379  const UniConfKey &section)
380 {
381  if (node->mode == NEWTREE)
382  {
383  // If the current change is a NEWTREE change, then replace the
384  // tree in the underlying generator with the stored one.
385  if (node->newtree == NULL)
386  base->set(section, WvString::null);
387  else
388  apply_values(node->newtree, section);
389  // Since such changes have no children, return immediately.
390  return;
391  }
392  else if (node->mode == NEWVALUE)
393  {
394  // Else if the current change is a NEWVALUE change, ...
395  base->set(section, node->newvalue);
396  }
397  else if (node->mode == NEWNODE)
398  {
399  // Else if the current change is a NEWNODE change, ...
400  if (!base->exists(section))
401  // ... and the current value in the underlying generator doesn't
402  // exist, then create it.
403  base->set(section, WvString::empty);
404  // Note: This *is* necessary. We can't ignore this change and have
405  // the underlying generator handle it, because it's possible that
406  // this NEWNODE was the result of a set() which was later deleted.
407  }
408 
409  // Repeat for each child in the change tree.
410  UniConfChangeTree::Iter i(*node);
411  for (i.rewind(); i.next();)
412  apply_changes(i.ptr(), UniConfKey(section, i->key()));
413 }
414 
416 {
417  UniConfValueTree *node;
418  const UniConfKey &key;
419 };
420 
422  void *userdata)
423 {
424  my_userdata *data = (my_userdata *)userdata;
425  delta(UniConfKey(data->key, node->fullkey(data->node)), WvString::null);
426 }
427 
428 // Mirror image of apply_values() that issues all of the callbacks associated
429 // with discarding a replacement value tree.
431  const UniConfKey &section)
432 {
433  WvString value(base->get(section));
434  if (!newcontents || newcontents->value() != value)
435  delta(section, value);
436 
437  if (newcontents)
438  {
439  UniConfValueTree::Iter i(*newcontents);
440  for (i.rewind(); i.next();)
441  {
442  UniConfKey subkey(section, i->key());
443  if (!base->exists(subkey))
444  {
445  my_userdata data = { i.ptr(), subkey };
446  i->visit(wv::bind(&UniTransactionGen::deletion_visitor, this,
447  _1, _2),
448  (void*)&data, false, true);
449  }
450  }
451  }
452 
453  UniConfGen::Iter *i = base->iterator(section);
454  if (i)
455  {
456  for (i->rewind(); i->next();)
457  cancel_values(newcontents ?
458  newcontents->findchild(i->key()) : NULL,
459  UniConfKey(section, i->key()));
460  delete i;
461  }
462 }
463 
464 // Mirror image of apply_changes() that issues all of the callbacks associated
465 // with discarding a change tree.
467  const UniConfKey &section)
468 {
469  if (node->mode == NEWTREE)
470  {
471  if (!base->exists(section))
472  {
473  if (node->newtree != NULL)
474  {
475  my_userdata data = { node->newtree, section };
476  node->newtree->visit(
477  wv::bind(&UniTransactionGen::deletion_visitor, this,
478  _1, _2),
479  (void *)&data, false, true);
480  }
481  }
482  else
483  cancel_values(node->newtree, section);
484  return;
485  }
486 
487  WvString value;
488  if (node->mode != BLANK)
489  value = base->get(section);
490 
491  if (node->mode == NEWVALUE &&
492  !value.isnull() &&
493  value != node->newvalue)
494  delta(section, value);
495 
496  UniConfChangeTree::Iter i(*node);
497  for (i.rewind(); i.next();)
498  cancel_changes(i.ptr(), UniConfKey(section, i->key()));
499 
500  if (node->mode != BLANK && value.isnull())
501  delta(section, WvString::null);
502 }
503 
505  WvStringParm value)
506 {
507  UniConfChangeTree *node = root;
508  for (int seg = 0;; node = node->findchild(key.segment(seg++)))
509  {
510  if (!node)
511  // If we couldn't find the next node, then we aren't changing
512  // the changed key or any of its children, and so a callback
513  // should be made.
514  break;
515  else if (node->mode == NEWTREE)
516  // Else if the next node has mode of NEWTREE, then we're changing
517  // the changed key and all of its children to whatever their
518  // values are in the stored tree, and so the callback should be
519  // ignored.
520  return;
521  else if (seg == key.numsegments())
522  {
523  // Else if this is the last node, then figure out what we
524  // should do.
525  if (node->mode == NEWVALUE)
526  // If we're replacing this key's value, then we should
527  // ignore the callback.
528  return;
529  else if (node->mode == NEWNODE)
530  {
531  // Else if we want to create this key, then use its
532  // was_null_or_empty flag to figure out if we need
533  // to issue a callback, and update it if necessary.
534  if (node->was_null_or_empty && !value)
535  return;
536  node->was_null_or_empty = !value;
537  if (value.isnull())
538  {
539  delta(key, WvString::empty);
540  return;
541  }
542  break;
543  }
544  else // i.e. node->mode == BLANK
545  // Else if we're doing nothing to this key, then a
546  // callback should be made.
547  break;
548  }
549  }
550 
551  // Make a normal callback.
552  delta(key, value);
553 }
554 
555 // Create and return a UniConfValueTree containing the value 'value' for
556 // the key given by the segments of 'key' at and after position 'seg', with
557 // parent 'parent' and key given by the segment of 'key' at position seg-1
558 // (which is the "root" key if seg == 0). Issue callbacks as necessary using
559 // all the segments of 'key'.
561  const UniConfKey &key,
562  int seg,
563  WvStringParm value)
564 {
565  UniConfValueTree *tree = 0;
566  for (; seg != key.numsegments();)
567  {
568  // Create any needed intermediate nodes, each with value equal to
569  // the empty string.
570  parent = new UniConfValueTree(parent,
571  key.segment(seg-1),
572  WvString::empty);
573  delta(key.first(seg++), WvString::empty);
574  if (!tree)
575  tree = parent;
576  }
577  // Create the last node with the specified value.
578  parent = new UniConfValueTree(parent,
579  key.segment(seg-1),
580  value);
581  delta(key, value);
582  if (!tree)
583  tree = parent;
584  return tree;
585 }
586 
588 {
589  UniConfGen::Iter *i = base->iterator(key);
590  if (i)
591  {
592  for (i->rewind(); i->next();)
593  deletion_simulator(UniConfKey(key, i->key()));
594  delete i;
595  }
596  delta(key, WvString::null);
597 }
598 
599 // Like create_value(), but make a UniConfChangeTree containing a *change*
600 // to value 'value'.
601 UniConfChangeTree *UniTransactionGen::create_change(UniConfChangeTree *parent,
602  const UniConfKey &key,
603  int seg,
604  WvStringParm value)
605 {
606  // if the key has a trailing slash, this should be a no-op: we don't
607  // want this to have any effect
608  if ((key.hastrailingslash()) && !value.isnull())
609  return parent;
610 
611  UniConfChangeTree *tree = 0;
612  for (; seg != key.numsegments(); seg++)
613  {
614  parent = new UniConfChangeTree(parent, key.segment(seg-1));
615  if (value.isnull())
616  // We don't do anything for intermediate nodes when deleting, ...
617  parent->mode = BLANK;
618  else
619  {
620  // ... but when set()'ing a non-null value, we want them to exist.
621  parent->mode = NEWNODE;
622  UniConfKey nodekey(key.first(seg));
623  WvString curr = base->get(nodekey);
624  parent->was_null_or_empty = !curr;
625  if (curr.isnull())
626  delta(nodekey, WvString::empty);
627  }
628  if (!tree)
629  tree = parent;
630  }
631  parent = new UniConfChangeTree(parent, key.segment(seg-1));
632  // Create the last node with the specified change.
633  if (value.isnull())
634  {
635  parent->mode = NEWTREE;
636  parent->newtree = 0;
637  if (base->exists(key))
638  deletion_simulator(key);
639  }
640  else
641  {
642  parent->mode = NEWVALUE;
643  parent->newvalue = WvString(value);
644  if (base->get(key) != value)
645  delta(key, value);
646  }
647  if (!tree)
648  tree = parent;
649  return tree;
650 }
651 
652 // Modify an existing UniConfValueTree to incorporate the set() of a
653 // particular value for a particular key. Return a possibly altered
654 // pointer to the root of the tree. 'seg' and 'key' are used like they
655 // are in create_value(), and callbacks are made similarly.
656 UniConfValueTree *UniTransactionGen::set_value(UniConfValueTree *node,
657  const UniConfKey &key,
658  int seg,
659  WvStringParm value)
660 {
661  // printf("set_value('%s', %d)\n", WvString(key).cstr(), value.isnull());
662  if (value.isnull())
663  {
664  // Delete the key if it exists.
665  if (node)
666  {
667  UniConfValueTree *subnode = node->find(
668  key.last(key.numsegments() - seg));
669  if (subnode)
670  {
671  hold_delta();
672  my_userdata data = { subnode, key };
673  subnode->visit(wv::bind(&UniTransactionGen::deletion_visitor,
674  this, _1, _2),
675  (void *)&data, false, true);
676  // printf("DELETE SUBNODE!\n");
677  delete subnode;
678  unhold_delta();
679  return subnode == node ? NULL : node;
680  }
681  else
682  return node;
683  }
684  else
685  return NULL;
686  }
687  else
688  {
689  // Switch to create_value() if we ever can't find the next node.
690  if (!node)
691  return create_value(NULL, key, seg, value);
692 
693  UniConfValueTree *subnode = node;
694  for (; seg != key.numsegments();)
695  {
696  UniConfKey segment(key.segment(seg++));
697  UniConfValueTree *child = subnode->findchild(segment);
698  // Switch to create_value() if we ever can't find the next node.
699  if (!child)
700  {
701  create_value(subnode, key, seg, value);
702  return node;
703  }
704  else
705  subnode = child;
706  }
707  // The node already existed and we've found it; set it.
708  if (value != subnode->value())
709  {
710  subnode->setvalue(value);
711  delta(key, value);
712  }
713  return node;
714  }
715 }
716 
718 {
719  UniConfGen::Iter *i = this->iterator(key);
720  if (i)
721  {
722  for (i->rewind(); i->next();)
723  deletion_simulator2(UniConfKey(key, i->key()));
724  delete i;
725  }
726  delta(key, WvString::null);
727 }
728 
729 // Like set_value(), but, again, for UniConfChangeTrees instead.
730 UniConfChangeTree *UniTransactionGen::set_change(UniConfChangeTree *node,
731  const UniConfKey &key,
732  int seg,
733  WvStringParm value)
734 {
735  // printf("set_change(key=%s,mode=%d) = '%s'\n",
736  // WvString(key).cstr(), node ? node->mode : 999, value.cstr());
737 
738  // Switch to create_change() if we ever can't find the next node,
739  // and switch to set_value() if we ever find a NEWTREE.
740  if (!node)
741  return create_change(NULL, key, seg, value);
742  else if (node->mode == NEWTREE)
743  {
744  node->newtree = set_value(node->newtree, key, seg, value);
745  return node;
746  }
747 
748  UniConfChangeTree *subnode = node;
749  for (; seg != key.numsegments();)
750  {
751  if (subnode->mode == BLANK && !value.isnull())
752  {
753  // If we're setting a non-null value and we weren't previously
754  // doing anything to this node, then now we want to create it.
755  subnode->mode = NEWNODE;
756  UniConfKey nodekey(key.first(seg));
757  WvString curr = base->get(nodekey);
758  subnode->was_null_or_empty = !curr;
759  if (curr.isnull())
760  delta(nodekey, WvString::empty);
761  }
762 
763  UniConfKey segment(key.segment(seg++));
764  UniConfChangeTree *next = subnode->findchild(segment);
765  // Switch to create_change() if we ever can't find the next node,
766  // and switch to set_value() if we ever find a NEWTREE.
767  if (!next)
768  {
769  create_change(subnode, key, seg, value);
770  return node;
771  }
772  else if (next->mode == NEWTREE)
773  {
774  next->newtree = set_value(next->newtree,
775  key, seg, value);
776  return node;
777  }
778  else
779  subnode = next;
780  }
781  // The node already existed, didn't have mode of NEWTREE, and we've
782  // found it; change it.
783  if (value.isnull())
784  {
785  if (subnode->mode != BLANK || base->exists(key))
786  deletion_simulator2(key);
787  subnode->zap();
788  subnode->mode = NEWTREE;
789  subnode->newtree = 0;
790  }
791  else if (subnode->mode == NEWVALUE)
792  {
793  if (subnode->newvalue != value)
794  {
795  subnode->newvalue = value;
796  delta(key, value);
797  }
798  }
799  else if (subnode->mode == BLANK)
800  {
801  if (base->get(key) != value)
802  delta(key, value);
803  subnode->mode = NEWVALUE;
804  subnode->newvalue = WvString(value);
805  }
806  else // i.e. subnode->mode == NEWNODE
807  {
808  WvString currval(base->get(key));
809  if ((!currval != !value) && (currval != value))
810  delta(key, value);
811  subnode->mode = NEWVALUE;
812  subnode->newvalue = WvString(value);
813  }
814  return node;
815 }
816 
817 // We'll say we're okay whenever the underlying generator is.
819 {
820  return base->isok();
821 }
822 
824 {
825 }
void rewind()
Rewinds the iterator.
bool next()
Seeks to the next element in the sequence.
UniConfKey key() const
Returns the current key.
WvString value() const
Returns the value of the current key.
WvString value() const
Returns the value of the current key.
UniConfKey key() const
Returns the current key.
bool next()
Seeks to the next element in the sequence.
void rewind()
Rewinds the iterator.
The basic interface which is included by all other XPLC interfaces and objects.
Definition: IObject.h:65
An abstract data container that backs a UniConf tree.
Definition: uniconfgen.h:40
virtual Iter * iterator(const UniConfKey &key)=0
Returns an iterator over the children of the specified key.
virtual bool exists(const UniConfKey &key)=0
Without fetching its value, returns true if a key exists.
virtual bool isok()=0
Determines if the generator is usable and working properly.
virtual bool refresh()=0
Refreshes information about a key recursively.
virtual WvString get(const UniConfKey &key)=0
Fetches a string value for a key from the registry.
virtual void add_callback(void *cookie, const UniConfGenCallback &callback)=0
Adds a callback for change notification.
virtual void commit()=0
Commits any changes.
virtual void del_callback(void *cookie)=0
Removes a callback for change notification.
virtual void set(const UniConfKey &key, WvStringParm value)=0
Stores a string value for a key into the registry.
An abstract iterator over keys and values in a generator.
Definition: uniconfgen.h:324
virtual bool next()=0
Seeks to the next element in the sequence.
virtual WvString value() const =0
Returns the value of the current key.
virtual void rewind()=0
Rewinds the iterator.
virtual UniConfKey key() const =0
Returns the current key.
An iterator that's always empty.
Definition: uniconfgen.h:358
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition: uniconfgen.cc:32
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition: uniconfgen.cc:38
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Definition: uniconfgen.cc:77
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:39
bool hastrailingslash() const
Returns true if the key has a trailing slash.
Definition: uniconfkey.h:273
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 first(int n=1) const
Returns the path formed by the n first segments of this path.
Definition: uniconfkey.h:314
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
Definition: uniconfkey.h:324
A recursively composed dictionary for tree-structured data indexed by UniConfKey.
Definition: uniconftree.h:24
UniConfKey fullkey(const Sub *ancestor=NULL) const
Returns full path of this node relative to an ancestor.
Definition: uniconftree.h:55
Sub * findchild(const UniConfKey &key) const
Finds the direct child node with the specified key.
Definition: uniconftree.h:71
UniConfChangeTree * parent() const
Returns a pointer to the parent node, or NULL if there is none.
Definition: uniconftree.h:40
void visit(const Visitor &visitor, void *userdata, bool preorder=true, bool postorder=false) const
Performs a traversal on this tree using the specified visitor function and traversal type(s).
Definition: uniconftree.h:108
void zap()
Removes and deletes all children of this node.
Definition: uniconftree.h:84
Sub * find(const UniConfKey &key) const
Finds the sub-node with the specified key.
Definition: uniconftree.h:62
A plain UniConfTree that holds keys and values.
Definition: uniconftree.h:153
const WvString & value() const
Returns the value field.
Definition: uniconftree.h:163
void setvalue(WvStringParm value)
Sets the value field.
Definition: uniconftree.h:167
const UniConfKey & key() const
Returns the key field.
Definition: unihashtree.h:40
An iterator that iterates through a constant list of keys.
Definition: unilistiter.h:28
void autofill(IUniConfGen::Iter *source)
Automatically fill the contents of this iterator by calling add() for each element of the 'source' it...
Definition: unilistiter.cc:26
A UniConfGen that represents pending transactions to another generator.
void deletion_visitor(const UniConfValueTree *node, void *userdata)
A UniConfTree visitor function for set_value(), cancel_values(), and cancel_changes().
UniConfValueTree * create_value(UniConfValueTree *parent, const UniConfKey &key, int seg, WvStringParm value)
Four functions to implement the functionality of set() so that it isn't two pages long.
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
void cancel_changes(UniConfChangeTree *node, const UniConfKey &section)
A recursive helper function for refresh().
virtual bool refresh()
Refreshes information about a key recursively.
void apply_values(UniConfValueTree *newcontents, const UniConfKey &section)
A recursive helper function for apply_changes().
virtual void flush_buffers()
Flushes any commitment/notification buffers .
virtual void commit()
Commits any changes.
void deletion_simulator(const UniConfKey &key)
A recursive helper function for create_change().
UniTransactionGen(IUniConfGen *_base)
Constructs a UniTransactionGen for the given underlying generator, which must be non-null.
void deletion_simulator2(const UniConfKey &key)
A recursive helper function for set_change().
void cancel_values(UniConfValueTree *newcontents, const UniConfKey &section)
A recursive helper function for cancel_changes().
~UniTransactionGen()
Destroys the UniTransactionGen and the underlying generator.
virtual bool isok()
Determines if the generator is usable and working properly.
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
void gencallback(const UniConfKey &key, WvStringParm value)
The callback function for the underlying generator.
void apply_changes(UniConfChangeTree *node, const UniConfKey &section)
A recursive helper function for commit().
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
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
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:62
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:330