WvStreams
unitempgen.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2002-2005 Net Integration Technologies, Inc.
00004  * 
00005  * A UniConf generator that stores keys in memory.
00006  */
00007 #include "unitempgen.h"
00008 #include "wvmoniker.h"
00009 #include "wvlog.h"
00010 #include "wvstringcache.h"
00011 #include "unilistiter.h"
00012 #include "wvlinkerhack.h"
00013 
00014 WV_LINK(UniTempGen);
00015 
00016 static IUniConfGen *creator(WvStringParm, IObject*)
00017 {
00018     return new UniTempGen();
00019 }
00020 
00021 static WvMoniker<IUniConfGen> reg("temp", creator);
00022 
00023 
00024 /***** UniTempGen *****/
00025 
00026 UniTempGen::UniTempGen()
00027     : root(NULL)
00028 {
00029 }
00030 
00031 
00032 UniTempGen::~UniTempGen()
00033 {
00034     delete root;
00035 }
00036 
00037 
00038 WvString UniTempGen::get(const UniConfKey &key)
00039 {
00040     if (root)
00041     {
00042         // Look for an empty section at the end.
00043         if (!key.isempty() && key.last().isempty())
00044             return WvString::null;
00045         UniConfValueTree *node = root->find(key);
00046         if (node)
00047             return node->value();
00048     }
00049     return WvString::null;
00050 }
00051 
00052 void UniTempGen::notify_deleted(const UniConfValueTree *node, void *)
00053 {
00054     delta(node->fullkey(), WvString::null);
00055 }
00056 
00057 void UniTempGen::set(const UniConfKey &_key, WvStringParm _value)
00058 {
00059     WvString value(scache.get(_value));
00060     
00061     hold_delta();
00062     UniConfKey key = _key;
00063     // FIXME: Use key.hastrailingslash(), it's shorter and easier and faster
00064     bool trailing_slash = false;
00065     if (!key.isempty())
00066     {
00067         // Look for an empty section at the end.
00068         UniConfKey last = key;
00069         key = last.pop(last.numsegments() - 1);
00070         if (last.isempty())
00071             trailing_slash = true;
00072         else
00073             key = _key;
00074     }
00075 
00076     if (value.isnull())
00077     {
00078         // remove a subtree
00079         if (root)
00080         {
00081             UniConfValueTree *node = root->find(key);
00082             if (node)
00083             {
00084                 hold_delta();
00085                 // Issue notifications for every key that gets deleted.
00086                 node->visit(wv::bind(&UniTempGen::notify_deleted, this,
00087                                      _1, _2),
00088                             NULL, false, true);
00089                 delete node;
00090                 if (node == root)
00091                     root = NULL;
00092                 dirty = true;
00093                 unhold_delta();
00094             }
00095         }
00096     }
00097     else if (!trailing_slash)
00098     {
00099         UniConfValueTree *node = root;
00100         UniConfValueTree *prev = NULL;
00101         UniConfKey prevkey;
00102         
00103         UniConfKey::Iter it(key);
00104         it.rewind();
00105         for (;;)
00106         {
00107             bool more = it.next(); // not the last node in the key?
00108             
00109             if (!node)
00110             {
00111                 // we'll have to create the sub-node, since we couldn't
00112                 // find the most recent part of the key.
00113                 node = new UniConfValueTree(prev, prevkey,
00114                                             more ? WvString::empty : value);
00115                 dirty = true;
00116                 if (!prev) // we just created the root
00117                     root = node;
00118                 if (more)
00119                     delta(node->fullkey(), WvString::empty); // AUTO-VIVIFIED
00120                 else
00121                 {
00122                     delta(node->fullkey(), value); // ADDED
00123                     break; // done!
00124                 }
00125             }
00126             else if (!more)
00127             {
00128                 // don't have to create the most recent sub-node, but there
00129                 // are no more sub-nodes; that means we're changing the value
00130                 // of an existing node.
00131                 if (value != node->value())
00132                 {
00133                     node->setvalue(value);
00134                     dirty = true;
00135                     delta(node->fullkey(), value); // CHANGED
00136                 }
00137                 break;
00138             }
00139             prevkey = *it;
00140             prev = node;
00141             node = prev->findchild(prevkey);
00142         }
00143         assert(node);
00144     }
00145     
00146     unhold_delta();
00147 }
00148 
00149 
00150 void UniTempGen::setv(const UniConfPairList &pairs)
00151 {
00152     setv_naive(pairs);
00153 }
00154 
00155 
00156 bool UniTempGen::haschildren(const UniConfKey &key)
00157 {
00158     if (root)
00159     {
00160         UniConfValueTree *node = root->find(key);
00161         return node != NULL && node->haschildren();
00162     }
00163     return false;
00164 }
00165 
00166 
00167 UniConfGen::Iter *UniTempGen::iterator(const UniConfKey &key)
00168 {
00169     if (root)
00170     {
00171         UniConfValueTree *node = root->find(key);
00172         if (node)
00173         {
00174             ListIter *it = new ListIter(this);
00175             UniConfValueTree::Iter i(*node);
00176             for (i.rewind(); i.next(); )
00177                 it->add(i->key(), i->value());
00178             return it;
00179         }
00180     }
00181     return NULL;
00182 }
00183 
00184 
00185 void UniTempGen::commit()
00186 {
00187     UniConfGen::commit();
00188 }
00189 
00190 
00191 bool UniTempGen::refresh()
00192 {
00193     return UniConfGen::refresh();
00194 }