00001
00002
00003
00004
00005
00006
00007 #include "wvassert.h"
00008 #include "wvstream.h"
00009 #include "uniconfkey.h"
00010 #include "wvhash.h"
00011 #include <climits>
00012 #include <assert.h>
00013 #include <strutils.h>
00014
00015 unsigned WvHash(const UniConfKey &k)
00016 {
00017 int numsegs = k.right - k.left;
00018 unsigned result;
00019 switch (numsegs)
00020 {
00021 case 0:
00022 result = 0;
00023 break;
00024 case 1:
00025 result = WvHash(k.store->segments[k.left]);
00026 break;
00027 default:
00028 result = WvHash(k.store->segments[k.left])
00029 ^ WvHash(k.store->segments[k.right - 1])
00030 ^ numsegs;
00031 break;
00032 }
00033 return result;
00034 }
00035
00036
00037
00038 UniConfKey::Store UniConfKey::EMPTY_store(1, 1);
00039 UniConfKey::Store UniConfKey::ANY_store(1, 1, "*");
00040 UniConfKey::Store UniConfKey::RECURSIVE_ANY_store(1, 1, "...");
00041
00042 UniConfKey UniConfKey::EMPTY(&EMPTY_store, 0, 0);
00043 UniConfKey UniConfKey::ANY(&ANY_store, 0, 1);
00044 UniConfKey UniConfKey::RECURSIVE_ANY(&RECURSIVE_ANY_store, 0, 1);
00045
00046
00047 UniConfKey::Store::Store(int size, int _ref_count,
00048 WvStringParm key) :
00049 segments(size),
00050 ref_count(_ref_count)
00051 {
00052 if (!key)
00053 return;
00054
00055 WvStringList parts;
00056 parts.split(key, "/");
00057
00058 segments.resize(parts.count());
00059 WvStringList::Iter part(parts);
00060 for (part.rewind(); part.next(); )
00061 {
00062 if (!*part)
00063 continue;
00064 segments.append(*part);
00065 }
00066 if (!!key && key[key.len()-1] == '/' && segments.used() > 0)
00067 segments.append(Segment());
00068 }
00069
00070
00071 UniConfKey &UniConfKey::collapse()
00072 {
00073 if ((right - left == 1 && !store->segments[right-1])
00074 || right == left)
00075 {
00076 if (--store->ref_count == 0)
00077 delete store;
00078 store = &EMPTY_store;
00079 left = right = 0;
00080 ++store->ref_count;
00081 }
00082 return *this;
00083 }
00084
00085
00086 void UniConfKey::unique()
00087 {
00088 if (store->ref_count == 1)
00089 return;
00090 store->ref_count--;
00091 Store *old_store = store;
00092 store = new Store(right - left, 1);
00093 for (int i=left; i<right; ++i)
00094 store->segments.append(old_store->segments[i]);
00095 right -= left;
00096 left = 0;
00097 }
00098
00099 UniConfKey::UniConfKey(const UniConfKey &_path, const UniConfKey &_key) :
00100 store(new Store(_path.numsegments() + _key.numsegments() + 1, 1)),
00101 left(0),
00102 right(0)
00103 {
00104 bool hastrailingslash = _key.isempty() || _key.hastrailingslash();
00105 for (int i=_path.left; i<_path.right; ++i)
00106 {
00107 const Segment &segment = _path.store->segments[i];
00108 if (!segment)
00109 continue;
00110 store->segments.append(segment);
00111 ++right;
00112 }
00113 for (int j=_key.left; j<_key.right; ++j)
00114 {
00115 const Segment &segment = _key.store->segments[j];
00116 if (!segment)
00117 continue;
00118 store->segments.append(segment);
00119 ++right;
00120 }
00121 if (hastrailingslash)
00122 {
00123 store->segments.append("");
00124 ++right;
00125 }
00126 collapse();
00127 }
00128
00129
00130 void UniConfKey::append(const UniConfKey &_key)
00131 {
00132 bool hastrailingslash = _key.isempty() || _key.hastrailingslash();
00133 unique();
00134 store->segments.resize(right - left + _key.right - _key.left + 1);
00135 for (int j=_key.left; j<_key.right; ++j)
00136 {
00137 const Segment &segment = _key.store->segments[j];
00138 if (!segment)
00139 continue;
00140 store->segments.replace(right, segment);
00141 ++right;
00142 }
00143 if (hastrailingslash)
00144 {
00145 store->segments.replace(right, "");
00146 ++right;
00147 }
00148 collapse();
00149 }
00150
00151
00152 void UniConfKey::prepend(const UniConfKey &_key)
00153 {
00154 unique();
00155 int shift = 0;
00156 for (int j=_key.left; j<_key.right; ++j)
00157 {
00158 if (!!_key.store->segments[j])
00159 ++shift;
00160 }
00161 store->segments.resize(shift + right - left, shift);
00162 for (int j=_key.left; j<_key.right; ++j)
00163 {
00164 const Segment &segment = _key.store->segments[j];
00165 if (!segment)
00166 continue;
00167 store->segments.replace(left + j - _key.left, segment);
00168 ++right;
00169 }
00170 collapse();
00171 }
00172
00173
00174 bool UniConfKey::iswild() const
00175 {
00176 for (int i=left; i<right; ++i)
00177 if (store->segments[i].iswild())
00178 return true;
00179 return false;
00180 }
00181
00182
00183 UniConfKey UniConfKey::pop(int n)
00184 {
00185 if (n == 0)
00186 return UniConfKey();
00187 unique();
00188 if (n > right - left)
00189 n = right - left;
00190 if (n < 0)
00191 n = 0;
00192 int old_left = left;
00193 left += n;
00194 UniConfKey result(store, old_left, left);
00195 collapse();
00196 return result.collapse();
00197 }
00198
00199
00200 UniConfKey UniConfKey::range(int i, int j) const
00201 {
00202 if (j > right - left)
00203 j = right - left;
00204 if (i < 0)
00205 i = 0;
00206 if (j < i)
00207 j = i;
00208 return UniConfKey(store, left + i, left + j).collapse();
00209 }
00210
00211
00212 WvString UniConfKey::printable() const
00213 {
00214 switch (right - left)
00215 {
00216 case 0:
00217 return WvString::empty;
00218 case 1:
00219 return store->segments[left];
00220 default:
00221 {
00222 WvDynBuf buf;
00223 for (int i=left; i<right; ++i)
00224 {
00225 buf.putstr(store->segments[i]);
00226 if (i < right-1)
00227 buf.put('/');
00228 }
00229 return buf.getstr();
00230 }
00231 }
00232 }
00233
00234
00235 int UniConfKey::compareto(const UniConfKey &other) const
00236 {
00237 int i, j;
00238 for (i=left, j=other.left; i<right && j<other.right; ++i, ++j)
00239 {
00240 int val = strcasecmp(store->segments[i], other.store->segments[j]);
00241 if (val != 0)
00242 return val;
00243 }
00244 if (i == right)
00245 {
00246 if (j == other.right)
00247 return 0;
00248 else
00249 return -1;
00250 }
00251 else
00252 return 1;
00253 }
00254
00255
00256 bool UniConfKey::matches(const UniConfKey &pattern) const
00257 {
00258
00259 if (*this == pattern)
00260 return true;
00261
00262 UniConfKey head(pattern.first());
00263
00264
00265 if (head == UniConfKey::ANY)
00266 {
00267 if (isempty())
00268 return false;
00269 return removefirst().matches(pattern.removefirst());
00270 }
00271
00272
00273 if (head == UniConfKey::RECURSIVE_ANY)
00274 {
00275 UniConfKey tail(pattern.removefirst());
00276 if (tail.isempty())
00277 return true;
00278 for (int n = 0; ; ++n)
00279 {
00280 UniConfKey part(removefirst(n));
00281 if (part.matches(tail))
00282 return true;
00283 if (part.isempty())
00284 break;
00285 }
00286 return false;
00287 }
00288
00289
00290 return false;
00291 }
00292
00293
00294 bool UniConfKey::suborsame(const UniConfKey &key) const
00295 {
00296 int n = numsegments();
00297 if (hastrailingslash())
00298 n -= 1;
00299
00300 if (key.first(n) == first(n))
00301 return true;
00302 return false;
00303 }
00304
00305
00306 bool UniConfKey::suborsame(const UniConfKey &key, UniConfKey &subkey) const
00307 {
00308 int n = numsegments();
00309
00310
00311
00312 if (hastrailingslash())
00313 n -= 1;
00314
00315 if (key.first(n) == first(n))
00316 {
00317 subkey = key.removefirst(n);
00318 return true;
00319 }
00320 return false;
00321 }
00322
00323
00324 UniConfKey UniConfKey::subkey(const UniConfKey &key) const
00325 {
00326 UniConfKey answer;
00327 wvassert(suborsame(key, answer),
00328 "this = '%s'\nkey = '%s'", printable(), key);
00329 return answer;
00330 }