1/* 2 * Copyright (c) 2001-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
| 1/* 2 * Copyright (c) 2001-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27 */ 28 29#define USE_CPP 30 31#ifdef USE_CPP 32#include <sys/signal.h> 33#include <sys/types.h> 34#include <sys/wait.h> 35 36#include <libgen.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <unistd.h> 40#endif 41 42#include <fstream> 43#include <iostream> 44 45#include <vector> 46#include <string> 47 48#include "base/inifile.hh" 49#include "base/str.hh" 50 51using namespace std; 52 53IniFile::IniFile() 54{} 55 56IniFile::~IniFile() 57{ 58 SectionTable::iterator i = table.begin(); 59 SectionTable::iterator end = table.end(); 60 61 while (i != end) { 62 delete (*i).second; 63 ++i; 64 } 65} 66 67 68#ifdef USE_CPP 69bool 70IniFile::loadCPP(const string &file, vector<char *> &cppArgs) 71{ 72 // Open the file just to verify that we can. Otherwise if the 73 // file doesn't exist or has bad permissions the user will get 74 // confusing errors from cpp/g++. 75 ifstream tmpf(file.c_str()); 76 77 if (!tmpf.is_open()) 78 return false; 79 80 tmpf.close(); 81 82 char *cfile = strncpy(new char[file.size() + 1], file.c_str(), 83 file.size()); 84 char *dir = dirname(cfile); 85 char *dir_arg = NULL; 86 if (*dir != '.') { 87 string arg = "-I"; 88 arg += dir; 89 90 dir_arg = new char[arg.size() + 1]; 91 strncpy(dir_arg, arg.c_str(), arg.size()); 92 } 93 94 delete [] cfile; 95 96 char tempfile[] = "/tmp/configXXXXXX"; 97 int tmp_fd = mkstemp(tempfile); 98 99 int pid = fork(); 100 101 if (pid == -1) 102 return false; 103 104 if (pid == 0) { 105 char filename[FILENAME_MAX]; 106 string::size_type i = file.copy(filename, sizeof(filename) - 1); 107 filename[i] = '\0'; 108 109 int arg_count = cppArgs.size(); 110 111 char **args = new char *[arg_count + 20]; 112 113 int nextArg = 0; 114 args[nextArg++] = "g++"; 115 args[nextArg++] = "-E"; 116 args[nextArg++] = "-P"; 117 args[nextArg++] = "-nostdinc"; 118 args[nextArg++] = "-nostdinc++"; 119 args[nextArg++] = "-x"; 120 args[nextArg++] = "c++"; 121 args[nextArg++] = "-undef"; 122 123 for (int i = 0; i < arg_count; i++) 124 args[nextArg++] = cppArgs[i]; 125 126 if (dir_arg) 127 args[nextArg++] = dir_arg; 128 129 args[nextArg++] = filename; 130 args[nextArg++] = NULL; 131 132 close(STDOUT_FILENO); 133 if (dup2(tmp_fd, STDOUT_FILENO) == -1) 134 exit(1); 135 136 execvp("g++", args); 137 138 exit(0); 139 } 140 141 int retval; 142 waitpid(pid, &retval, 0); 143 144 delete [] dir_arg; 145 146 // check for normal completion of CPP 147 if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0) 148 return false; 149 150 close(tmp_fd); 151 152 bool status = false; 153 154 status = load(tempfile); 155 156 unlink(tempfile); 157 158 return status; 159} 160#endif 161 162bool 163IniFile::load(const string &file) 164{ 165 ifstream f(file.c_str()); 166 167 if (!f.is_open()) 168 return false; 169 170 return load(f); 171} 172 173 174const string & 175IniFile::Entry::getValue() const 176{ 177 referenced = true; 178 return value; 179} 180 181 182void 183IniFile::Section::addEntry(const std::string &entryName, 184 const std::string &value, 185 bool append) 186{ 187 EntryTable::iterator ei = table.find(entryName); 188 189 if (ei == table.end()) { 190 // new entry 191 table[entryName] = new Entry(value); 192 } 193 else if (append) { 194 // append new reult to old entry 195 ei->second->appendValue(value); 196 } 197 else { 198 // override old entry 199 ei->second->setValue(value); 200 } 201} 202 203 204bool 205IniFile::Section::add(const std::string &assignment) 206{ 207 string::size_type offset = assignment.find('='); 208 if (offset == string::npos) { 209 // no '=' found 210 cerr << "Can't parse .ini line " << assignment << endl; 211 return false; 212 } 213 214 // if "+=" rather than just "=" then append value 215 bool append = (assignment[offset-1] == '+'); 216 217 string entryName = assignment.substr(0, append ? offset-1 : offset); 218 string value = assignment.substr(offset + 1); 219 220 eat_white(entryName); 221 eat_white(value); 222 223 addEntry(entryName, value, append); 224 return true; 225} 226 227 228IniFile::Entry * 229IniFile::Section::findEntry(const std::string &entryName) const 230{ 231 referenced = true; 232 233 EntryTable::const_iterator ei = table.find(entryName); 234 235 return (ei == table.end()) ? NULL : ei->second; 236} 237 238 239IniFile::Section * 240IniFile::addSection(const string §ionName) 241{ 242 SectionTable::iterator i = table.find(sectionName); 243 244 if (i != table.end()) { 245 return i->second; 246 } 247 else { 248 // new entry 249 Section *sec = new Section(); 250 table[sectionName] = sec; 251 return sec; 252 } 253} 254 255 256IniFile::Section * 257IniFile::findSection(const string §ionName) const 258{ 259 SectionTable::const_iterator i = table.find(sectionName); 260 261 return (i == table.end()) ? NULL : i->second; 262} 263 264 265// Take string of the form "<section>:<parameter>=<value>" and add to 266// database. Return true if successful, false if parse error. 267bool 268IniFile::add(const string &str) 269{ 270 // find ':' 271 string::size_type offset = str.find(':'); 272 if (offset == string::npos) // no ':' found 273 return false; 274 275 string sectionName = str.substr(0, offset); 276 string rest = str.substr(offset + 1); 277 278 eat_white(sectionName); 279 Section *s = addSection(sectionName); 280 281 return s->add(rest); 282} 283 284bool 285IniFile::load(istream &f) 286{ 287 Section *section = NULL; 288 289 while (!f.eof()) { 290 f >> ws; // Eat whitespace 291 if (f.eof()) { 292 break; 293 } 294 295 string line; 296 getline(f, line); 297 if (line.size() == 0) 298 continue; 299 300 eat_end_white(line); 301 int last = line.size() - 1; 302 303 if (line[0] == '[' && line[last] == ']') { 304 string sectionName = line.substr(1, last - 1); 305 eat_white(sectionName); 306 section = addSection(sectionName); 307 continue; 308 } 309 310 if (section == NULL) 311 continue; 312 313 if (!section->add(line)) 314 return false; 315 } 316 317 return true; 318} 319 320bool 321IniFile::find(const string §ionName, const string &entryName, 322 string &value) const 323{ 324 Section *section = findSection(sectionName); 325 if (section == NULL) 326 return false; 327 328 Entry *entry = section->findEntry(entryName); 329 if (entry == NULL) 330 return false; 331 332 value = entry->getValue(); 333 334 return true; 335} 336 337bool 338IniFile::sectionExists(const string §ionName) const 339{ 340 return findSection(sectionName) != NULL; 341} 342 343 344bool 345IniFile::Section::printUnreferenced(const string §ionName) 346{ 347 bool unref = false; 348 bool search_unref_entries = false; 349 vector<string> unref_ok_entries; 350 351 Entry *entry = findEntry("unref_entries_ok"); 352 if (entry != NULL) { 353 tokenize(unref_ok_entries, entry->getValue(), ' '); 354 if (unref_ok_entries.size()) { 355 search_unref_entries = true; 356 } 357 } 358 359 for (EntryTable::iterator ei = table.begin(); 360 ei != table.end(); ++ei) { 361 const string &entryName = ei->first; 362 Entry *entry = ei->second; 363 364 if (entryName == "unref_section_ok" || 365 entryName == "unref_entries_ok") 366 { 367 continue; 368 } 369 370 if (!entry->isReferenced()) { 371 if (search_unref_entries && 372 (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), 373 entryName) != unref_ok_entries.end())) 374 { 375 continue; 376 } 377 378 cerr << "Parameter " << sectionName << ":" << entryName 379 << " not referenced." << endl; 380 unref = true; 381 } 382 } 383 384 return unref; 385} 386 387 388bool 389IniFile::printUnreferenced() 390{ 391 bool unref = false; 392 393 for (SectionTable::iterator i = table.begin(); 394 i != table.end(); ++i) { 395 const string §ionName = i->first; 396 Section *section = i->second; 397 398 if (!section->isReferenced()) { 399 if (section->findEntry("unref_section_ok") == NULL) { 400 cerr << "Section " << sectionName << " not referenced." 401 << endl; 402 unref = true; 403 } 404 } 405 else { 406 if (section->printUnreferenced(sectionName)) { 407 unref = true; 408 } 409 } 410 } 411 412 return unref; 413} 414 415 416void 417IniFile::Section::dump(const string §ionName) 418{ 419 for (EntryTable::iterator ei = table.begin(); 420 ei != table.end(); ++ei) { 421 cout << sectionName << ": " << (*ei).first << " => " 422 << (*ei).second->getValue() << "\n"; 423 } 424} 425 426void 427IniFile::dump() 428{ 429 for (SectionTable::iterator i = table.begin(); 430 i != table.end(); ++i) { 431 i->second->dump(i->first); 432 } 433}
| 30 */ 31 32#define USE_CPP 33 34#ifdef USE_CPP 35#include <sys/signal.h> 36#include <sys/types.h> 37#include <sys/wait.h> 38 39#include <libgen.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <unistd.h> 43#endif 44 45#include <fstream> 46#include <iostream> 47 48#include <vector> 49#include <string> 50 51#include "base/inifile.hh" 52#include "base/str.hh" 53 54using namespace std; 55 56IniFile::IniFile() 57{} 58 59IniFile::~IniFile() 60{ 61 SectionTable::iterator i = table.begin(); 62 SectionTable::iterator end = table.end(); 63 64 while (i != end) { 65 delete (*i).second; 66 ++i; 67 } 68} 69 70 71#ifdef USE_CPP 72bool 73IniFile::loadCPP(const string &file, vector<char *> &cppArgs) 74{ 75 // Open the file just to verify that we can. Otherwise if the 76 // file doesn't exist or has bad permissions the user will get 77 // confusing errors from cpp/g++. 78 ifstream tmpf(file.c_str()); 79 80 if (!tmpf.is_open()) 81 return false; 82 83 tmpf.close(); 84 85 char *cfile = strncpy(new char[file.size() + 1], file.c_str(), 86 file.size()); 87 char *dir = dirname(cfile); 88 char *dir_arg = NULL; 89 if (*dir != '.') { 90 string arg = "-I"; 91 arg += dir; 92 93 dir_arg = new char[arg.size() + 1]; 94 strncpy(dir_arg, arg.c_str(), arg.size()); 95 } 96 97 delete [] cfile; 98 99 char tempfile[] = "/tmp/configXXXXXX"; 100 int tmp_fd = mkstemp(tempfile); 101 102 int pid = fork(); 103 104 if (pid == -1) 105 return false; 106 107 if (pid == 0) { 108 char filename[FILENAME_MAX]; 109 string::size_type i = file.copy(filename, sizeof(filename) - 1); 110 filename[i] = '\0'; 111 112 int arg_count = cppArgs.size(); 113 114 char **args = new char *[arg_count + 20]; 115 116 int nextArg = 0; 117 args[nextArg++] = "g++"; 118 args[nextArg++] = "-E"; 119 args[nextArg++] = "-P"; 120 args[nextArg++] = "-nostdinc"; 121 args[nextArg++] = "-nostdinc++"; 122 args[nextArg++] = "-x"; 123 args[nextArg++] = "c++"; 124 args[nextArg++] = "-undef"; 125 126 for (int i = 0; i < arg_count; i++) 127 args[nextArg++] = cppArgs[i]; 128 129 if (dir_arg) 130 args[nextArg++] = dir_arg; 131 132 args[nextArg++] = filename; 133 args[nextArg++] = NULL; 134 135 close(STDOUT_FILENO); 136 if (dup2(tmp_fd, STDOUT_FILENO) == -1) 137 exit(1); 138 139 execvp("g++", args); 140 141 exit(0); 142 } 143 144 int retval; 145 waitpid(pid, &retval, 0); 146 147 delete [] dir_arg; 148 149 // check for normal completion of CPP 150 if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0) 151 return false; 152 153 close(tmp_fd); 154 155 bool status = false; 156 157 status = load(tempfile); 158 159 unlink(tempfile); 160 161 return status; 162} 163#endif 164 165bool 166IniFile::load(const string &file) 167{ 168 ifstream f(file.c_str()); 169 170 if (!f.is_open()) 171 return false; 172 173 return load(f); 174} 175 176 177const string & 178IniFile::Entry::getValue() const 179{ 180 referenced = true; 181 return value; 182} 183 184 185void 186IniFile::Section::addEntry(const std::string &entryName, 187 const std::string &value, 188 bool append) 189{ 190 EntryTable::iterator ei = table.find(entryName); 191 192 if (ei == table.end()) { 193 // new entry 194 table[entryName] = new Entry(value); 195 } 196 else if (append) { 197 // append new reult to old entry 198 ei->second->appendValue(value); 199 } 200 else { 201 // override old entry 202 ei->second->setValue(value); 203 } 204} 205 206 207bool 208IniFile::Section::add(const std::string &assignment) 209{ 210 string::size_type offset = assignment.find('='); 211 if (offset == string::npos) { 212 // no '=' found 213 cerr << "Can't parse .ini line " << assignment << endl; 214 return false; 215 } 216 217 // if "+=" rather than just "=" then append value 218 bool append = (assignment[offset-1] == '+'); 219 220 string entryName = assignment.substr(0, append ? offset-1 : offset); 221 string value = assignment.substr(offset + 1); 222 223 eat_white(entryName); 224 eat_white(value); 225 226 addEntry(entryName, value, append); 227 return true; 228} 229 230 231IniFile::Entry * 232IniFile::Section::findEntry(const std::string &entryName) const 233{ 234 referenced = true; 235 236 EntryTable::const_iterator ei = table.find(entryName); 237 238 return (ei == table.end()) ? NULL : ei->second; 239} 240 241 242IniFile::Section * 243IniFile::addSection(const string §ionName) 244{ 245 SectionTable::iterator i = table.find(sectionName); 246 247 if (i != table.end()) { 248 return i->second; 249 } 250 else { 251 // new entry 252 Section *sec = new Section(); 253 table[sectionName] = sec; 254 return sec; 255 } 256} 257 258 259IniFile::Section * 260IniFile::findSection(const string §ionName) const 261{ 262 SectionTable::const_iterator i = table.find(sectionName); 263 264 return (i == table.end()) ? NULL : i->second; 265} 266 267 268// Take string of the form "<section>:<parameter>=<value>" and add to 269// database. Return true if successful, false if parse error. 270bool 271IniFile::add(const string &str) 272{ 273 // find ':' 274 string::size_type offset = str.find(':'); 275 if (offset == string::npos) // no ':' found 276 return false; 277 278 string sectionName = str.substr(0, offset); 279 string rest = str.substr(offset + 1); 280 281 eat_white(sectionName); 282 Section *s = addSection(sectionName); 283 284 return s->add(rest); 285} 286 287bool 288IniFile::load(istream &f) 289{ 290 Section *section = NULL; 291 292 while (!f.eof()) { 293 f >> ws; // Eat whitespace 294 if (f.eof()) { 295 break; 296 } 297 298 string line; 299 getline(f, line); 300 if (line.size() == 0) 301 continue; 302 303 eat_end_white(line); 304 int last = line.size() - 1; 305 306 if (line[0] == '[' && line[last] == ']') { 307 string sectionName = line.substr(1, last - 1); 308 eat_white(sectionName); 309 section = addSection(sectionName); 310 continue; 311 } 312 313 if (section == NULL) 314 continue; 315 316 if (!section->add(line)) 317 return false; 318 } 319 320 return true; 321} 322 323bool 324IniFile::find(const string §ionName, const string &entryName, 325 string &value) const 326{ 327 Section *section = findSection(sectionName); 328 if (section == NULL) 329 return false; 330 331 Entry *entry = section->findEntry(entryName); 332 if (entry == NULL) 333 return false; 334 335 value = entry->getValue(); 336 337 return true; 338} 339 340bool 341IniFile::sectionExists(const string §ionName) const 342{ 343 return findSection(sectionName) != NULL; 344} 345 346 347bool 348IniFile::Section::printUnreferenced(const string §ionName) 349{ 350 bool unref = false; 351 bool search_unref_entries = false; 352 vector<string> unref_ok_entries; 353 354 Entry *entry = findEntry("unref_entries_ok"); 355 if (entry != NULL) { 356 tokenize(unref_ok_entries, entry->getValue(), ' '); 357 if (unref_ok_entries.size()) { 358 search_unref_entries = true; 359 } 360 } 361 362 for (EntryTable::iterator ei = table.begin(); 363 ei != table.end(); ++ei) { 364 const string &entryName = ei->first; 365 Entry *entry = ei->second; 366 367 if (entryName == "unref_section_ok" || 368 entryName == "unref_entries_ok") 369 { 370 continue; 371 } 372 373 if (!entry->isReferenced()) { 374 if (search_unref_entries && 375 (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), 376 entryName) != unref_ok_entries.end())) 377 { 378 continue; 379 } 380 381 cerr << "Parameter " << sectionName << ":" << entryName 382 << " not referenced." << endl; 383 unref = true; 384 } 385 } 386 387 return unref; 388} 389 390 391bool 392IniFile::printUnreferenced() 393{ 394 bool unref = false; 395 396 for (SectionTable::iterator i = table.begin(); 397 i != table.end(); ++i) { 398 const string §ionName = i->first; 399 Section *section = i->second; 400 401 if (!section->isReferenced()) { 402 if (section->findEntry("unref_section_ok") == NULL) { 403 cerr << "Section " << sectionName << " not referenced." 404 << endl; 405 unref = true; 406 } 407 } 408 else { 409 if (section->printUnreferenced(sectionName)) { 410 unref = true; 411 } 412 } 413 } 414 415 return unref; 416} 417 418 419void 420IniFile::Section::dump(const string §ionName) 421{ 422 for (EntryTable::iterator ei = table.begin(); 423 ei != table.end(); ++ei) { 424 cout << sectionName << ": " << (*ei).first << " => " 425 << (*ei).second->getValue() << "\n"; 426 } 427} 428 429void 430IniFile::dump() 431{ 432 for (SectionTable::iterator i = table.begin(); 433 i != table.end(); ++i) { 434 i->second->dump(i->first); 435 } 436}
|