WvStreams
|
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