wvconfemu.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  *
00005  * Basic WvConf emulation layer for UniConf.
00006  */
00007 #include "wvconfemu.h"
00008 #include "uniinigen.h"
00009 #include "wvstringtable.h"
00010 #include "wvfile.h"
00011 #include "strutils.h"
00012 
00013 //#define DEBUG_DEL_CALLBACK 1
00014 #ifdef DEBUG_DEL_CALLBACK
00015 #include <execinfo.h>
00016 #endif
00017 
00018 /*
00019  * Parse the WvConf string "request"; pointers to the found section,
00020  * entry, and value fields are stored in *section, *entry, and *value
00021  * respectively, and request[] is modified.
00022  * 
00023  * For example, the string:
00024  *     [silly]billy=willy
00025  * is parsed into:
00026  *     section="silly"; entry="billy"; value="willy";
00027  * 
00028  * Returns 0 on success, -1 if the command is missing the '[', -2 if
00029  * the string is missing a ']', or -3 if the section or entry is
00030  * blank.  If a "value" is not found (ie. there is no equal sign
00031  * outside the [] brackets) this does not qualify as an error, but
00032  * *value is set to NULL.
00033 */
00034 static int parse_wvconf_request(char *request, char *&section,
00035                                 char *&entry, char *&value)
00036 {
00037     entry = value = NULL;
00038     
00039     section = strchr(request, '[');
00040     if (!section)
00041         return -1;
00042 
00043     section++;
00044     
00045     entry = strchr(section, ']');
00046     if (!entry)
00047         return -2;
00048 
00049     *entry++ = 0;
00050     
00051     value = strchr(entry, '=');
00052     if (value)
00053     {
00054         *value++ = 0;
00055         value = trim_string(value);
00056     }
00057     
00058     section = trim_string(section);
00059     entry = trim_string(entry);
00060     
00061     if (!*section)
00062         return -3;
00063     
00064     return 0;
00065 }
00066 
00067 
00068 static void do_setbool(void *userdata,
00069                        WvStringParm section, WvStringParm key,
00070                        WvStringParm oldval, WvStringParm newval)
00071 {
00072     bool* b = static_cast<bool*>(userdata);
00073 
00074     *b = true;
00075 }
00076 
00077 
00078 static void do_addname(void *userdata,
00079                        WvStringParm section, WvStringParm key,
00080                        WvStringParm oldval, WvStringParm newval)
00081 {
00082     if (!!key)
00083         (*(WvStringList *)userdata).append(new WvString(key), true);
00084 }
00085 
00086 
00087 WvConfigEntryEmu *WvConfigSectionEmu::operator[] (WvStringParm s)
00088 {
00089     WvConfigEntryEmu* entry = entries[s];
00090 
00091     if (uniconf[s].exists())
00092     {
00093         if (!entry)
00094         {
00095             entry = new WvConfigEntryEmu(s, uniconf[s].getme());
00096             entries.add(entry, true);
00097         }
00098         else
00099             entry->value = uniconf[s].getme();
00100     }
00101     else
00102         entry = NULL;
00103 
00104     return entry;
00105 }
00106 
00107 
00108 const char *WvConfigSectionEmu::get(WvStringParm entry, const char *def_val)
00109 {
00110     if (!entry)
00111         return def_val;
00112 
00113     WvString s(uniconf[entry].getme(def_val));
00114     
00115     // look it up in the cache
00116     WvString *sp = values[s];
00117     if (!sp) values.add(sp = new WvString(s), true);
00118     return sp->cstr();
00119 }
00120 
00121 
00122 void WvConfigSectionEmu::set(WvStringParm entry, WvStringParm value)
00123 {
00124     if (!!entry)
00125     {
00126         if (!!value)
00127             uniconf[entry].setme(value);
00128         else
00129             uniconf[entry].setme(WvString::null);
00130     }
00131 }
00132 
00133 
00134 void WvConfigSectionEmu::quick_set(WvStringParm entry, WvStringParm value)
00135 {
00136     uniconf[entry].setme(value);
00137 }
00138 
00139 
00140 bool WvConfigSectionEmu::isempty() const
00141 {
00142     return !uniconf.haschildren();
00143 }
00144 
00145 
00146 WvConfigSectionEmu::Iter::~Iter()
00147 {
00148 }
00149 
00150 
00151 void WvConfigSectionEmu::Iter::rewind()
00152 {
00153     iter.rewind();
00154     link.data = entry = NULL;
00155 }
00156 
00157 
00158 WvLink *WvConfigSectionEmu::Iter::next()
00159 {
00160     while (iter.next())
00161     {
00162         // WvConf-enabled code expects all set keys to be non-empty;
00163         // enforce this behaviour
00164         if (!!iter->getme())
00165         {
00166             /*
00167              * FIXME: if the WvConfEmu is not at the root of the
00168              * UniConf tree, this will give an incorrect result.
00169              */
00170             entry = sect[iter->fullkey(sect.uniconf)];
00171             link.data = static_cast<void*>(entry);
00172             assert(entry);
00173             return &link;
00174         }
00175     }
00176 
00177     return NULL;
00178 }
00179 
00180 
00181 WvLink *WvConfigSectionEmu::Iter::cur()
00182 {
00183     return &link;
00184 }
00185 
00186 
00187 WvConfigEntryEmu *WvConfigSectionEmu::Iter::ptr() const
00188 {
00189     return entry;
00190 }
00191 
00192 
00193 void *WvConfigSectionEmu::Iter::vptr() const
00194 {
00195     return link.data;
00196 }
00197 
00198 
00199 void WvConfEmu::notify(const UniConf &_uni, const UniConfKey &_key)
00200 {
00201     WvString section(_key.first());
00202     WvString key(_key.removefirst());
00203 
00204     if (hold)
00205         return;
00206 
00207     WvString value = uniconf[section][key].getme("");
00208     
00209     WvList<CallbackInfo>::Iter i(callbacks);
00210     for (i.rewind(); i.next(); )
00211     {
00212         if ((!i->section || !strcasecmp(i->section, section))
00213             && (!i->key || !strcasecmp(i->key, key)))
00214         {
00215             i->callback(i->userdata, section, key, WvString(), value);
00216         }
00217     }
00218 }
00219 
00220 
00221 WvConfEmu::WvConfEmu(const UniConf &_uniconf)
00222     : sections(42), hold(false), values(420), uniconf(_uniconf)
00223 {
00224     wvauthd = NULL;
00225     uniconf.add_callback(this,
00226                          UniConfCallback(this, &WvConfEmu::notify),
00227                          true);
00228     dirty = false;
00229 }
00230 
00231 
00232 WvConfEmu::~WvConfEmu()
00233 {
00234     // things will "work" if you don't empty the callback list before
00235     // deleting the WvConfEmu, but they probably won't work the way you
00236     // think they will. (ie. someone might be using a temporary WvConfEmu
00237     // and think his callbacks will stick around; they won't!)
00238 #ifndef DEBUG_DEL_CALLBACK
00239     assert(callbacks.isempty());
00240 #else
00241     if (!callbacks.isempty())
00242     {
00243         WvList<CallbackInfo>::Iter i(callbacks);
00244 
00245         fprintf(stderr, " *** leftover callbacks in WvConfEmu ***\n");
00246         for (i.rewind(); i.next(); )
00247         {
00248             fprintf(stderr, "     - [%s]%s (%p)\n", i->section.cstr(), 
00249                     i->key.cstr(), i->cookie);
00250         }
00251     }
00252 #endif
00253 
00254     uniconf.del_callback(this);
00255 }
00256 
00257 
00258 void WvConfEmu::zap()
00259 {
00260     uniconf.remove();
00261 }
00262 
00263 
00264 bool WvConfEmu::isclean() const
00265 {
00266     return isok() && !dirty;
00267 }
00268 
00269 
00270 bool WvConfEmu::isok() const
00271 {
00272     return !uniconf.isnull();
00273 }
00274 
00275 
00276 void WvConfEmu::load_file(WvStringParm filename)
00277 {
00278     UniConfRoot new_uniconf(WvString("ini:%s", filename));
00279 
00280     hold = true;
00281     new_uniconf.copy(uniconf, true);
00282     hold = false;
00283 }
00284 
00285 
00286 void WvConfEmu::save(WvStringParm filename, int _create_mode)
00287 {
00288     UniConfRoot tmp_uniconf(new UniIniGen(filename, _create_mode), false);
00289 
00290     uniconf.copy(tmp_uniconf, true);
00291 
00292     tmp_uniconf.commit();
00293 }
00294 
00295 
00296 void WvConfEmu::save()
00297 {
00298     uniconf.commit();
00299 }
00300 
00301 
00302 void WvConfEmu::flush()
00303 {
00304     uniconf.commit();
00305     dirty = false;
00306 }
00307 
00308 
00309 WvConfigSectionEmu *WvConfEmu::operator[] (WvStringParm sect)
00310 {
00311     if (UniConfKey(sect).numsegments() != 1)
00312         return NULL;
00313 
00314     WvConfigSectionEmu* section = sections[sect];
00315 
00316     if (!section && uniconf[sect].exists())
00317     {
00318         section = new WvConfigSectionEmu(uniconf[sect], sect, &values);
00319         sections.add(section, true);
00320     }
00321 
00322     return section;
00323 }
00324 
00325 
00326 void WvConfEmu::add_callback(WvConfCallback callback, void *userdata,
00327                              WvStringParm section, WvStringParm key,
00328                              void *cookie)
00329 {
00330     if (!callback)
00331         return;
00332 
00333     WvList<CallbackInfo>::Iter i(callbacks);
00334     for (i.rewind(); i.next(); )
00335     {
00336         if (i->cookie == cookie
00337             && i->section == section
00338             && i->key == key)
00339             return;
00340     }
00341 
00342 #ifdef DEBUG_DEL_CALLBACK
00343     void* trace[10];
00344     int count = backtrace(trace, sizeof(trace)/sizeof(trace[0]));
00345     char** tracedump = backtrace_symbols(trace, count);
00346     fprintf(stderr, "TRACE:add:%s:%s:%p", section.cstr(), key.cstr(), cookie);
00347     for (int i = 0; i < count; ++i)
00348         fprintf(stderr, ":%s", tracedump[i]);
00349     fprintf(stderr, "\n");
00350     free(tracedump);
00351 #endif
00352 
00353     callbacks.append(new CallbackInfo(callback, userdata, section, key,
00354                                       cookie),
00355                      true);
00356 }
00357 
00358 
00359 void WvConfEmu::del_callback(WvStringParm section, WvStringParm key, void *cookie)
00360 {
00361     WvList<CallbackInfo>::Iter i(callbacks);
00362 
00363     assert(cookie);
00364 
00365     for (i.rewind(); i.next(); )
00366     {
00367         if (i->cookie == cookie
00368             && i->section == section
00369             && i->key == key)
00370         {
00371 #ifdef DEBUG_DEL_CALLBACK
00372             fprintf(stderr, "TRACE:del:%s:%s:%p\n", section.cstr(), key.cstr(), cookie);
00373 #endif
00374             i.xunlink();
00375         }
00376     }
00377 }
00378 
00379 
00380 void WvConfEmu::add_setbool(bool *b, WvStringParm _section, WvStringParm _key)
00381 {
00382     add_callback(do_setbool, b, _section, _key, b);
00383 }
00384 
00385 
00386 void WvConfEmu::del_setbool(bool *b, WvStringParm _section, WvStringParm _key)
00387 {
00388     del_callback(_section, _key, b);
00389 }
00390 
00391 
00392 void WvConfEmu::add_addname(WvStringList *list, WvStringParm sect, WvStringParm ent)
00393 {
00394     add_callback(do_addname, list, sect, ent, list);
00395 }
00396 
00397 
00398 void WvConfEmu::del_addname(WvStringList *list,
00399                             WvStringParm sect, WvStringParm ent)
00400 {
00401     del_callback(sect, ent, list);
00402 }
00403 
00404 
00405 WvString WvConfEmu::getraw(WvString wvconfstr, int &parse_error)
00406 {
00407     char *section, *entry, *value;
00408     parse_error = parse_wvconf_request(wvconfstr.edit(),
00409                                        section, entry, value);
00410 
00411     if (parse_error)
00412         return WvString();
00413 
00414     return get(section, entry, value);
00415 }
00416 
00417 
00418 int WvConfEmu::getint(WvStringParm section, WvStringParm entry, int def_val)
00419 {
00420     if (!section || !entry)
00421         return def_val;
00422 
00423     return uniconf[section][entry].getmeint(def_val);
00424 }
00425 
00426 
00427 const char *WvConfEmu::get(WvStringParm section, WvStringParm entry,
00428                            const char *def_val)
00429 {
00430     if (!section || !entry)
00431         return def_val;
00432 
00433     WvString s(uniconf[section][entry].getme(def_val));
00434     
00435     // look it up in the cache
00436     WvString *sp = values[s];
00437     if (!sp) values.add(sp = new WvString(s), true);
00438     return sp->cstr();
00439 }
00440 
00441 int WvConfEmu::fuzzy_getint(WvStringList &sect, WvStringParm entry,
00442                             int def_val)
00443 {
00444     WvString def_str(def_val);
00445     return check_for_bool_string(fuzzy_get(sect, entry, def_str));
00446 }
00447 
00448 
00449 const char *WvConfEmu::fuzzy_get(WvStringList &sect, WvStringParm entry,
00450                                  const char *def_val)
00451 {
00452     WvStringList::Iter i(sect);
00453     WvStringTable cache(5);
00454     WvConfigSectionEmu *s;
00455 
00456     for (i.rewind(); i.next(); )
00457     {
00458         for(s = (*this)[*i];
00459             s && !cache[s->name];
00460             s = (*s)["Inherits"] ? (*this)[(*s)["Inherits"]->value] : NULL)
00461         {
00462             const char *ret = s->get(entry);
00463             if (ret) return ret;
00464             cache.add(&s->name, false);
00465         }
00466     }
00467 
00468     return def_val;
00469 }
00470 
00471 void WvConfEmu::setraw(WvString wvconfstr, const char *&_value,
00472                        int &parse_error)
00473 {
00474     char *section, *entry, *value;
00475     parse_error = parse_wvconf_request(wvconfstr.edit(),
00476                                        section, entry, value);
00477     if (!parse_error)
00478     {
00479         set(section, entry, value);
00480         _value = get(section, entry, value);
00481     }
00482     else
00483         _value = NULL;
00484 }
00485 
00486 
00487 void WvConfEmu::setint(WvStringParm section, WvStringParm entry, int value)
00488 {
00489     if (!!entry)
00490         uniconf[section][entry].setmeint(value);
00491 }
00492 
00493 
00494 void WvConfEmu::set(WvStringParm section, WvStringParm entry,
00495                     const char *value)
00496 {
00497     if (!!entry)
00498     {
00499         if (value && value[0] != 0)
00500             uniconf[section][entry].setme(value);
00501         else
00502             uniconf[section][entry].setme(WvString::null);
00503         dirty = true;
00504     }
00505 }
00506 
00507 
00508 void WvConfEmu::maybesetint(WvStringParm section, WvStringParm entry,
00509                             int value)
00510 {
00511     if (!!entry && !get(section, entry, NULL))
00512         setint(section, entry, value);
00513 }
00514 
00515 
00516 void WvConfEmu::maybeset(WvStringParm section, WvStringParm entry,
00517                          const char *value)
00518 {
00519     if (!!entry && get(section, entry, 0) == 0)
00520         set(section, entry, value);
00521 }
00522 
00523 
00524 void WvConfEmu::delete_section(WvStringParm section)
00525 {
00526     uniconf[section].remove();
00527     dirty = true;
00528 }
00529 
00530 
00531 int WvConfEmu::check_for_bool_string(const char *s)
00532 {
00533     if (strcasecmp(s, "off") == 0
00534         || strcasecmp(s, "false") == 0
00535         || strncasecmp(s, "no", 2) == 0)   // also handles "none"
00536         return 0;
00537 
00538     if (strcasecmp(s, "on") == 0
00539         || strcasecmp(s, "true") == 0
00540         || strcasecmp(s, "yes") == 0)
00541         return 1;
00542 
00543     // not a special bool case, so just return the number
00544     return atoi(s);
00545 }
00546 
00547 
00548 void WvConfEmu::Iter::rewind()
00549 {
00550     iter.rewind();
00551     link.data = NULL;
00552 }
00553 
00554 
00555 WvLink *WvConfEmu::Iter::next()
00556 {
00557     link.data = NULL;
00558     while (link.data == NULL && iter.next())
00559     {
00560         link.data = static_cast<void*>(conf[iter->key()]);
00561     }
00562     if (link.data)
00563     {
00564         return &link;
00565     }
00566     return NULL;
00567 }
00568 
00569 
00570 WvConfigSectionEmu *WvConfEmu::Iter::ptr() const
00571 {
00572     return conf[iter->key()];
00573 }
00574 

Generated on Wed Jul 12 17:53:20 2006 for WvStreams by  doxygen 1.4.7