00001
00002
00003
00004
00005
00006
00007 #include "wvconfemu.h"
00008 #include "uniinigen.h"
00009 #include "wvstringtable.h"
00010 #include "wvfile.h"
00011 #include "strutils.h"
00012
00013
00014 #ifdef DEBUG_DEL_CALLBACK
00015 #include <execinfo.h>
00016 #endif
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 static int parse_wvconf_request(char *request, char *§ion,
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
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
00163
00164 if (!!iter->getme())
00165 {
00166
00167
00168
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, wv::bind(&WvConfEmu::notify, this, _1, _2),
00226 true);
00227 dirty = false;
00228 }
00229
00230
00231 WvConfEmu::~WvConfEmu()
00232 {
00233
00234
00235
00236
00237 #ifndef DEBUG_DEL_CALLBACK
00238 assert(callbacks.isempty());
00239 #else
00240 if (!callbacks.isempty())
00241 {
00242 WvList<CallbackInfo>::Iter i(callbacks);
00243
00244 fprintf(stderr, " *** leftover callbacks in WvConfEmu ***\n");
00245 for (i.rewind(); i.next(); )
00246 {
00247 fprintf(stderr, " - [%s]%s (%p)\n", i->section.cstr(),
00248 i->key.cstr(), i->cookie);
00249 }
00250 }
00251 #endif
00252
00253 uniconf.del_callback(this);
00254 }
00255
00256
00257 void WvConfEmu::zap()
00258 {
00259 uniconf.remove();
00260 }
00261
00262
00263 bool WvConfEmu::isclean() const
00264 {
00265 return isok() && !dirty;
00266 }
00267
00268
00269 bool WvConfEmu::isok() const
00270 {
00271 return !uniconf.isnull();
00272 }
00273
00274
00275 void WvConfEmu::load_file(WvStringParm filename)
00276 {
00277 UniConfRoot new_uniconf(WvString("ini:%s", filename));
00278
00279 hold = true;
00280 new_uniconf.copy(uniconf, true);
00281 hold = false;
00282 }
00283
00284
00285 void WvConfEmu::save(WvStringParm filename, int _create_mode)
00286 {
00287 UniConfRoot tmp_uniconf(new UniIniGen(filename, _create_mode), false);
00288
00289 uniconf.copy(tmp_uniconf, true);
00290
00291 tmp_uniconf.commit();
00292 }
00293
00294
00295 void WvConfEmu::save()
00296 {
00297 uniconf.commit();
00298 }
00299
00300
00301 void WvConfEmu::flush()
00302 {
00303 uniconf.commit();
00304 dirty = false;
00305 }
00306
00307
00308 WvConfigSectionEmu *WvConfEmu::operator[] (WvStringParm sect)
00309 {
00310 if (UniConfKey(sect).numsegments() != 1)
00311 return NULL;
00312
00313 WvConfigSectionEmu* section = sections[sect];
00314
00315 if (!section && uniconf[sect].exists())
00316 {
00317 section = new WvConfigSectionEmu(uniconf[sect], sect, &values);
00318 sections.add(section, true);
00319 }
00320
00321 return section;
00322 }
00323
00324
00325 void WvConfEmu::add_callback(WvConfCallback callback, void *userdata,
00326 WvStringParm section, WvStringParm key,
00327 void *cookie)
00328 {
00329 if (!callback)
00330 return;
00331
00332 WvList<CallbackInfo>::Iter i(callbacks);
00333 for (i.rewind(); i.next(); )
00334 {
00335 if (i->cookie == cookie
00336 && i->section == section
00337 && i->key == key)
00338 return;
00339 }
00340
00341 #ifdef DEBUG_DEL_CALLBACK
00342 void* trace[10];
00343 int count = backtrace(trace, sizeof(trace)/sizeof(trace[0]));
00344 char** tracedump = backtrace_symbols(trace, count);
00345 fprintf(stderr, "TRACE:add:%s:%s:%p", section.cstr(), key.cstr(), cookie);
00346 for (int i = 0; i < count; ++i)
00347 fprintf(stderr, ":%s", tracedump[i]);
00348 fprintf(stderr, "\n");
00349 free(tracedump);
00350 #endif
00351
00352 callbacks.append(new CallbackInfo(callback, userdata, section, key,
00353 cookie),
00354 true);
00355 }
00356
00357
00358 void WvConfEmu::del_callback(WvStringParm section, WvStringParm key, void *cookie)
00359 {
00360 WvList<CallbackInfo>::Iter i(callbacks);
00361
00362 assert(cookie);
00363
00364 for (i.rewind(); i.next(); )
00365 {
00366 if (i->cookie == cookie
00367 && i->section == section
00368 && i->key == key)
00369 {
00370 #ifdef DEBUG_DEL_CALLBACK
00371 fprintf(stderr, "TRACE:del:%s:%s:%p\n", section.cstr(), key.cstr(), cookie);
00372 #endif
00373 i.xunlink();
00374 }
00375 }
00376 }
00377
00378
00379 void WvConfEmu::add_setbool(bool *b, WvStringParm _section, WvStringParm _key)
00380 {
00381 add_callback(do_setbool, b, _section, _key, b);
00382 }
00383
00384
00385 void WvConfEmu::del_setbool(bool *b, WvStringParm _section, WvStringParm _key)
00386 {
00387 del_callback(_section, _key, b);
00388 }
00389
00390
00391 void WvConfEmu::add_addname(WvStringList *list, WvStringParm sect, WvStringParm ent)
00392 {
00393 add_callback(do_addname, list, sect, ent, list);
00394 }
00395
00396
00397 void WvConfEmu::del_addname(WvStringList *list,
00398 WvStringParm sect, WvStringParm ent)
00399 {
00400 del_callback(sect, ent, list);
00401 }
00402
00403
00404 WvString WvConfEmu::getraw(WvString wvconfstr, int &parse_error)
00405 {
00406 char *section, *entry, *value;
00407 parse_error = parse_wvconf_request(wvconfstr.edit(),
00408 section, entry, value);
00409
00410 if (parse_error)
00411 return WvString();
00412
00413 return get(section, entry, value);
00414 }
00415
00416
00417 int WvConfEmu::getint(WvStringParm section, WvStringParm entry, int def_val)
00418 {
00419 if (!section || !entry)
00420 return def_val;
00421
00422 return uniconf[section][entry].getmeint(def_val);
00423 }
00424
00425
00426 const char *WvConfEmu::get(WvStringParm section, WvStringParm entry,
00427 const char *def_val)
00428 {
00429 if (!section || !entry)
00430 return def_val;
00431
00432 WvString s(uniconf[section][entry].getme(def_val));
00433
00434
00435 WvString *sp = values[s];
00436 if (!sp) values.add(sp = new WvString(s), true);
00437 return sp->cstr();
00438 }
00439
00440 int WvConfEmu::fuzzy_getint(WvStringList §, WvStringParm entry,
00441 int def_val)
00442 {
00443 WvString def_str(def_val);
00444 return check_for_bool_string(fuzzy_get(sect, entry, def_str));
00445 }
00446
00447
00448 const char *WvConfEmu::fuzzy_get(WvStringList §, WvStringParm entry,
00449 const char *def_val)
00450 {
00451 WvStringList::Iter i(sect);
00452 WvStringTable cache(5);
00453 WvConfigSectionEmu *s;
00454
00455 for (i.rewind(); i.next(); )
00456 {
00457 for(s = (*this)[*i];
00458 s && !cache[s->name];
00459 s = (*s)["Inherits"] ? (*this)[(*s)["Inherits"]->value] : NULL)
00460 {
00461 const char *ret = s->get(entry);
00462 if (ret) return ret;
00463 cache.add(&s->name, false);
00464 }
00465 }
00466
00467 return def_val;
00468 }
00469
00470 void WvConfEmu::setraw(WvString wvconfstr, const char *&_value,
00471 int &parse_error)
00472 {
00473 char *section, *entry, *value;
00474 parse_error = parse_wvconf_request(wvconfstr.edit(),
00475 section, entry, value);
00476 if (!parse_error)
00477 {
00478 set(section, entry, value);
00479 _value = get(section, entry, value);
00480 }
00481 else
00482 _value = NULL;
00483 }
00484
00485
00486 void WvConfEmu::setint(WvStringParm section, WvStringParm entry, int value)
00487 {
00488 if (!!entry)
00489 uniconf[section][entry].setmeint(value);
00490 }
00491
00492
00493 void WvConfEmu::set(WvStringParm section, WvStringParm entry,
00494 const char *value)
00495 {
00496 if (!!entry)
00497 {
00498 if (value && value[0] != 0)
00499 uniconf[section][entry].setme(value);
00500 else
00501 uniconf[section][entry].setme(WvString::null);
00502 dirty = true;
00503 }
00504 }
00505
00506
00507 void WvConfEmu::maybesetint(WvStringParm section, WvStringParm entry,
00508 int value)
00509 {
00510 if (!!entry && !get(section, entry, NULL))
00511 setint(section, entry, value);
00512 }
00513
00514
00515 void WvConfEmu::maybeset(WvStringParm section, WvStringParm entry,
00516 const char *value)
00517 {
00518 if (!!entry && get(section, entry, 0) == 0)
00519 set(section, entry, value);
00520 }
00521
00522
00523 void WvConfEmu::delete_section(WvStringParm section)
00524 {
00525 uniconf[section].remove();
00526 dirty = true;
00527 }
00528
00529
00530 int WvConfEmu::check_for_bool_string(const char *s)
00531 {
00532 if (strcasecmp(s, "off") == 0
00533 || strcasecmp(s, "false") == 0
00534 || strncasecmp(s, "no", 2) == 0)
00535 return 0;
00536
00537 if (strcasecmp(s, "on") == 0
00538 || strcasecmp(s, "true") == 0
00539 || strcasecmp(s, "yes") == 0)
00540 return 1;
00541
00542
00543 return atoi(s);
00544 }
00545
00546
00547 void WvConfEmu::Iter::rewind()
00548 {
00549 iter.rewind();
00550 link.data = NULL;
00551 }
00552
00553
00554 WvLink *WvConfEmu::Iter::next()
00555 {
00556 link.data = NULL;
00557 while (link.data == NULL && iter.next())
00558 {
00559 link.data = static_cast<void*>(conf[iter->key()]);
00560 }
00561 if (link.data)
00562 {
00563 return &link;
00564 }
00565 return NULL;
00566 }
00567
00568
00569 WvConfigSectionEmu *WvConfEmu::Iter::ptr() const
00570 {
00571 return conf[iter->key()];
00572 }
00573