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