00001
00002
00003
00004
00005
00006
00007 #include "unimountgen.h"
00008 #include "wvmoniker.h"
00009 #include "wvhash.h"
00010 #include "wvstrutils.h"
00011 #include "unilistiter.h"
00012 #include "wvstringtable.h"
00013 #include <assert.h>
00014
00015
00016
00017 UniMountGen::UniMountGen()
00018 {
00019
00020 }
00021
00022
00023 UniMountGen::~UniMountGen()
00024 {
00025 zap();
00026 }
00027
00028
00029 WvString UniMountGen::get(const UniConfKey &key)
00030 {
00031 UniGenMount *found = findmount(key);
00032 if (!found)
00033 {
00034
00035
00036 if (has_subkey(key, NULL))
00037 return "";
00038
00039 return WvString::null;
00040 }
00041
00042 return found->gen->get(trimkey(found->key, key));
00043 }
00044
00045
00046 void UniMountGen::set(const UniConfKey &key, WvStringParm value)
00047 {
00048 UniGenMount *found = findmount(key);
00049 if (!found)
00050 return;
00051 found->gen->set(trimkey(found->key, key), value);
00052 }
00053
00054
00055 struct UniMountGen::UniGenMountPairs
00056 {
00057 UniGenMount *mount;
00058 WvString key;
00059 UniConfPairList pairs;
00060
00061 UniGenMountPairs(UniGenMount *_mount)
00062 : mount(_mount)
00063 {
00064 if (mount)
00065 key = mount->key;
00066 }
00067 };
00068
00069
00070 void UniMountGen::setv(const UniConfPairList &pairs)
00071 {
00072 UniGenMountPairsDict mountpairs(mounts.count());
00073
00074 {
00075 MountList::Iter m(mounts);
00076 for (m.rewind(); m.next(); )
00077 mountpairs.add(new UniGenMountPairs(m.ptr()), true);
00078 }
00079
00080 {
00081 UniConfPairList::Iter pair(pairs);
00082 for (pair.rewind(); pair.next(); )
00083 {
00084 UniGenMount *found = findmount(pair->key());
00085 if (!found)
00086 continue;
00087 UniConfPair *trimmed = new UniConfPair(trimkey(found->key,
00088 pair->key()),
00089 pair->value());
00090 mountpairs[found->key]->pairs.add(trimmed, true);
00091 }
00092 }
00093
00094 UniGenMountPairsDict::Iter i(mountpairs);
00095 for (i.rewind(); i.next(); )
00096 i->mount->gen->setv(i->pairs);
00097 }
00098
00099
00100 bool UniMountGen::exists(const UniConfKey &key)
00101 {
00102 UniGenMount *found = findmount(key);
00103
00104 if (found && found->gen->exists(trimkey(found->key, key)))
00105 return true;
00106 else
00107
00108
00109 return has_subkey(key, found);
00110 }
00111
00112
00113 bool UniMountGen::haschildren(const UniConfKey &key)
00114 {
00115 UniGenMount *found = findmount(key);
00116
00117 if (found && found->gen->haschildren(trimkey(found->key, key)))
00118 return true;
00119
00120
00121
00122
00123 return has_subkey(key, found);
00124 }
00125
00126
00127 bool UniMountGen::has_subkey(const UniConfKey &key, UniGenMount *found)
00128 {
00129 MountList::Iter i(mounts);
00130 for (i.rewind(); i.next(); )
00131 {
00132 if (key.suborsame(i->key) && key < i->key)
00133 {
00134
00135
00136 return true;
00137 }
00138
00139
00140
00141 if (found && (i->gen == found->gen))
00142 break;
00143 }
00144
00145
00146 return false;
00147 }
00148
00149 bool UniMountGen::refresh()
00150 {
00151 hold_delta();
00152
00153 bool result = true;
00154
00155 MountList::Iter i(mounts);
00156 for (i.rewind(); i.next(); )
00157 result = result && i->gen->refresh();
00158
00159 unhold_delta();
00160 return result;
00161 }
00162
00163
00164 void UniMountGen::commit()
00165 {
00166 hold_delta();
00167
00168 MountList::Iter i(mounts);
00169 for (i.rewind(); i.next();)
00170 i->gen->commit();
00171
00172 unhold_delta();
00173 }
00174
00175
00176 IUniConfGen *UniMountGen::mount(const UniConfKey &key,
00177 WvStringParm moniker, bool refresh)
00178 {
00179 IUniConfGen *gen = wvcreate<IUniConfGen>(moniker);
00180 if (gen)
00181 mountgen(key, gen, refresh);
00182 #if DEBUG
00183 assert(gen && "Moniker doesn't get us a generator!");
00184 #endif
00185 if (gen && !gen->exists("/"))
00186 gen->set("/", "");
00187 return gen;
00188 }
00189
00190
00191 IUniConfGen *UniMountGen::mountgen(const UniConfKey &key,
00192 IUniConfGen *gen, bool refresh)
00193 {
00194 if (!gen)
00195 return NULL;
00196
00197 UniGenMount *newgen = new UniGenMount(gen, key);
00198 gen->add_callback(this,
00199 WvBoundCallback<UniConfGenCallback, const UniConfKey&>
00200 (this, &UniMountGen::gencallback, newgen->key));
00201
00202 hold_delta();
00203 delta(key, WvString());
00204
00205 makemount(key);
00206
00207 if (gen && refresh)
00208 gen->refresh();
00209
00210 mounts.prepend(newgen, true);
00211
00212 delta(key, get(key));
00213 unhold_delta();
00214 if (!gen->exists("/"))
00215 gen->set("/", "");
00216 return gen;
00217 }
00218
00219
00220 void UniMountGen::unmount(IUniConfGen *gen, bool commit)
00221 {
00222 if (!gen)
00223 return;
00224
00225 MountList::Iter i(mounts);
00226
00227 for (i.rewind(); i.next() && i->gen != gen; )
00228 ;
00229
00230 if (i->gen != gen)
00231 return;
00232
00233 hold_delta();
00234
00235 if (commit)
00236 gen->commit();
00237 gen->del_callback(this);
00238
00239 UniConfKey key(i->key);
00240 IUniConfGen *next = NULL;
00241
00242 delta(key, WvString());
00243
00244
00245
00246
00247
00248 i.xunlink();
00249 if (i.next())
00250 next = i->gen;
00251
00252 for (i.rewind(); i.next() && i->gen != next; )
00253 {
00254 if (key.suborsame(i->key) && key != i->key)
00255 {
00256 makemount(i->key);
00257 delta(i->key, get(i->key));
00258 }
00259 }
00260
00261 unhold_delta();
00262 }
00263
00264
00265 void UniMountGen::zap()
00266 {
00267 while (!mounts.isempty())
00268 unmount(mounts.first()->gen, false);
00269 }
00270
00271
00272 IUniConfGen *UniMountGen::whichmount(const UniConfKey &key,
00273 UniConfKey *mountpoint)
00274 {
00275 MountList::Iter i(mounts);
00276
00277 for (i.rewind(); i.next(); )
00278 {
00279 if (i->key.suborsame(key))
00280 {
00281 if (mountpoint)
00282 *mountpoint = i->key;
00283 return i->gen;
00284 }
00285 }
00286
00287 return NULL;
00288 }
00289
00290
00291 bool UniMountGen::ismountpoint(const UniConfKey &key)
00292 {
00293 MountList::Iter i(mounts);
00294
00295 for (i.rewind(); i.next(); )
00296 {
00297 if (i->key == key)
00298 return true;
00299 }
00300
00301 return false;
00302 }
00303
00304 static int wvstrcmp(const WvString *l, const WvString *r)
00305 {
00306 return strcmp(*l, *r);
00307 }
00308
00309 UniMountGen::Iter *UniMountGen::iterator(const UniConfKey &key)
00310 {
00311 UniGenMount *found = findmount(key);
00312 if (found)
00313 return found->gen->iterator(trimkey(found->key, key));
00314 else
00315 {
00316
00317
00318
00319 ListIter *it = new ListIter(this);
00320
00321 MountList::Iter i(mounts);
00322 WvStringTable t(10);
00323 for (i.rewind(); i.next(); )
00324 {
00325 if (key.numsegments() < i->key.numsegments()
00326 && key.suborsame(i->key))
00327 {
00328
00329
00330 UniConfKey k1 = i->key.first(key.numsegments() + 1);
00331 UniConfKey k2 = k1.last();
00332
00333 if (!t[k2])
00334 t.add(new WvString(k2), true);
00335 }
00336 }
00337 WvStringTable::Sorter s(t, &::wvstrcmp);
00338 for (s.rewind(); s.next();)
00339 it->add(*s);
00340
00341 return it;
00342 }
00343 }
00344
00345
00346
00347
00348
00349 UniMountGen::Iter *UniMountGen::recursiveiterator(const UniConfKey &key)
00350 {
00351 UniGenMount *found = findmountunder(key);
00352 if (found)
00353 return found->gen->recursiveiterator(trimkey(found->key, key));
00354 else
00355 return UniConfGen::recursiveiterator(key);
00356 }
00357
00358
00359 UniMountGen::UniGenMount *UniMountGen::findmount(const UniConfKey &key)
00360 {
00361
00362 MountList::Iter i(mounts);
00363 for (i.rewind(); i.next(); )
00364 {
00365 if (i->key.suborsame(key))
00366 return i.ptr();
00367 }
00368
00369 return NULL;
00370 }
00371
00372
00373 UniMountGen::UniGenMount *UniMountGen::findmountunder(const UniConfKey &key)
00374 {
00375 UniMountGen::UniGenMount * foundmount = NULL;
00376 int num_found_mounts = 0;
00377
00378
00379 MountList::Iter i(mounts);
00380 for (i.rewind(); i.next(); )
00381 {
00382
00383 if (i->key.suborsame(key) && !foundmount)
00384 {
00385 foundmount = i.ptr();
00386 num_found_mounts++;
00387 }
00388
00389 else if (key.suborsame(i->key))
00390 {
00391 num_found_mounts++;
00392 }
00393 }
00394
00395 if (num_found_mounts == 1 && foundmount)
00396 return foundmount;
00397
00398 return NULL;
00399 }
00400
00401
00402 void UniMountGen::gencallback(const UniConfKey &base, const UniConfKey &key,
00403 WvStringParm value)
00404 {
00405 delta(UniConfKey(base, key), value);
00406 }
00407
00408
00409 void UniMountGen::makemount(const UniConfKey &key)
00410 {
00411
00412
00413 UniConfKey::Iter i(key);
00414 UniConfKey points;
00415
00416 for (i.rewind(); i.next(); )
00417 {
00418 points.append(*i);
00419 if (get(points).isnull())
00420 set(points, "");
00421 }
00422
00423
00424
00425
00426 UniGenMount *found = findmount(points.removelast());
00427 if (!found)
00428 return;
00429
00430 if (found->gen->get(trimkey(found->key, key)).isnull())
00431 found->gen->set(trimkey(found->key, key), "");
00432 }