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,
00226 UniConfCallback(this, &WvConfEmu::notify),
00227 true);
00228 dirty = false;
00229 }
00230
00231
00232 WvConfEmu::~WvConfEmu()
00233 {
00234
00235
00236
00237
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
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 §, 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 §, 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)
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
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