WvStreams
|
00001 #include "unitransactiongen.h" 00002 #include "uniconftree.h" 00003 #include "unilistiter.h" 00004 #include "wvmoniker.h" 00005 00006 static IUniConfGen *creator(WvStringParm s, IObject *_obj) 00007 { 00008 IUniConfGen *base = wvcreate<IUniConfGen>(s, _obj); 00009 if (base) 00010 return new UniTransactionGen(base); 00011 else 00012 return NULL; 00013 } 00014 00015 static WvMoniker<IUniConfGen> moniker("transaction", creator); 00016 00017 /* This enum is a field of UniConfChangeTree. It indicates the type of 00018 change represented by a node in a UniConfChangeTree. */ 00019 enum changeMode 00020 { 00021 /* This indicates that "newvalue" is valid and that 00022 its value should be written to the underlying generator at commit 00023 time. This tree *might* have children, which must be applied. 00024 "newvalue" will be a non-null pointer to a non-null WvString. */ 00025 NEWVALUE, 00026 /* This indicates that "newtree" is valid (but possibly NULL) and that 00027 the underlying generator's corresponding subtree should be made 00028 identical at commit time. This tree will *not* have children (though 00029 newtree might). */ 00030 NEWTREE, 00031 /* This indicates that "was_null_or_empty" is valid and that the key 00032 in the underlying generator should be created at commit time if it 00033 does not already exist at commit time. This tree *will* have 00034 children, which must be applied, and at least one of which will 00035 be non-BLANK. "was_null_or_empty" will be the return value of the 00036 WvString negation operation on the last known value of the 00037 corresponding key in the underlying generator; it is necessary 00038 in order to filter callbacks in certain cases. */ 00039 NEWNODE, 00040 /* This indicates that none of the fields are valid and that 00041 nothing should be done for this tree. This tree *will* have children, 00042 which must be applied, but they will all have mode of NEWTREE with 00043 newtree == NULL. */ 00044 BLANK 00045 }; 00046 00047 class UniConfChangeTree : public UniConfTree<UniConfChangeTree> 00048 { 00049 public: 00050 changeMode mode; 00051 00052 // This used to be a union, but it was causing memory errors that were 00053 // extremely difficult to track down. Some of this code might serve no 00054 // purpose without this being a union, but I'd rather have it still work 00055 // and not leak than break it. -- mrwise 00056 WvString newvalue; 00057 UniConfValueTree *newtree; 00058 bool was_null_or_empty; 00059 00060 // Constructs a tree and links it to a parent. 00061 UniConfChangeTree(UniConfChangeTree *parent, const UniConfKey &key) 00062 : UniConfTree<UniConfChangeTree>(parent, key), newtree(0) {} 00063 00064 // Destroys a tree and everything it owns. 00065 ~UniConfChangeTree() 00066 { 00067 if (newtree) 00068 delete newtree; 00069 } 00070 }; 00071 00072 // Constructed by UniTransactionGen::iterator() to iterate over a section that 00073 // is to be completely replaced by a particular UniConfValueTree. 00074 class GenStyleValueTreeIter : public UniConfGen::Iter 00075 { 00076 public: 00077 GenStyleValueTreeIter(UniConfValueTree *node) 00078 : i(*node) 00079 { 00080 // printf("GenStyleValueTreeIter\n"); 00081 } 00082 00083 ~GenStyleValueTreeIter() 00084 { 00085 // printf("~GenStyleValueTreeIter\n"); 00086 } 00087 00088 void rewind() { i.rewind(); } 00089 bool next() { return i.next(); } 00090 UniConfKey key() const { return i->key(); } 00091 WvString value() const { return i->value(); } 00092 00093 private: 00094 UniConfValueTree::Iter i; 00095 }; 00096 00097 // Constructed by UniTransactionGen::iterator() to iterate over a section that 00098 // is being modified but not replaced. We iterate first over all of the values 00099 // that we're changing, except those we're deleting, and second over all 00100 // existing values not iterated over in the first stage, except those we're 00101 // deleting. 00102 class GenStyleChangeTreeIter : public UniConfGen::Iter 00103 { 00104 public: 00105 GenStyleChangeTreeIter(UniConfChangeTree *_root, 00106 const UniConfKey &_section, 00107 IUniConfGen *_base) 00108 : root(_root), section(_section), base(_base), 00109 doing_i1(true), i1(*root), i2(base->iterator(section)) 00110 { 00111 // printf("GenStyleChangeTreeIter(%s)\n", WvString(section).cstr()); 00112 } 00113 00114 ~GenStyleChangeTreeIter() 00115 { 00116 // printf("~GenStyleChangeTreeIter(%s)\n", WvString(section).cstr()); 00117 if (i2) delete i2; 00118 } 00119 00120 void rewind() 00121 { 00122 i1.rewind(); 00123 doing_i1 = true; 00124 } 00125 00126 bool next() 00127 { 00128 if (doing_i1) 00129 { 00130 for (;;) 00131 { 00132 if (i1.next()) 00133 { 00134 if (i1->mode == NEWVALUE || 00135 i1->mode == NEWNODE || 00136 (i1->mode == NEWTREE && i1->newtree)) 00137 return true; 00138 } 00139 else 00140 break; 00141 } 00142 doing_i1 = false; 00143 if (i2) i2->rewind(); 00144 } 00145 if (i2) 00146 { 00147 for (;;) 00148 { 00149 if (i2->next()) 00150 { 00151 UniConfChangeTree *node = root->findchild(i2->key()); 00152 if (!node || node->mode == BLANK) 00153 return true; 00154 } 00155 else 00156 break; 00157 } 00158 } 00159 return false; 00160 } 00161 00162 UniConfKey key() const 00163 { 00164 if (doing_i1) 00165 return i1->key(); 00166 else if (i2) 00167 return i2->key(); 00168 else 00169 return UniConfKey(); 00170 } 00171 00172 WvString value() const 00173 { 00174 if (doing_i1) 00175 { 00176 if (i1->mode == NEWVALUE) 00177 return i1->newvalue; 00178 else if (i1->mode == NEWTREE) 00179 return i1->newtree->value(); 00180 else // i.e. i1->mode == NEWNODE 00181 { 00182 WvString value(base->get(UniConfKey(section, i1->key()))); 00183 return !value ? WvString::empty : value; 00184 } 00185 } 00186 else 00187 { 00188 return i2->value(); 00189 } 00190 } 00191 00192 private: 00193 UniConfChangeTree *root; 00194 UniConfKey section; 00195 IUniConfGen *base; 00196 00197 bool doing_i1; 00198 UniConfChangeTree::Iter i1; 00199 UniConfGen::Iter *i2; 00200 }; 00201 00202 UniTransactionGen::UniTransactionGen(IUniConfGen *_base) 00203 : root(NULL), base(_base) 00204 { 00205 base->add_callback(this, wv::bind(&UniTransactionGen::gencallback, this, 00206 _1, _2)); 00207 } 00208 00209 UniTransactionGen::~UniTransactionGen() 00210 { 00211 base->del_callback(this); 00212 WVRELEASE(base); 00213 WVDELETE(root); 00214 } 00215 00216 WvString UniTransactionGen::get(const UniConfKey &key) 00217 { 00218 UniConfChangeTree *node = root; 00219 for (int seg = 0;; node = node->findchild(key.segment(seg++))) 00220 { 00221 if (!node) 00222 // If we couldn't find the next node, then we aren't 00223 // changing the requested key, and so the value is whatever 00224 // it currently is. 00225 return base->get(key); 00226 else if (node->mode == NEWTREE) 00227 { 00228 // Else if the next node has mode of NEWTREE, then we're changing 00229 // the requested key to whatever its value is in the stored 00230 // tree. 00231 if (node->newtree) 00232 { 00233 UniConfValueTree *subnode = node->newtree->find( 00234 key.last(key.numsegments() - seg)); 00235 if (subnode) 00236 return subnode->value(); 00237 } 00238 return WvString::null; 00239 } 00240 else if (seg == key.numsegments()) 00241 { 00242 // Else if this is the last node, then figure out what the node 00243 // would do and return the appropriate value. (The node's mode 00244 // will be either NEWVALUE, NEWNODE, or BLANK.) 00245 if (node->mode == NEWVALUE) 00246 return node->newvalue; 00247 WvString value(base->get(key.first(seg))); 00248 return (node->mode == NEWNODE && !value) ? WvString::empty : value; 00249 } 00250 } 00251 } 00252 00253 void UniTransactionGen::set(const UniConfKey &key, WvStringParm value) 00254 { 00255 hold_delta(); 00256 root = set_change(root, key, 0, value); 00257 unhold_delta(); 00258 } 00259 00260 void UniTransactionGen::setv(const UniConfPairList &pairs) 00261 { 00262 hold_delta(); 00263 UniConfPairList::Iter i(pairs); 00264 for (i.rewind(); i.next(); ) 00265 root = set_change(root, i->key(), 0, i->value()); 00266 unhold_delta(); 00267 } 00268 00269 void UniTransactionGen::commit() 00270 { 00271 if (root) 00272 { 00273 // Apply our changes to the inner generator. We can't optimise 00274 // away callbacks at this point, because we may get notified of 00275 // changes caused by our changes. 00276 hold_delta(); 00277 apply_changes(root, UniConfKey()); 00278 00279 // make sure the inner generator also commits 00280 base->commit(); 00281 00282 // save deleting the root till now so we can hide any 00283 // redundant notifications caused by the base->commit() 00284 delete root; 00285 root = NULL; 00286 unhold_delta(); 00287 } 00288 00289 // no need to base->commit() if we know we haven't changed anything! 00290 } 00291 00292 bool UniTransactionGen::refresh() 00293 { 00294 if (root) 00295 { 00296 hold_delta(); 00297 cancel_changes(root, UniConfKey()); 00298 delete root; 00299 root = NULL; 00300 unhold_delta(); 00301 00302 // no need to base->commit() here, since the inner generator never 00303 // saw any changes 00304 } 00305 00306 // must always base->refresh(), even if we didn't change anything 00307 return base->refresh(); 00308 } 00309 00310 UniConfGen::Iter *UniTransactionGen::iterator(const UniConfKey &key) 00311 { 00312 UniConfChangeTree *node = root; 00313 for (int seg = 0;; node = node->findchild(key.segment(seg++))) 00314 { 00315 if (!node) 00316 // If we couldn't find the next node, then we aren't changing the 00317 // children of the requested key, so they're whatever they 00318 // currently are. 00319 return base->iterator(key); 00320 else if (node->mode == NEWTREE) 00321 { 00322 // Else if the next node has mode of NEWTREE, then we're changing 00323 // the children of the requested key to whatever they are in the 00324 // stored tree. 00325 if (node->newtree) 00326 { 00327 UniConfValueTree *subnode = node->newtree->find( 00328 key.last(key.numsegments() - seg)); 00329 if (subnode) 00330 { 00331 UniConfGen::Iter *i = new GenStyleValueTreeIter(subnode); 00332 UniListIter *i2 = new UniListIter(this); 00333 i2->autofill(i); 00334 delete i; 00335 return i2; 00336 } 00337 } 00338 return new UniConfGen::NullIter(); 00339 } 00340 else if (seg == key.numsegments()) 00341 { 00342 // Else if this is the last node, then iterate over its direct 00343 // children. 00344 UniConfGen::Iter *i = new GenStyleChangeTreeIter(node, key, base); 00345 UniListIter *i2 = new UniListIter(this); 00346 i2->autofill(i); 00347 delete i; 00348 return i2; 00349 } 00350 } 00351 } 00352 00353 void UniTransactionGen::apply_values(UniConfValueTree *newcontents, 00354 const UniConfKey §ion) 00355 { 00356 base->set(section, newcontents->value()); 00357 00358 UniConfGen::Iter *j = base->iterator(section); 00359 if (j) 00360 { 00361 for (j->rewind(); j->next();) 00362 { 00363 if (newcontents->findchild(j->key()) == NULL) 00364 // Delete all children of the current value in the 00365 // underlying generator that do not exist in our 00366 // replacement tree. 00367 base->set(UniConfKey(section, j->key()), WvString::null); 00368 } 00369 delete j; 00370 } 00371 00372 // Repeat for each child in the replacement tree. 00373 UniConfValueTree::Iter i(*newcontents); 00374 for (i.rewind(); i.next();) 00375 apply_values(i.ptr(), UniConfKey(section, i->key())); 00376 } 00377 00378 void UniTransactionGen::apply_changes(UniConfChangeTree *node, 00379 const UniConfKey §ion) 00380 { 00381 if (node->mode == NEWTREE) 00382 { 00383 // If the current change is a NEWTREE change, then replace the 00384 // tree in the underlying generator with the stored one. 00385 if (node->newtree == NULL) 00386 base->set(section, WvString::null); 00387 else 00388 apply_values(node->newtree, section); 00389 // Since such changes have no children, return immediately. 00390 return; 00391 } 00392 else if (node->mode == NEWVALUE) 00393 { 00394 // Else if the current change is a NEWVALUE change, ... 00395 base->set(section, node->newvalue); 00396 } 00397 else if (node->mode == NEWNODE) 00398 { 00399 // Else if the current change is a NEWNODE change, ... 00400 if (!base->exists(section)) 00401 // ... and the current value in the underlying generator doesn't 00402 // exist, then create it. 00403 base->set(section, WvString::empty); 00404 // Note: This *is* necessary. We can't ignore this change and have 00405 // the underlying generator handle it, because it's possible that 00406 // this NEWNODE was the result of a set() which was later deleted. 00407 } 00408 00409 // Repeat for each child in the change tree. 00410 UniConfChangeTree::Iter i(*node); 00411 for (i.rewind(); i.next();) 00412 apply_changes(i.ptr(), UniConfKey(section, i->key())); 00413 } 00414 00415 struct my_userdata 00416 { 00417 UniConfValueTree *node; 00418 const UniConfKey &key; 00419 }; 00420 00421 void UniTransactionGen::deletion_visitor(const UniConfValueTree *node, 00422 void *userdata) 00423 { 00424 my_userdata *data = (my_userdata *)userdata; 00425 delta(UniConfKey(data->key, node->fullkey(data->node)), WvString::null); 00426 } 00427 00428 // Mirror image of apply_values() that issues all of the callbacks associated 00429 // with discarding a replacement value tree. 00430 void UniTransactionGen::cancel_values(UniConfValueTree *newcontents, 00431 const UniConfKey §ion) 00432 { 00433 WvString value(base->get(section)); 00434 if (!newcontents || newcontents->value() != value) 00435 delta(section, value); 00436 00437 if (newcontents) 00438 { 00439 UniConfValueTree::Iter i(*newcontents); 00440 for (i.rewind(); i.next();) 00441 { 00442 UniConfKey subkey(section, i->key()); 00443 if (!base->exists(subkey)) 00444 { 00445 my_userdata data = { i.ptr(), subkey }; 00446 i->visit(wv::bind(&UniTransactionGen::deletion_visitor, this, 00447 _1, _2), 00448 (void*)&data, false, true); 00449 } 00450 } 00451 } 00452 00453 UniConfGen::Iter *i = base->iterator(section); 00454 if (i) 00455 { 00456 for (i->rewind(); i->next();) 00457 cancel_values(newcontents ? 00458 newcontents->findchild(i->key()) : NULL, 00459 UniConfKey(section, i->key())); 00460 delete i; 00461 } 00462 } 00463 00464 // Mirror image of apply_changes() that issues all of the callbacks associated 00465 // with discarding a change tree. 00466 void UniTransactionGen::cancel_changes(UniConfChangeTree *node, 00467 const UniConfKey §ion) 00468 { 00469 if (node->mode == NEWTREE) 00470 { 00471 if (!base->exists(section)) 00472 { 00473 if (node->newtree != NULL) 00474 { 00475 my_userdata data = { node->newtree, section }; 00476 node->newtree->visit( 00477 wv::bind(&UniTransactionGen::deletion_visitor, this, 00478 _1, _2), 00479 (void *)&data, false, true); 00480 } 00481 } 00482 else 00483 cancel_values(node->newtree, section); 00484 return; 00485 } 00486 00487 WvString value; 00488 if (node->mode != BLANK) 00489 value = base->get(section); 00490 00491 if (node->mode == NEWVALUE && 00492 !value.isnull() && 00493 value != node->newvalue) 00494 delta(section, value); 00495 00496 UniConfChangeTree::Iter i(*node); 00497 for (i.rewind(); i.next();) 00498 cancel_changes(i.ptr(), UniConfKey(section, i->key())); 00499 00500 if (node->mode != BLANK && value.isnull()) 00501 delta(section, WvString::null); 00502 } 00503 00504 void UniTransactionGen::gencallback(const UniConfKey &key, 00505 WvStringParm value) 00506 { 00507 UniConfChangeTree *node = root; 00508 for (int seg = 0;; node = node->findchild(key.segment(seg++))) 00509 { 00510 if (!node) 00511 // If we couldn't find the next node, then we aren't changing 00512 // the changed key or any of its children, and so a callback 00513 // should be made. 00514 break; 00515 else if (node->mode == NEWTREE) 00516 // Else if the next node has mode of NEWTREE, then we're changing 00517 // the changed key and all of its children to whatever their 00518 // values are in the stored tree, and so the callback should be 00519 // ignored. 00520 return; 00521 else if (seg == key.numsegments()) 00522 { 00523 // Else if this is the last node, then figure out what we 00524 // should do. 00525 if (node->mode == NEWVALUE) 00526 // If we're replacing this key's value, then we should 00527 // ignore the callback. 00528 return; 00529 else if (node->mode == NEWNODE) 00530 { 00531 // Else if we want to create this key, then use its 00532 // was_null_or_empty flag to figure out if we need 00533 // to issue a callback, and update it if necessary. 00534 if (node->was_null_or_empty && !value) 00535 return; 00536 node->was_null_or_empty = !value; 00537 if (value.isnull()) 00538 { 00539 delta(key, WvString::empty); 00540 return; 00541 } 00542 break; 00543 } 00544 else // i.e. node->mode == BLANK 00545 // Else if we're doing nothing to this key, then a 00546 // callback should be made. 00547 break; 00548 } 00549 } 00550 00551 // Make a normal callback. 00552 delta(key, value); 00553 } 00554 00555 // Create and return a UniConfValueTree containing the value 'value' for 00556 // the key given by the segments of 'key' at and after position 'seg', with 00557 // parent 'parent' and key given by the segment of 'key' at position seg-1 00558 // (which is the "root" key if seg == 0). Issue callbacks as necessary using 00559 // all the segments of 'key'. 00560 UniConfValueTree *UniTransactionGen::create_value(UniConfValueTree *parent, 00561 const UniConfKey &key, 00562 int seg, 00563 WvStringParm value) 00564 { 00565 UniConfValueTree *tree = 0; 00566 for (; seg != key.numsegments();) 00567 { 00568 // Create any needed intermediate nodes, each with value equal to 00569 // the empty string. 00570 parent = new UniConfValueTree(parent, 00571 key.segment(seg-1), 00572 WvString::empty); 00573 delta(key.first(seg++), WvString::empty); 00574 if (!tree) 00575 tree = parent; 00576 } 00577 // Create the last node with the specified value. 00578 parent = new UniConfValueTree(parent, 00579 key.segment(seg-1), 00580 value); 00581 delta(key, value); 00582 if (!tree) 00583 tree = parent; 00584 return tree; 00585 } 00586 00587 void UniTransactionGen::deletion_simulator(const UniConfKey &key) 00588 { 00589 UniConfGen::Iter *i = base->iterator(key); 00590 if (i) 00591 { 00592 for (i->rewind(); i->next();) 00593 deletion_simulator(UniConfKey(key, i->key())); 00594 delete i; 00595 } 00596 delta(key, WvString::null); 00597 } 00598 00599 // Like create_value(), but make a UniConfChangeTree containing a *change* 00600 // to value 'value'. 00601 UniConfChangeTree *UniTransactionGen::create_change(UniConfChangeTree *parent, 00602 const UniConfKey &key, 00603 int seg, 00604 WvStringParm value) 00605 { 00606 // if the key has a trailing slash, this should be a no-op: we don't 00607 // want this to have any effect 00608 if ((key.hastrailingslash()) && !value.isnull()) 00609 return parent; 00610 00611 UniConfChangeTree *tree = 0; 00612 for (; seg != key.numsegments(); seg++) 00613 { 00614 parent = new UniConfChangeTree(parent, key.segment(seg-1)); 00615 if (value.isnull()) 00616 // We don't do anything for intermediate nodes when deleting, ... 00617 parent->mode = BLANK; 00618 else 00619 { 00620 // ... but when set()'ing a non-null value, we want them to exist. 00621 parent->mode = NEWNODE; 00622 UniConfKey nodekey(key.first(seg)); 00623 WvString curr = base->get(nodekey); 00624 parent->was_null_or_empty = !curr; 00625 if (curr.isnull()) 00626 delta(nodekey, WvString::empty); 00627 } 00628 if (!tree) 00629 tree = parent; 00630 } 00631 parent = new UniConfChangeTree(parent, key.segment(seg-1)); 00632 // Create the last node with the specified change. 00633 if (value.isnull()) 00634 { 00635 parent->mode = NEWTREE; 00636 parent->newtree = 0; 00637 if (base->exists(key)) 00638 deletion_simulator(key); 00639 } 00640 else 00641 { 00642 parent->mode = NEWVALUE; 00643 parent->newvalue = WvString(value); 00644 if (base->get(key) != value) 00645 delta(key, value); 00646 } 00647 if (!tree) 00648 tree = parent; 00649 return tree; 00650 } 00651 00652 // Modify an existing UniConfValueTree to incorporate the set() of a 00653 // particular value for a particular key. Return a possibly altered 00654 // pointer to the root of the tree. 'seg' and 'key' are used like they 00655 // are in create_value(), and callbacks are made similarly. 00656 UniConfValueTree *UniTransactionGen::set_value(UniConfValueTree *node, 00657 const UniConfKey &key, 00658 int seg, 00659 WvStringParm value) 00660 { 00661 // printf("set_value('%s', %d)\n", WvString(key).cstr(), value.isnull()); 00662 if (value.isnull()) 00663 { 00664 // Delete the key if it exists. 00665 if (node) 00666 { 00667 UniConfValueTree *subnode = node->find( 00668 key.last(key.numsegments() - seg)); 00669 if (subnode) 00670 { 00671 hold_delta(); 00672 my_userdata data = { subnode, key }; 00673 subnode->visit(wv::bind(&UniTransactionGen::deletion_visitor, 00674 this, _1, _2), 00675 (void *)&data, false, true); 00676 // printf("DELETE SUBNODE!\n"); 00677 delete subnode; 00678 unhold_delta(); 00679 return subnode == node ? NULL : node; 00680 } 00681 else 00682 return node; 00683 } 00684 else 00685 return NULL; 00686 } 00687 else 00688 { 00689 // Switch to create_value() if we ever can't find the next node. 00690 if (!node) 00691 return create_value(NULL, key, seg, value); 00692 00693 UniConfValueTree *subnode = node; 00694 for (; seg != key.numsegments();) 00695 { 00696 UniConfKey segment(key.segment(seg++)); 00697 UniConfValueTree *child = subnode->findchild(segment); 00698 // Switch to create_value() if we ever can't find the next node. 00699 if (!child) 00700 { 00701 create_value(subnode, key, seg, value); 00702 return node; 00703 } 00704 else 00705 subnode = child; 00706 } 00707 // The node already existed and we've found it; set it. 00708 if (value != subnode->value()) 00709 { 00710 subnode->setvalue(value); 00711 delta(key, value); 00712 } 00713 return node; 00714 } 00715 } 00716 00717 void UniTransactionGen::deletion_simulator2(const UniConfKey &key) 00718 { 00719 UniConfGen::Iter *i = this->iterator(key); 00720 if (i) 00721 { 00722 for (i->rewind(); i->next();) 00723 deletion_simulator2(UniConfKey(key, i->key())); 00724 delete i; 00725 } 00726 delta(key, WvString::null); 00727 } 00728 00729 // Like set_value(), but, again, for UniConfChangeTrees instead. 00730 UniConfChangeTree *UniTransactionGen::set_change(UniConfChangeTree *node, 00731 const UniConfKey &key, 00732 int seg, 00733 WvStringParm value) 00734 { 00735 // printf("set_change(key=%s,mode=%d) = '%s'\n", 00736 // WvString(key).cstr(), node ? node->mode : 999, value.cstr()); 00737 00738 // Switch to create_change() if we ever can't find the next node, 00739 // and switch to set_value() if we ever find a NEWTREE. 00740 if (!node) 00741 return create_change(NULL, key, seg, value); 00742 else if (node->mode == NEWTREE) 00743 { 00744 node->newtree = set_value(node->newtree, key, seg, value); 00745 return node; 00746 } 00747 00748 UniConfChangeTree *subnode = node; 00749 for (; seg != key.numsegments();) 00750 { 00751 if (subnode->mode == BLANK && !value.isnull()) 00752 { 00753 // If we're setting a non-null value and we weren't previously 00754 // doing anything to this node, then now we want to create it. 00755 subnode->mode = NEWNODE; 00756 UniConfKey nodekey(key.first(seg)); 00757 WvString curr = base->get(nodekey); 00758 subnode->was_null_or_empty = !curr; 00759 if (curr.isnull()) 00760 delta(nodekey, WvString::empty); 00761 } 00762 00763 UniConfKey segment(key.segment(seg++)); 00764 UniConfChangeTree *next = subnode->findchild(segment); 00765 // Switch to create_change() if we ever can't find the next node, 00766 // and switch to set_value() if we ever find a NEWTREE. 00767 if (!next) 00768 { 00769 create_change(subnode, key, seg, value); 00770 return node; 00771 } 00772 else if (next->mode == NEWTREE) 00773 { 00774 next->newtree = set_value(next->newtree, 00775 key, seg, value); 00776 return node; 00777 } 00778 else 00779 subnode = next; 00780 } 00781 // The node already existed, didn't have mode of NEWTREE, and we've 00782 // found it; change it. 00783 if (value.isnull()) 00784 { 00785 if (subnode->mode != BLANK || base->exists(key)) 00786 deletion_simulator2(key); 00787 subnode->zap(); 00788 subnode->mode = NEWTREE; 00789 subnode->newtree = 0; 00790 } 00791 else if (subnode->mode == NEWVALUE) 00792 { 00793 if (subnode->newvalue != value) 00794 { 00795 subnode->newvalue = value; 00796 delta(key, value); 00797 } 00798 } 00799 else if (subnode->mode == BLANK) 00800 { 00801 if (base->get(key) != value) 00802 delta(key, value); 00803 subnode->mode = NEWVALUE; 00804 subnode->newvalue = WvString(value); 00805 } 00806 else // i.e. subnode->mode == NEWNODE 00807 { 00808 WvString currval(base->get(key)); 00809 if ((!currval != !value) && (currval != value)) 00810 delta(key, value); 00811 subnode->mode = NEWVALUE; 00812 subnode->newvalue = WvString(value); 00813 } 00814 return node; 00815 } 00816 00817 // We'll say we're okay whenever the underlying generator is. 00818 bool UniTransactionGen::isok() 00819 { 00820 return base->isok(); 00821 } 00822 00823 void UniTransactionGen::flush_buffers() 00824 { 00825 }