WvStreams
uniconfgen.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2002 Net Integration Technologies, Inc.
00004  * 
00005  * An abstract data container that backs a UniConf tree.
00006  */
00007 #include "uniconfgen.h"
00008 #include "strutils.h"
00009 
00010 // FIXME: interfaces (IUniConfGen) shouldn't have implementations!
00011 IUniConfGen::~IUniConfGen()
00012 {
00013 }
00014 
00015 UUID_MAP_BEGIN(UniConfGen)
00016   UUID_MAP_ENTRY(IObject)
00017   UUID_MAP_ENTRY(IUniConfGen)
00018   UUID_MAP_END
00019 
00020 UniConfGen::UniConfGen()
00021 {
00022     hold_nesting = 0;
00023 }
00024 
00025 
00026 UniConfGen::~UniConfGen()
00027 {
00028     assert(cblist.isempty());
00029 }
00030 
00031 
00032 void UniConfGen::hold_delta()
00033 {
00034     hold_nesting++;
00035 }
00036 
00037 
00038 void UniConfGen::unhold_delta()
00039 {
00040     assert(hold_nesting > 0);
00041     if (hold_nesting == 1)
00042         flush_delta();
00043     hold_nesting--;
00044 }
00045 
00046 
00047 void UniConfGen::clear_delta()
00048 {
00049     deltas.zap();
00050 }
00051 
00052 
00053 void UniConfGen::flush_delta()
00054 {
00055     UniConfPairList::Iter it(deltas);
00056     for (;;)
00057     {
00058         it.rewind();
00059         if (! it.next())
00060             break;
00061 
00062         UniConfKey key((*it).key());
00063         WvString value((*it).value());
00064 
00065         it.xunlink();
00066         dispatch_delta(key, value);
00067     }
00068 }
00069 
00070 
00071 void UniConfGen::dispatch_delta(const UniConfKey &key, WvStringParm value)
00072 {
00073     cblist(key, value);
00074 }
00075 
00076 
00077 void UniConfGen::delta(const UniConfKey &key, WvStringParm value)
00078 {
00079     if (hold_nesting == 0)
00080     {
00081         // not nested, dispatch immediately
00082         dispatch_delta(key, value);
00083     }
00084     else
00085     {
00086         hold_delta();
00087         deltas.add(new UniConfPair(key, value), true);
00088         unhold_delta();
00089     }
00090 }
00091 
00092 
00093 void UniConfGen::setv_naive(const UniConfPairList &pairs)
00094 {
00095     UniConfPairList::Iter pair(pairs);
00096     for (pair.rewind(); pair.next(); )
00097         set(pair->key(), pair->value());
00098 }
00099 
00100 
00101 bool UniConfGen::haschildren(const UniConfKey &key)
00102 {
00103     bool children = false;
00104     
00105     hold_delta();
00106     
00107     Iter *it = iterator(key);
00108     if (it)
00109     {
00110         it->rewind();
00111         if (it->next()) children = true;
00112         delete it;
00113     }
00114     
00115     unhold_delta();
00116     return children;
00117 }
00118 
00119 
00120 bool UniConfGen::exists(const UniConfKey &key)
00121 {
00122     return !get(key).isnull();
00123 }
00124 
00125 
00126 int UniConfGen::str2int(WvStringParm value, int defvalue) const
00127 {
00128     // also recognize bool strings as integers
00129     const char *strs[] = {
00130         "true", "yes", "on", "enabled",
00131         "false", "no", "off", "disabled"
00132     };
00133     const size_t numtruestrs = 4;
00134 
00135     if (!value.isnull())
00136     {
00137         // try to recognize an integer
00138         char *end;
00139         int num = strtol(value.cstr(), &end, 0);
00140         if (end != value.cstr())
00141             return num; // was a valid integer
00142         
00143         // try to recognize a special string
00144         for (size_t i = 0; i < sizeof(strs) / sizeof(const char*); ++i)
00145             if (strcasecmp(value, strs[i]) == 0)
00146                 return i < numtruestrs;
00147     }
00148     return defvalue;
00149 }
00150 
00151 
00152 bool UniConfGen::isok()
00153 {
00154     return true;
00155 }
00156 
00157 
00158 void UniConfGen::add_callback(void *cookie,
00159                               const UniConfGenCallback &callback)
00160 {
00161     cblist.add(callback, cookie);
00162 }
00163 
00164 
00165 void UniConfGen::del_callback(void *cookie)
00166 {
00167     cblist.del(cookie);
00168 }
00169 
00170 
00171 
00172 class _UniConfGenRecursiveIter : public IUniConfGen::Iter
00173 {
00174     WvList<IUniConfGen::Iter> itlist;
00175     IUniConfGen *gen;
00176     UniConfKey top, current;
00177     bool sub_next;
00178     
00179 public:
00180     _UniConfGenRecursiveIter(IUniConfGen *_gen, const UniConfKey &_top)
00181         : top(_top)
00182     {
00183         gen = _gen;
00184         sub_next = false;
00185     }
00186     
00187     virtual ~_UniConfGenRecursiveIter() { }
00188 
00189     virtual void rewind()
00190     {
00191         current = "";
00192         sub_next = false;
00193         itlist.zap();
00194         
00195         Iter *subi = gen->iterator(top);
00196         if (subi)
00197         {
00198             subi->rewind();
00199             itlist.prepend(subi, true);
00200         }
00201     }
00202 
00203     virtual bool next()
00204     {
00205         //assert(!itlist.isempty()); // trying to seek past the end is illegal!
00206         
00207         if (sub_next)
00208         {
00209             sub_next = false;
00210             
00211             UniConfKey subkey(itlist.first()->key());
00212             UniConfKey newkey(current, subkey);
00213             //fprintf(stderr, "subiter: '%s'\n", newkey.cstr());
00214             Iter *newsub = gen->iterator(UniConfKey(top, newkey));
00215             if (newsub)
00216             {
00217                 current.append(subkey);
00218                 //fprintf(stderr, "current is now: '%s'\n", current.cstr());
00219                 newsub->rewind();
00220                 itlist.prepend(newsub, true);
00221             }
00222         }
00223         
00224         WvList<IUniConfGen::Iter>::Iter i(itlist);
00225         for (i.rewind(); i.next(); )
00226         {
00227             if (i->next()) // NOTE: not the same as i.next()
00228             {
00229                 // set up so next time, we go into its subtree
00230                 sub_next = true;
00231                 return true;
00232             }
00233             
00234             // otherwise, this iterator is empty; move up the tree
00235             current = current.removelast();
00236             //fprintf(stderr, "current is now: '%s'\n", current.cstr());
00237             i.xunlink();
00238         }
00239         
00240         // all done!
00241         return false;
00242     }
00243 
00244     virtual UniConfKey key() const
00245     {
00246         //fprintf(stderr, "current is now: '%s'\n", current.cstr());
00247         if (!itlist.isempty())
00248             return UniConfKey(current, itlist.first()->key());
00249         else
00250             return current;
00251     }
00252     
00253     virtual WvString value() const
00254     {
00255         return gen->get(UniConfKey(top, key()));
00256     }
00257 };
00258 
00259 
00260 UniConfGen::Iter *UniConfGen::recursiveiterator(const UniConfKey &key)
00261 {
00262     return new _UniConfGenRecursiveIter(this, key);
00263 }
00264 
00265