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 }