00001
00002
00003
00004
00005
00006
00007
#include "uniinigen.h"
00008
#include "unitempgen.h"
00009
#include "wvtclstring.h"
00010
#include "strutils.h"
00011
#include "wvfile.h"
00012
#include "wvmoniker.h"
00013
00014 static UniConfGen *
creator(
WvStringParm s,
IObject *,
void *)
00015 {
00016
return new UniIniGen(s);
00017 }
00018
00019
static WvMoniker<UniConfGen> reg(
"ini", creator);
00020
00021
00022
00023 static void printsection(
WvStream &file,
const UniConfKey &key)
00024 {
00025 file.
print(
"[%s]\n",
wvtcl_escape(key,
"\t\r\n[]"));
00026 }
00027
00028 static void printkey(
WvStream &file,
const UniConfKey &key,
00029
WvStringParm value)
00030 {
00031
00032
00033 file.
print(
"%s = %s\n",
00034
wvtcl_escape(key,
" \t\r\n[]=#"),
00035
wvtcl_escape(value,
" \t\r\n"));
00036 }
00037
00038
00039
00040
00041 UniIniGen::UniIniGen(
WvStringParm _filename,
int _create_mode)
00042 : filename(_filename), create_mode(_create_mode),
log(filename)
00043 {
00044
log(WvLog::Debug1,
"Using IniFile \"%s\"\n", filename);
00045
00046 dirty =
true;
00047 }
00048
00049
00050 UniIniGen::~UniIniGen()
00051 {
00052 }
00053
00054
00055 bool UniIniGen::refresh()
00056 {
00057
00058
WvFile file(filename, O_RDONLY);
00059
if (! file.
isok())
00060 {
00061
log(
"Cannot open config file for reading: \"%s\"\n",
00062 file.
errstr());
00063 file.
close();
00064
return false;
00065 }
00066
00067
00068
UniTempGen *newgen =
new UniTempGen();
00069
UniConfKey section;
00070
WvDynBuf buf;
00071
for (
bool eof =
false; ! eof; )
00072 {
00073
if (file.
isok())
00074 {
00075
00076
char *line = file.
getline(-1);
00077
if (line)
00078 buf.putstr(line);
00079
else
00080 eof =
true;
00081 }
00082
else
00083 eof =
true;
00084
00085
if (eof)
00086 {
00087
00088 size_t avail = buf.
used();
00089
if (avail == 0)
00090
break;
00091
if (buf.
peek(avail - 1) ==
'\n')
00092
break;
00093
00094 }
00095 buf.
put(
'\n');
00096
00097
for (
WvString word;
00098 ! (word =
wvtcl_getword(buf,
"\r\n",
false)).isnull(); )
00099 {
00100
char *str =
trim_string(word.
edit());
00101
int len = strlen(str);
00102
if (len == 0)
00103 {
00104
00105
continue;
00106 }
00107
if (str[0] ==
'#')
00108 {
00109
00110
log(WvLog::Debug5,
"Comment: \"%s\"\n", str + 1);
00111
continue;
00112 }
00113
if (str[0] ==
'[' && str[len - 1] ==
']')
00114 {
00115
00116 str[len - 1] =
'\0';
00117
WvString name(
wvtcl_unescape(
trim_string(str + 1)));
00118 section =
UniConfKey(name.
unique());
00119
log(WvLog::Debug5,
"Refresh section: \"%s\"\n", section);
00120
continue;
00121 }
00122
00123
WvConstStringBuffer line(word);
00124
WvString temp =
wvtcl_getword(line,
"=",
false);
00125
if (! temp.
isnull() && line.
peek(-1) ==
'=')
00126 {
00127
WvString name(
wvtcl_unescape(
trim_string(temp.
edit())));
00128
UniConfKey key(name.
unique());
00129
if (! key.
isempty())
00130 {
00131 key.
prepend(section);
00132 temp = line.getstr();
00133
WvString value(
wvtcl_unescape(
trim_string(temp.
edit())));
00134 newgen->
set(key, value.
unique());
00135
00136
00137
continue;
00138 }
00139 }
00140
log(
"Ignoring malformed input line: \"%s\"\n", word);
00141 }
00142 }
00143
00144
00145 file.
close();
00146
if (file.
geterr())
00147 {
00148
log(
"Error reading from config file: \"%s\"\n", file.
errstr());
00149
delete newgen;
00150
return false;
00151 }
00152
00153
00154 size_t avail = buf.
used();
00155
while (avail > 0 && buf.
peek(avail - 1) ==
'\n')
00156 {
00157 buf.
unalloc(1);
00158 avail -= 1;
00159 }
00160
if (avail > 0)
00161 {
00162
00163
log(
"XXX Ignoring malformed input line: \"%s\"\n", buf.getstr());
00164 }
00165
00166
00167
hold_delta();
00168
UniConfValueTree *oldtree = root;
00169
UniConfValueTree *newtree = newgen->
root;
00170 root = newtree;
00171 newgen->
root = NULL;
00172 dirty =
false;
00173
if (oldtree && newtree)
00174 {
00175 oldtree->
compare(newtree, UniConfValueTree::Comparator
00176 (
this, &UniIniGen::refreshcomparator), NULL);
00177
delete oldtree;
00178 }
00179
else
00180 {
00181 delta(UniConfKey::EMPTY, WvString::null);
00182 }
00183
unhold_delta();
00184
00185
delete newgen;
00186
00187
00188
return true;
00189 }
00190
00191
00192
00193
bool UniIniGen::refreshcomparator(
const UniConfValueTree *a,
00194
const UniConfValueTree *b,
void *userdata)
00195 {
00196
if (a)
00197 {
00198
if (b)
00199 {
00200
if (a->
value() != b->
value())
00201 {
00202
00203 delta(b->
fullkey(), b->
value());
00204
return false;
00205 }
00206
return true;
00207 }
00208
else
00209 {
00210
00211
delta(a->
fullkey(),
WvString::null);
00212
return false;
00213 }
00214 }
00215
else
00216 {
00217 assert(b);
00218
00219
delta(b->
fullkey(), b->
value());
00220
return false;
00221 }
00222 }
00223
00224
00225 void UniIniGen::commit()
00226 {
00227
00228
if (! dirty)
00229
return;
00230
00231
00232
WvFile file(filename, O_WRONLY | O_TRUNC | O_CREAT, create_mode);
00233
if (! file.
isok())
00234 {
00235
00236
log(
"Cannot open config file for writing: \"%s\"\n",
00237 file.
errstr());
00238
return;
00239 }
00240
00241
00242
if (root)
00243 save(file, *root);
00244
00245
00246 file.
close();
00247
if (file.
geterr())
00248 {
00249
00250
log(
"Error writing to config file: \"%s\"\n", file.
errstr());
00251
return;
00252 }
00253
00254 dirty =
false;
00255
00256
00257
return;
00258 }
00259
00260
00261
void UniIniGen::save(
WvStream &file,
UniConfValueTree &parent)
00262 {
00263 UniConfValueTree::Iter it(parent);
00264
00265
00266
00267
00268
00269
bool printedsection =
false;
00270
for (it.rewind(); it.next() && file.
isok(); )
00271 {
00272
UniConfValueTree *node = it.ptr();
00273
if (!! node->
value() || ! node->
haschildren())
00274 {
00275
if (! printedsection)
00276 {
00277
printsection(file, parent.
fullkey());
00278 printedsection =
true;
00279 }
00280
printkey(file, node->
key(), node->
value());
00281 }
00282 }
00283
if (printedsection)
00284 file.
print(
"\n");
00285
00286
00287
for (it.rewind(); it.next() && file.
isok(); )
00288 {
00289 save(file, *it);
00290 }
00291 }