WvStreams
unitransactiongen.cc
1#include "unitransactiongen.h"
2#include "uniconftree.h"
3#include "unilistiter.h"
4#include "wvmoniker.h"
5
6static 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
15static 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. */
19enum 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
47class UniConfChangeTree : public UniConfTree<UniConfChangeTree>
48{
49public:
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.
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{
76public:
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
93private:
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{
104public:
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
163 {
164 if (doing_i1)
165 return i1->key();
166 else if (i2)
167 return i2->key();
168 else
169 return UniConfKey();
170 }
171
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
192private:
193 UniConfChangeTree *root;
194 UniConfKey section;
195 IUniConfGen *base;
196
197 bool doing_i1;
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
260void 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.
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(
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
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();)
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'.
601UniConfChangeTree *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))
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.
656UniConfValueTree *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 };
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();)
724 delete i;
725 }
726 delta(key, WvString::null);
727}
728
729// Like set_value(), but, again, for UniConfChangeTrees instead.
730UniConfChangeTree *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))
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 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 Iter * iterator(const UniConfKey &key)=0
Returns an iterator over the children of the specified key.
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
UniConfChangeTree * 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
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 * findchild(const UniConfKey &key) const
Finds the direct child node with the specified key.
Definition: uniconftree.h:71
A plain UniConfTree that holds keys and values.
Definition: uniconftree.h:153
void setvalue(WvStringParm value)
Sets the value field.
Definition: uniconftree.h:167
const WvString & value() const
Returns the value field.
Definition: uniconftree.h:163
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