WvStreams
uniconf.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * Defines a hierarchical registry abstraction.  See uniconf.h.
00006  */
00007 #include "uniconf.h"
00008 #include "uniconfroot.h"
00009 #include "uniconfgen.h"
00010 #include "wvstream.h"
00011 #include <climits>
00012 #include <algorithm>
00013 #include <assert.h>
00014 
00015 
00016 UniConf::UniConf(UniConfRoot *root, const UniConfKey &fullkey)
00017     : xroot(root), xfullkey(fullkey)
00018 { 
00019     // nothing special
00020 }
00021     
00022 
00023 UniConf::UniConf() : xroot(NULL), xfullkey(UniConfKey::EMPTY)
00024 { 
00025     // nothing special
00026 }
00027 
00028 
00029 UniConf::UniConf(const UniConf &other)
00030     : xroot(other.xroot), xfullkey(other.xfullkey)
00031 { 
00032     // nothing special
00033 }
00034 
00035 
00036 UniConf::~UniConf()
00037 { 
00038     // nothing special
00039 }
00040 
00041 
00042 
00043 
00044 UniConfKey UniConf::fullkey(const UniConfKey &k) const
00045 {
00046     return k.subkey(xfullkey);
00047 }
00048 
00049 
00050 bool UniConf::exists() const
00051 {
00052     return xroot->mounts.exists(xfullkey);
00053 }
00054 
00055 
00056 bool UniConf::haschildren() const
00057 {
00058     return xroot->mounts.haschildren(xfullkey);
00059 }
00060 
00061 
00062 void UniConf::prefetch(bool recursive) const
00063 {
00064     xroot->mounts.prefetch(xfullkey, recursive);
00065 }
00066 
00067 
00068 WvString UniConf::getme(WvStringParm defvalue) const
00069 {
00070     WvString value = xroot->mounts.get(xfullkey);
00071     if (value.isnull())
00072         return defvalue;
00073     return value;
00074 }
00075 
00076 
00077 int UniConf::getmeint(int defvalue) const
00078 {
00079     return xroot->mounts.str2int(getme(), defvalue);
00080 }
00081 
00082 
00083 void UniConf::setme(WvStringParm value) const
00084 {
00085     xroot->mounts.set(xfullkey, value);
00086 }
00087 
00088 
00089 void UniConf::setmeint(int value) const
00090 {
00091     setme(WvString(value));
00092 }
00093 
00094 
00095 void UniConf::move(const UniConf &dst) const
00096 {
00097     dst.remove();
00098     copy(dst, true); 
00099     remove();
00100 }
00101 
00102 
00103 void UniConf::copy(const UniConf &dst, bool force) const
00104 {
00105     // do the main key first
00106     dst.setme(getme());
00107 
00108     // now all the children
00109     RecursiveIter i(*this);
00110     for (i.rewind(); i.next(); )
00111     {
00112         UniConf dst2 = dst[i->fullkey(*this)];
00113         if (force || dst2.getme().isnull())
00114             dst2.setme(i->getme());
00115     }
00116 }
00117 
00118 
00119 bool UniConf::refresh() const
00120 {
00121     return xroot->mounts.refresh();
00122 }
00123 
00124 
00125 void UniConf::commit() const
00126 {
00127     xroot->mounts.commit();
00128 }
00129 
00130 
00131 IUniConfGen *UniConf::mount(WvStringParm moniker, bool refresh) const
00132 {
00133     return xroot->mounts.mount(xfullkey, moniker, refresh);
00134 }
00135 
00136 
00137 IUniConfGen *UniConf::mountgen(IUniConfGen *gen, bool refresh) const
00138 {
00139     return xroot->mounts.mountgen(xfullkey, gen, refresh);
00140 }
00141 
00142 
00143 void UniConf::unmount(IUniConfGen *gen, bool commit) const
00144 {
00145     return xroot->mounts.unmount(gen, commit);
00146 }
00147 
00148 
00149 bool UniConf::ismountpoint() const
00150 {
00151     return xroot->mounts.ismountpoint(xfullkey);
00152 }
00153 
00154 
00155 IUniConfGen *UniConf::whichmount(UniConfKey *mountpoint) const
00156 {
00157     return xroot->mounts.whichmount(xfullkey, mountpoint);
00158 }
00159 
00160 
00161 bool UniConf::isok() const
00162 {
00163     IUniConfGen *gen = whichmount();
00164     return gen && gen->isok();
00165 }
00166 
00167 
00168 void UniConf::add_callback(void *cookie, const UniConfCallback &callback,
00169                            bool recurse) const
00170 {
00171     xroot->add_callback(cookie, xfullkey, callback, recurse);
00172 }
00173 
00174 
00175 void UniConf::del_callback(void *cookie, bool recurse) const
00176 {
00177     xroot->del_callback(cookie, xfullkey, recurse);
00178 }
00179 
00180 
00181 void UniConf::add_setbool(bool *flag, bool recurse) const
00182 {
00183     xroot->add_setbool(xfullkey, flag, recurse);
00184 }
00185 
00186 
00187 void UniConf::del_setbool(bool *flag, bool recurse) const
00188 {
00189     xroot->del_setbool(xfullkey, flag, recurse);
00190 }
00191 
00192 
00193 void UniConf::hold_delta()
00194 {
00195     xroot->mounts.hold_delta();
00196 }
00197 
00198 
00199 void UniConf::unhold_delta()
00200 {
00201     xroot->mounts.unhold_delta();
00202 }
00203 
00204 
00205 void UniConf::clear_delta()
00206 {
00207     xroot->mounts.clear_delta();
00208 }
00209 
00210 
00211 void UniConf::flush_delta()
00212 {
00213     xroot->mounts.flush_delta();
00214 }
00215 
00216 
00217 void UniConf::dump(WvStream &stream, bool everything) const
00218 {
00219     UniConf::RecursiveIter it(*this);
00220     for (it.rewind(); it.next(); )
00221     {
00222         WvString value(it->getme());
00223         if (everything || !!value)
00224             stream.print("%s = %s\n", it->fullkey(), value);
00225     }
00226 }
00227 
00228 
00229 
00230 /***** UniConf::Iter *****/
00231 
00232 UniConf::Iter::Iter(const UniConf &_top)
00233     : IterBase(_top)
00234 {
00235     it = _top.rootobj()->mounts.iterator(top.fullkey());
00236     if (!it) it = new UniConfGen::NullIter;
00237 }
00238 
00239 
00240 
00241 /***** UniConf::RecursiveIter *****/
00242 
00243 UniConf::RecursiveIter::RecursiveIter(const UniConf &_top)
00244     : IterBase(_top)
00245 {
00246     it = _top.rootobj()->mounts.recursiveiterator(top.fullkey());
00247     if (!it) it = new UniConfGen::NullIter;
00248 }
00249 
00250 
00251 /***** UniConf::XIter *****/
00252 
00253 UniConf::XIter::XIter(const UniConf &_top, const UniConfKey &pattern)
00254     : IterBase(_top), pathead(pattern.first()),
00255     pattail(pattern.removefirst()), subit(NULL), it(NULL), recit(NULL)
00256 {
00257     if (! pathead.iswild())
00258     {
00259         // optimization to collect as many consecutive non-wildcard
00260         // segments as possible in one go
00261         while (! pattail.isempty())
00262         {
00263             UniConfKey patnext(pattail.first());
00264             if (patnext.iswild())
00265                 break;
00266             pathead.append(patnext);
00267             pattail = pattail.removefirst();
00268         }
00269     }
00270 }
00271 
00272 
00273 UniConf::XIter::~XIter()
00274 {
00275     cleanup();
00276 }
00277 
00278 
00279 void UniConf::XIter::cleanup()
00280 {
00281     if (subit)
00282     {
00283         delete subit;
00284         subit = NULL;
00285     }
00286     if (it)
00287     {
00288         delete it;
00289         it = NULL;
00290     }
00291     if (recit)
00292     {
00293         delete recit;
00294         recit = NULL;
00295     }
00296 }
00297 
00298 
00299 void UniConf::XIter::rewind()
00300 {
00301     cleanup();
00302     ready = false;
00303 
00304     if (pathead.isempty())
00305     {
00306         current = top;
00307         ready = current.exists();
00308     }
00309     else if (pathead == UniConfKey::RECURSIVE_ANY)
00310     {
00311         recit = new UniConf::RecursiveIter(top);
00312         recit->rewind();
00313         if (UniConfKey::EMPTY.matches(pattail))
00314         {
00315             // pattern includes self
00316             current = top;
00317             ready = current.exists();
00318         }
00319     }
00320     else if (pathead == UniConfKey::ANY)
00321     {
00322         it = new UniConf::Iter(top);
00323         it->rewind();
00324     }
00325     else
00326     {
00327         // non-wildcard segment
00328         current = top[pathead];
00329         if (pattail.isempty())
00330         {
00331             // don't bother recursing if there are no deeper wildcard
00332             // elements (works together with optimization in constructor)
00333             ready = current.exists();
00334         }
00335         else
00336         {
00337             // more wildcards, setup recursion
00338             enter(current);
00339         }
00340     }
00341 }
00342 
00343 
00344 inline bool UniConf::XIter::qnext()
00345 {
00346     if (subit) // currently in a sub-iterator
00347     {
00348         bool found = subit->next();
00349         if (found)
00350         {
00351             current = **subit;
00352             return true;
00353         }
00354         else
00355         {
00356             // end of this sub-iterator
00357             delete subit;
00358             subit = NULL;
00359             return false;
00360         }
00361     }
00362     else // no sub-iterator at all
00363         return false;
00364 }
00365 
00366 
00367 void UniConf::XIter::enter(const UniConf &child)
00368 {
00369     subit = new UniConf::XIter(child, pattail);
00370     subit->rewind();
00371 }
00372 
00373 
00374 bool UniConf::XIter::next()
00375 {
00376     if (ready)
00377     {
00378         ready = false;
00379         return true;
00380     }
00381     while (!qnext())
00382     {
00383         // UniConfKey::ANY
00384         if (it && it->next())
00385         {
00386             /* Not needed for now since we don't match partial keys
00387             if (! pathead.matches(it->key()))
00388                 break;
00389             */
00390             enter(**it);
00391             continue;
00392         }
00393         // UniConfKey::RECURSIVE_ANY
00394         if (recit && recit->next())
00395         {
00396             enter(**recit);
00397             continue;
00398         }
00399         // anything else or finished
00400         return false;
00401     }
00402     
00403     // if we get here, qnext() returned true
00404     return true; 
00405 }
00406 
00407 
00408 
00409 /***** UniConf::SortedIterBase *****/
00410 
00411 UniConf::SortedIterBase::SortedIterBase(const UniConf &root,
00412     UniConf::SortedIterBase::Comparator comparator) 
00413     : IterBase(root), xcomparator(comparator), xkeys()
00414 {
00415 }
00416 
00417 
00418 UniConf::SortedIterBase::~SortedIterBase()
00419 {
00420     _purge();
00421 }
00422 
00423 
00424 int UniConf::SortedIterBase::defcomparator(const UniConf &a,
00425     const UniConf &b)
00426 {
00427     return a.fullkey().compareto(b.fullkey());
00428 }
00429 
00430 
00431 static UniConf::SortedIterBase::Comparator innercomparator = NULL;
00432 
00433 static bool wrapcomparator(const UniConf &a, const UniConf &b)
00434 {
00435     return innercomparator(a, b) < 0;
00436 }
00437 
00438 
00439 void UniConf::SortedIterBase::_purge()
00440 {
00441     count = xkeys.size();
00442     xkeys.clear();
00443 }
00444 
00445 
00446 void UniConf::SortedIterBase::_rewind()
00447 {
00448     index = 0;
00449     count = xkeys.size();
00450     
00451     // This code is NOT reentrant because qsort makes it too hard
00452     innercomparator = xcomparator;
00453     std::sort(xkeys.begin(), xkeys.end(), wrapcomparator);
00454 }
00455 
00456 
00457 bool UniConf::SortedIterBase::next()
00458 {
00459     if (index >= count)
00460         return false;
00461     current = xkeys[index];
00462     index += 1;
00463     return true;
00464 }