Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

uniconfkey.cc

Go to the documentation of this file.
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2002 Net Integration Technologies, Inc.
00004  *
00005  * A UniConf hierarchical key path abstraction.
00006  */
00007 #include "wvstream.h"
00008 #include "uniconfkey.h"
00009 #include <climits>
00010 #include <assert.h>
00011 #include <strutils.h>
00012 
00013 UniConfKey UniConfKey::EMPTY;
00014 UniConfKey UniConfKey::ANY("*");
00015 UniConfKey UniConfKey::RECURSIVE_ANY("...");
00016 
00017 
00018 UniConfKey::UniConfKey() :
00019     path("") // important to ensure we don't get nil paths everywhere
00020              // since for the moment we are not equipped to deal with them
00021 {
00022 }
00023 
00024 
00025 void UniConfKey::init(WvStringParm key)
00026 {
00027     assert(!key.isnull());
00028 
00029     // canonicalize the key by removing leading/trailing slashes, and
00030     // changing multiple slashes in a row to single slashes.
00031 
00032     if (key[0] == '/' || *(strchr(key, 0)-1) == '/' || strstr(key, "//"))
00033     {
00034         path.setsize(strlen(key) + 1);
00035         char *optr = path.edit();
00036         const char *iptr = key + int(strspn(key, "/"));
00037         
00038         while (*iptr)
00039         {
00040             if (*iptr == '/')
00041             {
00042                 // if there's more than one slash, this finds the last one:
00043                 iptr += strspn(iptr, "/") - 1;
00044                 
00045                 // if there's nothing after the slash, it's a terminating
00046                 // slash; stop now.
00047                 if (!iptr[1]) break;
00048                 
00049                 // if we get here, it's exactly one intermediate slash.
00050             }
00051             
00052             *optr++ = *iptr++;
00053         }
00054         
00055         *optr = 0;
00056     }
00057     else // easy: already in good shape!  Use WvString's optimized copying.
00058         path = key;
00059 }
00060 
00061 
00062 UniConfKey::UniConfKey(const UniConfKey &other) : path(other.path)
00063 {
00064 }
00065 
00066 
00067 UniConfKey::UniConfKey(const UniConfKey &_path, const UniConfKey &_key) 
00068 {
00069     if (!_path.path)
00070         path = _key;
00071     else if (!_key.path)
00072         path = _path;
00073     else
00074         path = WvString("%s/%s", _path, _key.path);
00075 }
00076 
00077 
00078 void UniConfKey::append(const UniConfKey &_key)
00079 {
00080     if (!path)
00081         path = _key.path;
00082     else if (!!_key.path)
00083         path = WvString("%s/%s", path, _key.path);
00084 }
00085 
00086 
00087 void UniConfKey::prepend(const UniConfKey &_key)
00088 {
00089     if (!path)
00090         path = _key.path;
00091     else if (!!_key.path)
00092         path = WvString("%s/%s", _key.path, path);
00093 }
00094 
00095 
00096 bool UniConfKey::isempty() const
00097 {
00098     return !path;
00099 }
00100 
00101 
00102 bool UniConfKey::iswild() const
00103 {
00104     // FIXME: not precise
00105     return strchr(path, '*') || strstr(path, "...");
00106 }
00107 
00108 
00109 int UniConfKey::numsegments() const
00110 {
00111     if (!path)
00112         return 0;
00113     
00114     int n = 1; // all non-null paths have at least one segment
00115     for (const char *cptr = path; *cptr; cptr++)
00116     {
00117         if (*cptr == '/')
00118             n++;
00119     }
00120     return n;
00121 }
00122 
00123 
00124 UniConfKey UniConfKey::segment(int n) const
00125 {
00126     return range(n, n + 1);
00127 }
00128 
00129 
00130 UniConfKey UniConfKey::first(int n) const
00131 {
00132     return range(0, n);
00133 }
00134 
00135 
00136 UniConfKey UniConfKey::last(int n) const
00137 {
00138     return range(numsegments() - n, INT_MAX);
00139 }
00140 
00141 
00142 UniConfKey UniConfKey::removefirst(int n) const
00143 {
00144     return range(n, INT_MAX);
00145 }
00146 
00147 
00148 UniConfKey UniConfKey::removelast(int n) const
00149 {
00150     return range(0, numsegments() - n);
00151 }
00152 
00153 
00154 UniConfKey UniConfKey::range(int i, int j) const
00155 {
00156     if (!path) return *this;
00157     
00158     const char *sptr, *eptr;
00159     int count;
00160     
00161     // find the beginning
00162     for (sptr = path, count = 0; *sptr && count < i; sptr++)
00163     {
00164         if (*sptr == '/')
00165             count++;
00166     }
00167     
00168     // find the end
00169     for (eptr = sptr; *eptr; eptr++)
00170     {
00171         if (*eptr == '/')
00172             count++;
00173         
00174         if (count >= j)
00175             break; // don't want to increment eptr
00176     }
00177     
00178     // optimization: they got the whole key!  Don't copy.
00179     if (sptr == path && !*eptr)
00180         return *this;
00181 
00182     // otherwise, return a new key.
00183     UniConfKey result; // avoid running the normalizing constructor
00184     int len = eptr - sptr;
00185     if (len)
00186     {
00187         result.path.setsize(len + 1);
00188         char *cptr = result.path.edit();
00189         strncpy(cptr, sptr, len);
00190         cptr[len] = 0;
00191     }
00192     return result;
00193 }
00194 
00195 
00196 WvString UniConfKey::printable() const
00197 {
00198     return path;
00199 }
00200 
00201 
00202 UniConfKey &UniConfKey::operator= (const UniConfKey &other)
00203 {
00204     path = other.path;
00205     return *this;
00206 }
00207 
00208 
00209 int UniConfKey::compareto(const UniConfKey &other) const
00210 {
00211     return strcasecmp(path, other.path);
00212 }
00213 
00214 
00215 bool UniConfKey::matches(const UniConfKey &pattern) const
00216 {
00217     // TODO: optimize this function
00218     if (*this == pattern)
00219         return true;
00220     
00221     UniConfKey head(pattern.first());
00222 
00223     // handle * wildcard
00224     if (head == UniConfKey::ANY)
00225     {
00226         if (isempty())
00227             return false;
00228         return removefirst().matches(pattern.removefirst());
00229     }
00230 
00231     // handle ... wildcard
00232     if (head == UniConfKey::RECURSIVE_ANY)
00233     {
00234         UniConfKey tail(pattern.removefirst());
00235         if (tail.isempty())
00236             return true; // recursively matches anything
00237         for (int n = 0; ; ++n)
00238         {
00239             UniConfKey part(removefirst(n));
00240             if (part.matches(tail))
00241                 return true;
00242             if (part.isempty())
00243                 break;
00244         }
00245         return false;
00246     }
00247     
00248     // no other wildcard arrangements currently supported
00249     return false;
00250 }
00251 
00252 
00253 bool UniConfKey::suborsame(const UniConfKey &key) const
00254 {
00255     UniConfKey k = key.first(numsegments());
00256 
00257     if (k == *this)
00258         return true;
00259     return false;
00260 }
00261 

Generated on Wed Dec 15 15:08:10 2004 for WvStreams by  doxygen 1.3.9.1