unitransactiongen.cc

00001 #include "unitransactiongen.h"
00002 #include "uniconftree.h"
00003 #include "unilistiter.h"
00004 #include "wvmoniker.h"
00005 
00006 static IUniConfGen *creator(WvStringParm s)
00007 {
00008     IUniConfGen *base = wvcreate<IUniConfGen>(s);
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,
00206         UniConfGenCallback(this, &UniTransactionGen::gencallback));
00207 }
00208 
00209 UniTransactionGen::~UniTransactionGen()
00210 {
00211     base->del_callback(this);
00212     WVRELEASE(base);
00213     if (root)
00214         delete root;
00215 }
00216 
00217 WvString UniTransactionGen::get(const UniConfKey &key)
00218 {
00219     UniConfChangeTree *node = root;
00220     for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00221     {
00222         if (!node)
00223             // If we couldn't find the next node, then we aren't
00224             // changing the requested key, and so the value is whatever
00225             // it currently is.
00226             return base->get(key);
00227         else if (node->mode == NEWTREE)
00228         {
00229             // Else if the next node has mode of NEWTREE, then we're changing
00230             // the requested key to whatever its value is in the stored
00231             // tree.
00232             if (node->newtree)
00233             {
00234                 UniConfValueTree *subnode = node->newtree->find(
00235                     key.last(key.numsegments() - seg));
00236                 if (subnode)
00237                     return subnode->value();
00238             }
00239             return WvString::null;
00240         }
00241         else if (seg == key.numsegments())
00242         {
00243             // Else if this is the last node, then figure out what the node
00244             // would do and return the appropriate value. (The node's mode
00245             // will be either NEWVALUE, NEWNODE, or BLANK.)
00246             if (node->mode == NEWVALUE)
00247                 return node->newvalue;
00248             WvString value(base->get(key.first(seg)));
00249             return (node->mode == NEWNODE && !value) ? WvString::empty : value;
00250         }
00251     }
00252 }
00253 
00254 void UniTransactionGen::set(const UniConfKey &key, WvStringParm value)
00255 {
00256     hold_delta();
00257     root = set_change(root, key, 0, value);
00258     unhold_delta();
00259 }
00260 
00261 void UniTransactionGen::setv(const UniConfPairList &pairs)
00262 {
00263     hold_delta();
00264     UniConfPairList::Iter i(pairs);
00265     for (i.rewind(); i.next(); )
00266         root = set_change(root, i->key(), 0, i->value());
00267     unhold_delta();
00268 }
00269 
00270 void UniTransactionGen::commit()
00271 {
00272     if (root)
00273     {
00274         // Apply our changes to the inner generator.  We can't optimise
00275         // away callbacks at this point, because we may get notified of
00276         // changes caused by our changes.
00277         hold_delta();
00278         apply_changes(root, UniConfKey());
00279 
00280         // make sure the inner generator also commits
00281         base->commit();
00282 
00283         // save deleting the root till now so we can hide any
00284         // redundant notifications caused by the base->commit()
00285         delete root;
00286         root = NULL;
00287         unhold_delta();
00288     }
00289     
00290     // no need to base->commit() if we know we haven't changed anything!
00291 }
00292 
00293 bool UniTransactionGen::refresh()
00294 {
00295     if (root)
00296     {
00297         hold_delta();
00298         cancel_changes(root, UniConfKey());
00299         delete root;
00300         root = NULL;
00301         unhold_delta();
00302         
00303         // no need to base->commit() here, since the inner generator never
00304         // saw any changes
00305     }
00306     
00307     // must always base->refresh(), even if we didn't change anything
00308     return base->refresh();
00309 }
00310 
00311 UniConfGen::Iter *UniTransactionGen::iterator(const UniConfKey &key)
00312 {
00313     UniConfChangeTree *node = root;
00314     for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00315     {
00316         if (!node)
00317             // If we couldn't find the next node, then we aren't changing the
00318             // children of the requested key, so they're whatever they
00319             // currently are.
00320             return base->iterator(key);
00321         else if (node->mode == NEWTREE)
00322         {
00323             // Else if the next node has mode of NEWTREE, then we're changing
00324             // the children of the requested key to whatever they are in the
00325             // stored tree.
00326             if (node->newtree)
00327             {
00328                 UniConfValueTree *subnode = node->newtree->find(
00329                     key.last(key.numsegments() - seg));
00330                 if (subnode)
00331                 {
00332                     UniConfGen::Iter *i = new GenStyleValueTreeIter(subnode);
00333                     UniListIter *i2 = new UniListIter(this);
00334                     i2->autofill(i);
00335                     delete i;
00336                     return i2;
00337                 }
00338             }
00339             return new UniConfGen::NullIter();
00340         }
00341         else if (seg == key.numsegments())
00342         {
00343             // Else if this is the last node, then iterate over its direct
00344             // children.
00345             UniConfGen::Iter *i = new GenStyleChangeTreeIter(node, key, base);
00346             UniListIter *i2 = new UniListIter(this);
00347             i2->autofill(i);
00348             delete i;
00349             return i2;
00350         }
00351     }
00352 }
00353 
00354 void UniTransactionGen::apply_values(UniConfValueTree *newcontents,
00355                                      const UniConfKey &section)
00356 {
00357     base->set(section, newcontents->value());
00358 
00359     UniConfGen::Iter *j = base->iterator(section);
00360     if (j)
00361     {
00362         for (j->rewind(); j->next();)
00363         {
00364             if (newcontents->findchild(j->key()) == NULL)
00365                 // Delete all children of the current value in the
00366                 // underlying generator that do not exist in our
00367                 // replacement tree.
00368                 base->set(UniConfKey(section, j->key()), WvString::null);
00369         }
00370         delete j;
00371     }
00372 
00373     // Repeat for each child in the replacement tree.
00374     UniConfValueTree::Iter i(*newcontents);
00375     for (i.rewind(); i.next();)
00376         apply_values(i.ptr(), UniConfKey(section, i->key()));
00377 }
00378 
00379 void UniTransactionGen::apply_changes(UniConfChangeTree *node,
00380                                       const UniConfKey &section)
00381 {
00382     if (node->mode == NEWTREE)
00383     {
00384         // If the current change is a NEWTREE change, then replace the
00385         // tree in the underlying generator with the stored one.
00386         if (node->newtree == NULL)
00387             base->set(section, WvString::null);
00388         else
00389             apply_values(node->newtree, section);
00390         // Since such changes have no children, return immediately.
00391         return;
00392     }
00393     else if (node->mode == NEWVALUE)
00394     {
00395         // Else if the current change is a NEWVALUE change, ...
00396         base->set(section, node->newvalue);
00397     }
00398     else if (node->mode == NEWNODE)
00399     {
00400         // Else if the current change is a NEWNODE change, ...
00401         if (!base->exists(section))
00402             // ... and the current value in the underlying generator doesn't
00403             // exist, then create it.
00404             base->set(section, WvString::empty);
00405         // Note: This *is* necessary. We can't ignore this change and have
00406         // the underlying generator handle it, because it's possible that
00407         // this NEWNODE was the result of a set() which was later deleted.
00408     }
00409     
00410     // Repeat for each child in the change tree.
00411     UniConfChangeTree::Iter i(*node);
00412     for (i.rewind(); i.next();)
00413         apply_changes(i.ptr(), UniConfKey(section, i->key()));
00414 }
00415 
00416 struct my_userdata
00417 {
00418     UniConfValueTree *node;
00419     const UniConfKey &key;
00420 };
00421 
00422 void UniTransactionGen::deletion_visitor(const UniConfValueTree *node,
00423                                          void *userdata)
00424 {
00425     my_userdata *data = (my_userdata *)userdata;
00426     delta(UniConfKey(data->key, node->fullkey(data->node)), WvString::null);
00427 }
00428 
00429 // Mirror image of apply_values() that issues all of the callbacks associated
00430 // with discarding a replacement value tree.
00431 void UniTransactionGen::cancel_values(UniConfValueTree *newcontents,
00432                                       const UniConfKey &section)
00433 {
00434     WvString value(base->get(section));
00435     if (!newcontents || newcontents->value() != value)
00436         delta(section, value);
00437     
00438     if (newcontents)
00439     {
00440         UniConfValueTree::Iter i(*newcontents);
00441         for (i.rewind(); i.next();)
00442         {
00443             UniConfKey subkey(section, i->key());
00444             if (!base->exists(subkey))
00445             {
00446                 my_userdata data = { i.ptr(), subkey };
00447                 i->visit(
00448                     UniConfValueTree::Visitor(
00449                         this, &UniTransactionGen::deletion_visitor),
00450                     (void *)&data, false, true);
00451             }
00452         }
00453     }
00454 
00455     UniConfGen::Iter *i = base->iterator(section);
00456     if (i)
00457     {
00458         for (i->rewind(); i->next();)
00459             cancel_values(newcontents ?
00460                           newcontents->findchild(i->key()) : NULL,
00461                           UniConfKey(section, i->key()));
00462         delete i;
00463     }
00464 }
00465 
00466 // Mirror image of apply_changes() that issues all of the callbacks associated
00467 // with discarding a change tree.
00468 void UniTransactionGen::cancel_changes(UniConfChangeTree *node,
00469                                        const UniConfKey &section)
00470 {
00471     if (node->mode == NEWTREE)
00472     {
00473         if (!base->exists(section))
00474         {
00475             if (node->newtree != NULL)
00476             {
00477                 my_userdata data = { node->newtree, section };
00478                 node->newtree->visit(
00479                     UniConfValueTree::Visitor(
00480                         this, &UniTransactionGen::deletion_visitor),
00481                     (void *)&data, false, true);
00482             }
00483         }
00484         else
00485             cancel_values(node->newtree, section);
00486         return;
00487     }
00488 
00489     WvString value;
00490     if (node->mode != BLANK)
00491         value = base->get(section);
00492 
00493     if (node->mode == NEWVALUE &&
00494         !value.isnull() &&
00495         value != node->newvalue)
00496         delta(section, value);
00497 
00498     UniConfChangeTree::Iter i(*node);
00499     for (i.rewind(); i.next();)
00500         cancel_changes(i.ptr(), UniConfKey(section, i->key()));
00501 
00502     if (node->mode != BLANK && value.isnull())
00503         delta(section, WvString::null);
00504 }
00505 
00506 void UniTransactionGen::gencallback(const UniConfKey &key,
00507                                     WvStringParm value)
00508 {
00509     UniConfChangeTree *node = root;
00510     for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00511     {
00512         if (!node)
00513             // If we couldn't find the next node, then we aren't changing
00514             // the changed key or any of its children, and so a callback
00515             // should be made.
00516             break;
00517         else if (node->mode == NEWTREE)
00518             // Else if the next node has mode of NEWTREE, then we're changing
00519             // the changed key and all of its children to whatever their
00520             // values are in the stored tree, and so the callback should be
00521             // ignored.
00522             return;
00523         else if (seg == key.numsegments())
00524         {
00525             // Else if this is the last node, then figure out what we 
00526             // should do.
00527             if (node->mode == NEWVALUE)
00528                 // If we're replacing this key's value, then we should
00529                 // ignore the callback.
00530                 return;
00531             else if (node->mode == NEWNODE)
00532             {
00533                 // Else if we want to create this key, then use its
00534                 // was_null_or_empty flag to figure out if we need
00535                 // to issue a callback, and update it if necessary.
00536                 if (node->was_null_or_empty && !value)
00537                     return;
00538                 node->was_null_or_empty = !value;
00539                 if (value.isnull())
00540                 {
00541                     delta(key, WvString::empty);
00542                     return;
00543                 }
00544                 break;
00545             }
00546             else // i.e. node->mode == BLANK
00547                 // Else if we're doing nothing to this key, then a
00548                 // callback should be made.
00549                 break;
00550         }
00551     }
00552     
00553     // Make a normal callback.
00554     delta(key, value);
00555 }
00556 
00557 // Create and return a UniConfValueTree containing the value 'value' for
00558 // the key given by the segments of 'key' at and after position 'seg', with
00559 // parent 'parent' and key given by the segment of 'key' at position seg-1
00560 // (which is the "root" key if seg == 0). Issue callbacks as necessary using
00561 // all the segments of 'key'.
00562 UniConfValueTree *UniTransactionGen::create_value(UniConfValueTree *parent,
00563                                                   const UniConfKey &key,
00564                                                   int seg,
00565                                                   WvStringParm value)
00566 {
00567     UniConfValueTree *tree = 0;
00568     for (; seg != key.numsegments();)
00569     {
00570         // Create any needed intermediate nodes, each with value equal to
00571         // the empty string.
00572         parent = new UniConfValueTree(parent,
00573                                       key.segment(seg-1),
00574                                       WvString::empty);
00575         delta(key.first(seg++), WvString::empty);
00576         if (!tree)
00577             tree = parent;
00578     }
00579     // Create the last node with the specified value.
00580     parent = new UniConfValueTree(parent,
00581                                   key.segment(seg-1),
00582                                   value);
00583     delta(key, value);
00584     if (!tree)
00585         tree = parent;
00586     return tree;
00587 }
00588 
00589 void UniTransactionGen::deletion_simulator(const UniConfKey &key)
00590 {
00591     UniConfGen::Iter *i = base->iterator(key);
00592     if (i)
00593     {
00594         for (i->rewind(); i->next();)
00595             deletion_simulator(UniConfKey(key, i->key()));
00596         delete i;
00597     }
00598     delta(key, WvString::null);
00599 }
00600 
00601 // Like create_value(), but make a UniConfChangeTree containing a *change*
00602 // to value 'value'.
00603 UniConfChangeTree *UniTransactionGen::create_change(UniConfChangeTree *parent,
00604                                                     const UniConfKey &key,
00605                                                     int seg,
00606                                                     WvStringParm value)
00607 {
00608     UniConfChangeTree *tree = 0;
00609     for (; seg != key.numsegments(); seg++)
00610     {
00611         parent = new UniConfChangeTree(parent, key.segment(seg-1));
00612         if (value.isnull())
00613             // We don't do anything for intermediate nodes when deleting, ...
00614             parent->mode = BLANK;
00615         else
00616         {
00617             // ... but when set()'ing a non-null value, we want them to exist.
00618             parent->mode = NEWNODE;
00619             UniConfKey nodekey(key.first(seg));
00620             WvString curr = base->get(nodekey);
00621             parent->was_null_or_empty = !curr;
00622             if (curr.isnull())
00623                 delta(nodekey, WvString::empty);
00624         }
00625         if (!tree)
00626             tree = parent;
00627     }
00628     parent = new UniConfChangeTree(parent, key.segment(seg-1));
00629     // Create the last node with the specified change.
00630     if (value.isnull())
00631     {
00632         parent->mode = NEWTREE;
00633         parent->newtree = 0;
00634         if (base->exists(key))
00635             deletion_simulator(key);
00636     }
00637     else
00638     {
00639         parent->mode = NEWVALUE;
00640         parent->newvalue = WvString(value);
00641         if (base->get(key) != value)
00642             delta(key, value);
00643     }
00644     if (!tree)
00645         tree = parent;
00646     return tree;
00647 }
00648 
00649 // Modify an existing UniConfValueTree to incorporate the set() of a
00650 // particular value for a particular key. Return a possibly altered
00651 // pointer to the root of the tree. 'seg' and 'key' are used like they
00652 // are in create_value(), and callbacks are made similarly.
00653 UniConfValueTree *UniTransactionGen::set_value(UniConfValueTree *node,
00654                                                const UniConfKey &key,
00655                                                int seg,
00656                                                WvStringParm value)
00657 {
00658     // printf("set_value('%s', %d)\n", WvString(key).cstr(), value.isnull());
00659     if (value.isnull())
00660     {
00661         // Delete the key if it exists.
00662         if (node)
00663         {
00664             UniConfValueTree *subnode = node->find(
00665                 key.last(key.numsegments() - seg));
00666             if (subnode)
00667             {
00668                 hold_delta();
00669                 my_userdata data = { subnode, key };
00670                 subnode->visit(
00671                     UniConfValueTree::Visitor(
00672                         this, &UniTransactionGen::deletion_visitor),
00673                     (void *)&data, false, true);
00674                 // printf("DELETE SUBNODE!\n");
00675                 delete subnode;
00676                 unhold_delta();
00677                 return subnode == node ? NULL : node;
00678             }
00679             else
00680                 return node;
00681         }
00682         else
00683             return NULL;
00684     }
00685     else
00686     {
00687         // Switch to create_value() if we ever can't find the next node.
00688         if (!node)
00689             return create_value(NULL, key, seg, value);
00690         
00691         UniConfValueTree *subnode = node;
00692         for (; seg != key.numsegments();)
00693         {
00694             UniConfKey segment(key.segment(seg++));
00695             UniConfValueTree *child = subnode->findchild(segment);
00696             // Switch to create_value() if we ever can't find the next node.
00697             if (!child)
00698             {
00699                 create_value(subnode, key, seg, value);
00700                 return node;
00701             }
00702             else
00703                 subnode = child;
00704         }
00705         // The node already existed and we've found it; set it.
00706         if (value != subnode->value())
00707         {
00708             subnode->setvalue(value);
00709             delta(key, value);
00710         }
00711         return node;
00712     }
00713 }
00714 
00715 void UniTransactionGen::deletion_simulator2(const UniConfKey &key)
00716 {
00717     UniConfGen::Iter *i = this->iterator(key);
00718     if (i)
00719     {
00720         for (i->rewind(); i->next();)
00721             deletion_simulator2(UniConfKey(key, i->key()));
00722         delete i;
00723     }
00724     delta(key, WvString::null);
00725 }
00726 
00727 // Like set_value(), but, again, for UniConfChangeTrees instead.
00728 UniConfChangeTree *UniTransactionGen::set_change(UniConfChangeTree *node,
00729                                                  const UniConfKey &key,
00730                                                  int seg,
00731                                                  WvStringParm value)
00732 {
00733     // printf("set_change(key=%s,mode=%d) = '%s'\n",
00734     //        WvString(key).cstr(), node ? node->mode : 999, value.cstr());
00735     
00736     // Switch to create_change() if we ever can't find the next node,
00737     // and switch to set_value() if we ever find a NEWTREE.
00738     if (!node)
00739         return create_change(NULL, key, seg, value);
00740     else if (node->mode == NEWTREE)
00741     {
00742         node->newtree = set_value(node->newtree, key, seg, value);
00743         return node;
00744     }
00745     
00746     UniConfChangeTree *subnode = node;
00747     for (; seg != key.numsegments();)
00748     {
00749         if (subnode->mode == BLANK && !value.isnull())
00750         {
00751             // If we're setting a non-null value and we weren't previously
00752             // doing anything to this node, then now we want to create it.
00753             subnode->mode = NEWNODE;
00754             UniConfKey nodekey(key.first(seg));
00755             WvString curr = base->get(nodekey);
00756             subnode->was_null_or_empty = !curr;
00757             if (curr.isnull())
00758                 delta(nodekey, WvString::empty);
00759         }
00760         
00761         UniConfKey segment(key.segment(seg++));
00762         UniConfChangeTree *next = subnode->findchild(segment);
00763         // Switch to create_change() if we ever can't find the next node,
00764         // and switch to set_value() if we ever find a NEWTREE.
00765         if (!next)
00766         {
00767             create_change(subnode, key, seg, value);
00768             return node;
00769         }
00770         else if (next->mode == NEWTREE)
00771         {
00772             next->newtree = set_value(next->newtree,
00773                                       key, seg, value);
00774             return node;
00775         }
00776         else
00777             subnode = next;
00778     }
00779     // The node already existed, didn't have mode of NEWTREE, and we've
00780     // found it; change it.
00781     if (value.isnull())
00782     {
00783         if (subnode->mode != BLANK || base->exists(key))
00784             deletion_simulator2(key);
00785         subnode->zap();
00786         subnode->mode = NEWTREE;
00787         subnode->newtree = 0;
00788     }
00789     else if (subnode->mode == NEWVALUE)
00790     {
00791         if (subnode->newvalue != value)
00792         {
00793             subnode->newvalue = value;
00794             delta(key, value);
00795         }
00796     }
00797     else if (subnode->mode == BLANK)
00798     {
00799         if (base->get(key) != value)
00800             delta(key, value);      
00801         subnode->mode = NEWVALUE;
00802         subnode->newvalue = WvString(value);
00803     }
00804     else // i.e. subnode->mode == NEWNODE
00805     {
00806         WvString currval(base->get(key));
00807         if ((!currval != !value) && (currval != value))
00808             delta(key, value);
00809         subnode->mode = NEWVALUE;
00810         subnode->newvalue = WvString(value);
00811     }
00812     return node;
00813 }
00814 
00815 // We'll say we're okay whenever the underlying generator is.
00816 bool UniTransactionGen::isok()
00817 {
00818     return base->isok();
00819 }
00820 
00821 void UniTransactionGen::flush_buffers()
00822 {
00823 }

Generated on Thu Jan 24 16:50:55 2008 for WvStreams by  doxygen 1.5.4