Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

uniinigen.cc

Go to the documentation of this file.
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * A generator for .ini files. 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 // need to escape []#= in key only to distinguish a key/value 00032 // pair from a section name or comment and to delimit the value 00033 file.print("%s = %s\n", 00034 wvtcl_escape(key, " \t\r\n[]=#"), 00035 wvtcl_escape(value, " \t\r\n")); 00036 } 00037 00038 00039 /***** UniIniGen *****/ 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 // consider the generator dirty until it is first refreshed 00046 dirty = true; 00047 } 00048 00049 00050 UniIniGen::~UniIniGen() 00051 { 00052 } 00053 00054 00055 bool UniIniGen::refresh() 00056 { 00057 /** open the file **/ 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 /** loop over all Tcl words in the file **/ 00068 UniTempGen *newgen = new UniTempGen(); 00069 UniConfKey section; 00070 WvDynBuf buf; 00071 for (bool eof = false; ! eof; ) 00072 { 00073 if (file.isok()) 00074 { 00075 // read entire lines to ensure that we get whole values 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 // detect missing newline at end of file 00088 size_t avail = buf.used(); 00089 if (avail == 0) 00090 break; 00091 if (buf.peek(avail - 1) == '\n') 00092 break; 00093 // run the loop one more time to compensate 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 // we have an empty line 00105 continue; 00106 } 00107 if (str[0] == '#') 00108 { 00109 // we have a comment line 00110 log(WvLog::Debug5, "Comment: \"%s\"\n", str + 1); 00111 continue; 00112 } 00113 if (str[0] == '[' && str[len - 1] == ']') 00114 { 00115 // we have a section name line 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 // we possibly have a key = value line 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 //log(WvLog::Debug5, "Refresh: (\"%s\", \"%s\")\n", 00136 // key, value); 00137 continue; 00138 } 00139 } 00140 log("Ignoring malformed input line: \"%s\"\n", word); 00141 } 00142 } 00143 00144 /** close the file **/ 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 /** handle unparsed input **/ 00154 size_t avail = buf.used(); 00155 while (avail > 0 && buf.peek(avail - 1) == '\n') 00156 { 00157 buf.unalloc(1); // strip off uninteresting trailing newlines 00158 avail -= 1; 00159 } 00160 if (avail > 0) 00161 { 00162 // last line must have contained junk 00163 log("XXX Ignoring malformed input line: \"%s\"\n", buf.getstr()); 00164 } 00165 00166 /** switch the trees send notifications **/ 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); // REMOVED 00182 } 00183 unhold_delta(); 00184 00185 delete newgen; 00186 00187 /** done **/ 00188 return true; 00189 } 00190 00191 00192 // returns: true if a==b 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 // key changed 00203 delta(b->fullkey(), b->value()); // CHANGED 00204 return false; 00205 } 00206 return true; 00207 } 00208 else 00209 { 00210 // key removed 00211 delta(a->fullkey(), WvString::null); // REMOVED 00212 return false; 00213 } 00214 } 00215 else // a didn't exist 00216 { 00217 assert(b); 00218 // key added 00219 delta(b->fullkey(), b->value()); // ADDED 00220 return false; 00221 } 00222 } 00223 00224 00225 void UniIniGen::commit() 00226 { 00227 /** check dirtiness **/ 00228 if (! dirty) 00229 return; 00230 00231 /** open the file **/ 00232 WvFile file(filename, O_WRONLY | O_TRUNC | O_CREAT, create_mode); 00233 if (! file.isok()) 00234 { 00235 //FIXME: Should use wverror 00236 log("Cannot open config file for writing: \"%s\"\n", 00237 file.errstr()); 00238 return; 00239 } 00240 00241 /** iterate over all keys **/ 00242 if (root) 00243 save(file, *root); 00244 00245 /** close the file **/ 00246 file.close(); 00247 if (file.geterr()) 00248 { 00249 //FIXME: Should use wverror 00250 log("Error writing to config file: \"%s\"\n", file.errstr()); 00251 return; 00252 } 00253 00254 dirty = false; 00255 00256 /** done **/ 00257 return; 00258 } 00259 00260 00261 void UniIniGen::save(WvStream &file, UniConfValueTree &parent) 00262 { 00263 UniConfValueTree::Iter it(parent); 00264 00265 /** output values for non-empty direct or barren nodes **/ 00266 // we want to ensure that a key with an empty value will 00267 // get created either by writing its value or by ensuring 00268 // that some subkey will create it implictly with empty value 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 /** output child sections **/ 00287 for (it.rewind(); it.next() && file.isok(); ) 00288 { 00289 save(file, *it); 00290 } 00291 }

Generated on Tue Oct 5 01:09:19 2004 for WvStreams by doxygen 1.3.7