WvStreams
unidefgen.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2002 Net Integration Technologies, Inc.
00004  * 
00005  * UniDefGen is a UniConfGen for retrieving data with defaults
00006  */
00007 #include "unidefgen.h"
00008 #include "wvmoniker.h"
00009 //#include "wvstream.h"
00010 #include <ctype.h>
00011 #include <stdlib.h>
00012 
00013 #include "wvlinkerhack.h"
00014 
00015 WV_LINK(UniDefGen);
00016 
00017 
00018 // if 'obj' is non-NULL and is a UniConfGen, wrap that; otherwise wrap the
00019 // given moniker.
00020 static IUniConfGen *creator(WvStringParm s, IObject *_obj)
00021 {
00022     return new UniDefGen(wvcreate<IUniConfGen>(s, _obj));
00023 }
00024 
00025 // this name is too confusing.  We should deprecate it.
00026 static WvMoniker<IUniConfGen> reg("default", creator);
00027 
00028 // a better name for the same thing.
00029 static WvMoniker<IUniConfGen> reg2("wildcard", creator);
00030 
00031 
00032 UniConfKey UniDefGen::finddefault(const UniConfKey &key, char *p, char *q)
00033 {
00034     UniConfKey result;
00035     
00036     if (!p)
00037     {
00038         q++;
00039         if (inner() && inner()->exists(q))
00040             return q;
00041         else
00042             return UniConfKey();
00043     }
00044 
00045     // pop the first segment of p to r
00046     char *r = strchr(p, '/');
00047     if (r)
00048         *r++ = '\0';
00049 
00050     // append p to q
00051     char *s = strchr(q, '\0');
00052     *s++ = '/';
00053     *s = 0;
00054     q = strcat(q, p);
00055 
00056     // try this literal path
00057     result = finddefault(key, r, q);
00058     if (result.numsegments())
00059         return result;
00060 
00061     // replace what used to be p with a *
00062     *s++ = '*';
00063     *s = '\0';
00064     result = finddefault(key, r, q);
00065 
00066     if (r)
00067         *--r = '/';
00068     
00069     return result;
00070 }
00071 
00072 
00073 WvString UniDefGen::replacewildcard(const UniConfKey &key,
00074                             const UniConfKey &defkey, WvStringParm in)
00075 {
00076     // check if the result wants a wildcard ('*n')
00077     if (in.len() < 2 || in[0] != '*')
00078         return in;
00079 
00080     const char *s = in.cstr();
00081     int idx = atoi(s+1);
00082     if (idx == 0)
00083         return in;
00084 
00085     // search backwards for segment num of the n'th wildcard
00086     UniConfKey k(defkey);
00087     int loc = key.numsegments();
00088     for (int i = 0; i < idx; i++)
00089     {
00090         if (i != 0)
00091         {
00092             k = k.removelast();
00093             loc--;
00094         }
00095         while (!k.last().iswild())
00096         {
00097             k = k.removelast();
00098             loc--;
00099             if (k.isempty())
00100             {
00101                 // oops, ran out of segments!
00102                 return WvString();
00103             }
00104         }
00105     }
00106 
00107 
00108     // pull the literal from that segment num of the key
00109     return key.segment(loc-1);
00110 }
00111 
00112 
00113 bool UniDefGen::keymap(const UniConfKey &unmapped_key, UniConfKey &mapped_key)
00114 {
00115     WvString tmp_key(unmapped_key), tmp("");
00116     char *p = tmp_key.edit();
00117 
00118     tmp.setsize(strlen(tmp_key) * 2);
00119     char *q = tmp.edit();
00120     *q = '\0';
00121 
00122     mapped_key = finddefault(unmapped_key, p, q);
00123     if (!mapped_key.numsegments())
00124         mapped_key = unmapped_key;
00125     // fprintf(stderr, "mapping '%s' -> '%s'\n", key.cstr(), result.cstr());
00126     
00127     return true;
00128 }
00129 
00130 
00131 WvString UniDefGen::get(const UniConfKey &key)
00132 {
00133     UniConfKey mapped_key;
00134     if (keymap(key, mapped_key))
00135         return replacewildcard(key, mapped_key,
00136                             inner() ? inner()->get(mapped_key) : WvString());
00137     else
00138         return WvString::null;
00139 }
00140 
00141 
00142 void UniDefGen::set(const UniConfKey &key, WvStringParm value)
00143 {
00144     // no keymap() on set()
00145     if (inner())
00146         inner()->set(key, value);
00147 }