2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * Basic WvConf emulation layer for UniConf.
9 #include "wvstringtable.h"
13 //#define DEBUG_DEL_CALLBACK 1
14 #ifdef DEBUG_DEL_CALLBACK
19 * Parse the WvConf string "request"; pointers to the found section,
20 * entry, and value fields are stored in *section, *entry, and *value
21 * respectively, and request[] is modified.
23 * For example, the string:
26 * section="silly"; entry="billy"; value="willy";
28 * Returns 0 on success, -1 if the command is missing the '[', -2 if
29 * the string is missing a ']', or -3 if the section or entry is
30 * blank. If a "value" is not found (ie. there is no equal sign
31 * outside the [] brackets) this does not qualify as an error, but
32 * *value is set to NULL.
34 static int parse_wvconf_request(char *request
, char *§ion
,
35 char *&entry
, char *&value
)
39 section
= strchr(request
, '[');
45 entry
= strchr(section
, ']');
51 value
= strchr(entry
, '=');
55 value
= trim_string(value
);
58 section
= trim_string(section
);
59 entry
= trim_string(entry
);
68 static void do_setbool(void *userdata
,
69 WvStringParm section
, WvStringParm key
,
70 WvStringParm oldval
, WvStringParm newval
)
72 bool* b
= static_cast<bool*>(userdata
);
78 static void do_addname(void *userdata
,
79 WvStringParm section
, WvStringParm key
,
80 WvStringParm oldval
, WvStringParm newval
)
83 (*(WvStringList
*)userdata
).append(new WvString(key
), true);
87 WvConfigEntryEmu
*WvConfigSectionEmu::operator[] (WvStringParm s
)
89 WvConfigEntryEmu
* entry
= entries
[s
];
91 if (uniconf
[s
].exists())
95 entry
= new WvConfigEntryEmu(s
, uniconf
[s
].getme());
96 entries
.add(entry
, true);
99 entry
->value
= uniconf
[s
].getme();
108 const char *WvConfigSectionEmu::get(WvStringParm entry
, const char *def_val
)
113 WvString
s(uniconf
[entry
].getme(def_val
));
115 // look it up in the cache
116 WvString
*sp
= values
[s
];
117 if (!sp
) values
.add(sp
= new WvString(s
), true);
122 void WvConfigSectionEmu::set(WvStringParm entry
, WvStringParm value
)
127 uniconf
[entry
].setme(value
);
129 uniconf
[entry
].setme(WvString::null
);
134 void WvConfigSectionEmu::quick_set(WvStringParm entry
, WvStringParm value
)
136 uniconf
[entry
].setme(value
);
140 bool WvConfigSectionEmu::isempty() const
142 return !uniconf
.haschildren();
146 WvConfigSectionEmu::Iter::~Iter()
151 void WvConfigSectionEmu::Iter::rewind()
154 link
.data
= entry
= NULL
;
158 WvLink
*WvConfigSectionEmu::Iter::next()
162 // WvConf-enabled code expects all set keys to be non-empty;
163 // enforce this behaviour
167 * FIXME: if the WvConfEmu is not at the root of the
168 * UniConf tree, this will give an incorrect result.
170 entry
= sect
[iter
->fullkey(sect
.uniconf
)];
171 link
.data
= static_cast<void*>(entry
);
181 WvLink
*WvConfigSectionEmu::Iter::cur()
187 WvConfigEntryEmu
*WvConfigSectionEmu::Iter::ptr() const
193 void *WvConfigSectionEmu::Iter::vptr() const
199 void WvConfEmu::notify(const UniConf
&_uni
, const UniConfKey
&_key
)
201 WvString
section(_key
.first());
202 WvString
key(_key
.removefirst());
207 WvString value
= uniconf
[section
][key
].getme("");
209 WvList
<CallbackInfo
>::Iter
i(callbacks
);
210 for (i
.rewind(); i
.next(); )
212 if ((!i
->section
|| !strcasecmp(i
->section
, section
))
213 && (!i
->key
|| !strcasecmp(i
->key
, key
)))
215 i
->callback(i
->userdata
, section
, key
, WvString(), value
);
221 WvConfEmu::WvConfEmu(const UniConf
&_uniconf
)
222 : sections(42), hold(false), values(420), uniconf(_uniconf
)
225 uniconf
.add_callback(this, wv::bind(&WvConfEmu::notify
, this, _1
, _2
),
231 WvConfEmu::~WvConfEmu()
233 // things will "work" if you don't empty the callback list before
234 // deleting the WvConfEmu, but they probably won't work the way you
235 // think they will. (ie. someone might be using a temporary WvConfEmu
236 // and think his callbacks will stick around; they won't!)
237 #ifndef DEBUG_DEL_CALLBACK
238 assert(callbacks
.isempty());
240 if (!callbacks
.isempty())
242 WvList
<CallbackInfo
>::Iter
i(callbacks
);
244 fprintf(stderr
, " *** leftover callbacks in WvConfEmu ***\n");
245 for (i
.rewind(); i
.next(); )
247 fprintf(stderr
, " - [%s]%s (%p)\n", i
->section
.cstr(),
248 i
->key
.cstr(), i
->cookie
);
253 uniconf
.del_callback(this);
257 void WvConfEmu::zap()
263 bool WvConfEmu::isclean() const
265 return isok() && !dirty
;
269 bool WvConfEmu::isok() const
271 return !uniconf
.isnull();
275 void WvConfEmu::load_file(WvStringParm filename
)
277 UniConfRoot
new_uniconf(WvString("ini:%s", filename
));
280 new_uniconf
.copy(uniconf
, true);
285 void WvConfEmu::save(WvStringParm filename
, int _create_mode
)
287 UniConfRoot
tmp_uniconf(new UniIniGen(filename
, _create_mode
), false);
289 uniconf
.copy(tmp_uniconf
, true);
291 tmp_uniconf
.commit();
295 void WvConfEmu::save()
301 void WvConfEmu::flush()
308 WvConfigSectionEmu
*WvConfEmu::operator[] (WvStringParm sect
)
310 if (UniConfKey(sect
).numsegments() != 1)
313 WvConfigSectionEmu
* section
= sections
[sect
];
315 if (!section
&& uniconf
[sect
].exists())
317 section
= new WvConfigSectionEmu(uniconf
[sect
], sect
, &values
);
318 sections
.add(section
, true);
325 void WvConfEmu::add_callback(WvConfCallback callback
, void *userdata
,
326 WvStringParm section
, WvStringParm key
,
332 WvList
<CallbackInfo
>::Iter
i(callbacks
);
333 for (i
.rewind(); i
.next(); )
335 if (i
->cookie
== cookie
336 && i
->section
== section
341 #ifdef DEBUG_DEL_CALLBACK
343 int count
= backtrace(trace
, sizeof(trace
)/sizeof(trace
[0]));
344 char** tracedump
= backtrace_symbols(trace
, count
);
345 fprintf(stderr
, "TRACE:add:%s:%s:%p", section
.cstr(), key
.cstr(), cookie
);
346 for (int i
= 0; i
< count
; ++i
)
347 fprintf(stderr
, ":%s", tracedump
[i
]);
348 fprintf(stderr
, "\n");
352 callbacks
.append(new CallbackInfo(callback
, userdata
, section
, key
,
358 void WvConfEmu::del_callback(WvStringParm section
, WvStringParm key
, void *cookie
)
360 WvList
<CallbackInfo
>::Iter
i(callbacks
);
364 for (i
.rewind(); i
.next(); )
366 if (i
->cookie
== cookie
367 && i
->section
== section
370 #ifdef DEBUG_DEL_CALLBACK
371 fprintf(stderr
, "TRACE:del:%s:%s:%p\n", section
.cstr(), key
.cstr(), cookie
);
379 void WvConfEmu::add_setbool(bool *b
, WvStringParm _section
, WvStringParm _key
)
381 add_callback(do_setbool
, b
, _section
, _key
, b
);
385 void WvConfEmu::del_setbool(bool *b
, WvStringParm _section
, WvStringParm _key
)
387 del_callback(_section
, _key
, b
);
391 void WvConfEmu::add_addname(WvStringList
*list
, WvStringParm sect
, WvStringParm ent
)
393 add_callback(do_addname
, list
, sect
, ent
, list
);
397 void WvConfEmu::del_addname(WvStringList
*list
,
398 WvStringParm sect
, WvStringParm ent
)
400 del_callback(sect
, ent
, list
);
404 WvString
WvConfEmu::getraw(WvString wvconfstr
, int &parse_error
)
406 char *section
, *entry
, *value
;
407 parse_error
= parse_wvconf_request(wvconfstr
.edit(),
408 section
, entry
, value
);
413 return get(section
, entry
, value
);
417 int WvConfEmu::getint(WvStringParm section
, WvStringParm entry
, int def_val
)
419 if (!section
|| !entry
)
422 return uniconf
[section
][entry
].getmeint(def_val
);
426 const char *WvConfEmu::get(WvStringParm section
, WvStringParm entry
,
429 if (!section
|| !entry
)
432 WvString
s(uniconf
[section
][entry
].getme(def_val
));
434 // look it up in the cache
435 WvString
*sp
= values
[s
];
436 if (!sp
) values
.add(sp
= new WvString(s
), true);
440 int WvConfEmu::fuzzy_getint(WvStringList
§
, WvStringParm entry
,
443 WvString
def_str(def_val
);
444 return check_for_bool_string(fuzzy_get(sect
, entry
, def_str
));
448 const char *WvConfEmu::fuzzy_get(WvStringList
§
, WvStringParm entry
,
451 WvStringList::Iter
i(sect
);
452 WvStringTable
cache(5);
453 WvConfigSectionEmu
*s
;
455 for (i
.rewind(); i
.next(); )
458 s
&& !cache
[s
->name
];
459 s
= (*s
)["Inherits"] ? (*this)[(*s
)["Inherits"]->value
] : NULL
)
461 const char *ret
= s
->get(entry
);
463 cache
.add(&s
->name
, false);
470 void WvConfEmu::setraw(WvString wvconfstr
, const char *&_value
,
473 char *section
, *entry
, *value
;
474 parse_error
= parse_wvconf_request(wvconfstr
.edit(),
475 section
, entry
, value
);
478 set(section
, entry
, value
);
479 _value
= get(section
, entry
, value
);
486 void WvConfEmu::setint(WvStringParm section
, WvStringParm entry
, int value
)
489 uniconf
[section
][entry
].setmeint(value
);
493 void WvConfEmu::set(WvStringParm section
, WvStringParm entry
,
498 if (value
&& value
[0] != 0)
499 uniconf
[section
][entry
].setme(value
);
501 uniconf
[section
][entry
].setme(WvString::null
);
507 void WvConfEmu::maybesetint(WvStringParm section
, WvStringParm entry
,
510 if (!!entry
&& !get(section
, entry
, NULL
))
511 setint(section
, entry
, value
);
515 void WvConfEmu::maybeset(WvStringParm section
, WvStringParm entry
,
518 if (!!entry
&& get(section
, entry
, 0) == 0)
519 set(section
, entry
, value
);
523 void WvConfEmu::delete_section(WvStringParm section
)
525 uniconf
[section
].remove();
530 int WvConfEmu::check_for_bool_string(const char *s
)
532 if (strcasecmp(s
, "off") == 0
533 || strcasecmp(s
, "false") == 0
534 || strncasecmp(s
, "no", 2) == 0) // also handles "none"
537 if (strcasecmp(s
, "on") == 0
538 || strcasecmp(s
, "true") == 0
539 || strcasecmp(s
, "yes") == 0)
542 // not a special bool case, so just return the number
547 void WvConfEmu::Iter::rewind()
554 WvLink
*WvConfEmu::Iter::next()
557 while (link
.data
== NULL
&& iter
.next())
559 link
.data
= static_cast<void*>(conf
[iter
->key()]);
569 WvConfigSectionEmu
*WvConfEmu::Iter::ptr() const
571 return conf
[iter
->key()];