inifile.cc revision 2632:1bb2f91485ea
17119Sgblack@eecs.umich.edu/* 27119Sgblack@eecs.umich.edu * Copyright (c) 2001-2005 The Regents of The University of Michigan 37119Sgblack@eecs.umich.edu * All rights reserved. 47119Sgblack@eecs.umich.edu * 57119Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67119Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77119Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87119Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97119Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107119Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117119Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127119Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137119Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147119Sgblack@eecs.umich.edu * this software without specific prior written permission. 157119Sgblack@eecs.umich.edu * 167119Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177119Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187119Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197119Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207119Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217119Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227119Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237119Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247119Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257119Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267119Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277119Sgblack@eecs.umich.edu */ 287119Sgblack@eecs.umich.edu 297119Sgblack@eecs.umich.edu#define USE_CPP 307119Sgblack@eecs.umich.edu 317119Sgblack@eecs.umich.edu#ifdef USE_CPP 327119Sgblack@eecs.umich.edu#include <sys/signal.h> 337119Sgblack@eecs.umich.edu#include <sys/types.h> 347119Sgblack@eecs.umich.edu#include <sys/wait.h> 357119Sgblack@eecs.umich.edu 367119Sgblack@eecs.umich.edu#include <libgen.h> 377119Sgblack@eecs.umich.edu#include <stdio.h> 387119Sgblack@eecs.umich.edu#include <stdlib.h> 397119Sgblack@eecs.umich.edu#include <unistd.h> 407119Sgblack@eecs.umich.edu#endif 417119Sgblack@eecs.umich.edu 427119Sgblack@eecs.umich.edu#include <fstream> 437119Sgblack@eecs.umich.edu#include <iostream> 447119Sgblack@eecs.umich.edu 457119Sgblack@eecs.umich.edu#include <vector> 467119Sgblack@eecs.umich.edu#include <string> 477119Sgblack@eecs.umich.edu 487119Sgblack@eecs.umich.edu#include "base/inifile.hh" 497119Sgblack@eecs.umich.edu#include "base/str.hh" 507119Sgblack@eecs.umich.edu 517119Sgblack@eecs.umich.eduusing namespace std; 527119Sgblack@eecs.umich.edu 537119Sgblack@eecs.umich.eduIniFile::IniFile() 547119Sgblack@eecs.umich.edu{} 557119Sgblack@eecs.umich.edu 567128Sgblack@eecs.umich.eduIniFile::~IniFile() 577128Sgblack@eecs.umich.edu{ 587128Sgblack@eecs.umich.edu SectionTable::iterator i = table.begin(); 597128Sgblack@eecs.umich.edu SectionTable::iterator end = table.end(); 607128Sgblack@eecs.umich.edu 617128Sgblack@eecs.umich.edu while (i != end) { 627119Sgblack@eecs.umich.edu delete (*i).second; 637119Sgblack@eecs.umich.edu ++i; 647119Sgblack@eecs.umich.edu } 657119Sgblack@eecs.umich.edu} 667119Sgblack@eecs.umich.edu 677119Sgblack@eecs.umich.edu 687119Sgblack@eecs.umich.edu#ifdef USE_CPP 697119Sgblack@eecs.umich.edubool 707119Sgblack@eecs.umich.eduIniFile::loadCPP(const string &file, vector<char *> &cppArgs) 717119Sgblack@eecs.umich.edu{ 727119Sgblack@eecs.umich.edu // Open the file just to verify that we can. Otherwise if the 737119Sgblack@eecs.umich.edu // file doesn't exist or has bad permissions the user will get 747119Sgblack@eecs.umich.edu // confusing errors from cpp/g++. 757119Sgblack@eecs.umich.edu ifstream tmpf(file.c_str()); 767119Sgblack@eecs.umich.edu 777119Sgblack@eecs.umich.edu if (!tmpf.is_open()) 787119Sgblack@eecs.umich.edu return false; 797119Sgblack@eecs.umich.edu 807119Sgblack@eecs.umich.edu tmpf.close(); 817119Sgblack@eecs.umich.edu 827119Sgblack@eecs.umich.edu char *cfile = strncpy(new char[file.size() + 1], file.c_str(), 837119Sgblack@eecs.umich.edu file.size()); 847119Sgblack@eecs.umich.edu char *dir = dirname(cfile); 857119Sgblack@eecs.umich.edu char *dir_arg = NULL; 867119Sgblack@eecs.umich.edu if (*dir != '.') { 877119Sgblack@eecs.umich.edu string arg = "-I"; 887119Sgblack@eecs.umich.edu arg += dir; 897119Sgblack@eecs.umich.edu 907119Sgblack@eecs.umich.edu dir_arg = new char[arg.size() + 1]; 917119Sgblack@eecs.umich.edu strncpy(dir_arg, arg.c_str(), arg.size()); 927119Sgblack@eecs.umich.edu } 937119Sgblack@eecs.umich.edu 947119Sgblack@eecs.umich.edu delete [] cfile; 957119Sgblack@eecs.umich.edu 967119Sgblack@eecs.umich.edu char tempfile[] = "/tmp/configXXXXXX"; 977119Sgblack@eecs.umich.edu int tmp_fd = mkstemp(tempfile); 987119Sgblack@eecs.umich.edu 997119Sgblack@eecs.umich.edu int pid = fork(); 1007119Sgblack@eecs.umich.edu 1017119Sgblack@eecs.umich.edu if (pid == -1) 1027119Sgblack@eecs.umich.edu return false; 1037119Sgblack@eecs.umich.edu 1047119Sgblack@eecs.umich.edu if (pid == 0) { 1057119Sgblack@eecs.umich.edu char filename[FILENAME_MAX]; 1067119Sgblack@eecs.umich.edu string::size_type i = file.copy(filename, sizeof(filename) - 1); 1077119Sgblack@eecs.umich.edu filename[i] = '\0'; 1087119Sgblack@eecs.umich.edu 1097119Sgblack@eecs.umich.edu int arg_count = cppArgs.size(); 1107119Sgblack@eecs.umich.edu 1117119Sgblack@eecs.umich.edu char **args = new char *[arg_count + 20]; 1127119Sgblack@eecs.umich.edu 1137119Sgblack@eecs.umich.edu int nextArg = 0; 1147119Sgblack@eecs.umich.edu args[nextArg++] = "g++"; 1157119Sgblack@eecs.umich.edu args[nextArg++] = "-E"; 1167119Sgblack@eecs.umich.edu args[nextArg++] = "-P"; 1177119Sgblack@eecs.umich.edu args[nextArg++] = "-nostdinc"; 1187119Sgblack@eecs.umich.edu args[nextArg++] = "-nostdinc++"; 1197119Sgblack@eecs.umich.edu args[nextArg++] = "-x"; 1207119Sgblack@eecs.umich.edu args[nextArg++] = "c++"; 1217119Sgblack@eecs.umich.edu args[nextArg++] = "-undef"; 1227119Sgblack@eecs.umich.edu 1237119Sgblack@eecs.umich.edu for (int i = 0; i < arg_count; i++) 1247119Sgblack@eecs.umich.edu args[nextArg++] = cppArgs[i]; 1257128Sgblack@eecs.umich.edu 1267128Sgblack@eecs.umich.edu if (dir_arg) 1277128Sgblack@eecs.umich.edu args[nextArg++] = dir_arg; 1287128Sgblack@eecs.umich.edu 1297128Sgblack@eecs.umich.edu args[nextArg++] = filename; 1307128Sgblack@eecs.umich.edu args[nextArg++] = NULL; 1317128Sgblack@eecs.umich.edu 1327128Sgblack@eecs.umich.edu close(STDOUT_FILENO); 1337128Sgblack@eecs.umich.edu if (dup2(tmp_fd, STDOUT_FILENO) == -1) 1347128Sgblack@eecs.umich.edu exit(1); 1357128Sgblack@eecs.umich.edu 1367128Sgblack@eecs.umich.edu execvp("g++", args); 1377128Sgblack@eecs.umich.edu 1387128Sgblack@eecs.umich.edu exit(0); 1397128Sgblack@eecs.umich.edu } 1407128Sgblack@eecs.umich.edu 1417128Sgblack@eecs.umich.edu int retval; 1427128Sgblack@eecs.umich.edu waitpid(pid, &retval, 0); 1437128Sgblack@eecs.umich.edu 1447128Sgblack@eecs.umich.edu delete [] dir_arg; 1457128Sgblack@eecs.umich.edu 1467128Sgblack@eecs.umich.edu // check for normal completion of CPP 1477128Sgblack@eecs.umich.edu if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0) 1487128Sgblack@eecs.umich.edu return false; 1497128Sgblack@eecs.umich.edu 1507128Sgblack@eecs.umich.edu close(tmp_fd); 1517128Sgblack@eecs.umich.edu 1527128Sgblack@eecs.umich.edu bool status = false; 1537128Sgblack@eecs.umich.edu 1547128Sgblack@eecs.umich.edu status = load(tempfile); 1557128Sgblack@eecs.umich.edu 1567128Sgblack@eecs.umich.edu unlink(tempfile); 1577128Sgblack@eecs.umich.edu 1587128Sgblack@eecs.umich.edu return status; 1597128Sgblack@eecs.umich.edu} 1607128Sgblack@eecs.umich.edu#endif 1617128Sgblack@eecs.umich.edu 1627128Sgblack@eecs.umich.edubool 1637128Sgblack@eecs.umich.eduIniFile::load(const string &file) 1647128Sgblack@eecs.umich.edu{ 1657128Sgblack@eecs.umich.edu ifstream f(file.c_str()); 1667128Sgblack@eecs.umich.edu 1677128Sgblack@eecs.umich.edu if (!f.is_open()) 1687128Sgblack@eecs.umich.edu return false; 1697128Sgblack@eecs.umich.edu 1707128Sgblack@eecs.umich.edu return load(f); 1717128Sgblack@eecs.umich.edu} 1727128Sgblack@eecs.umich.edu 1737128Sgblack@eecs.umich.edu 1747128Sgblack@eecs.umich.educonst string & 1757128Sgblack@eecs.umich.eduIniFile::Entry::getValue() const 1767119Sgblack@eecs.umich.edu{ 1777119Sgblack@eecs.umich.edu referenced = true; 1787119Sgblack@eecs.umich.edu return value; 1797119Sgblack@eecs.umich.edu} 1807119Sgblack@eecs.umich.edu 1817119Sgblack@eecs.umich.edu 1827119Sgblack@eecs.umich.eduvoid 1837119Sgblack@eecs.umich.eduIniFile::Section::addEntry(const std::string &entryName, 1847119Sgblack@eecs.umich.edu const std::string &value, 1857119Sgblack@eecs.umich.edu bool append) 1867119Sgblack@eecs.umich.edu{ 1877119Sgblack@eecs.umich.edu EntryTable::iterator ei = table.find(entryName); 1887119Sgblack@eecs.umich.edu 1897119Sgblack@eecs.umich.edu if (ei == table.end()) { 1907128Sgblack@eecs.umich.edu // new entry 1917128Sgblack@eecs.umich.edu table[entryName] = new Entry(value); 1927128Sgblack@eecs.umich.edu } 1937128Sgblack@eecs.umich.edu else if (append) { 1947128Sgblack@eecs.umich.edu // append new reult to old entry 1957128Sgblack@eecs.umich.edu ei->second->appendValue(value); 1967128Sgblack@eecs.umich.edu } 1977128Sgblack@eecs.umich.edu else { 1987128Sgblack@eecs.umich.edu // override old entry 1997128Sgblack@eecs.umich.edu ei->second->setValue(value); 2007128Sgblack@eecs.umich.edu } 2017128Sgblack@eecs.umich.edu} 2027128Sgblack@eecs.umich.edu 2037128Sgblack@eecs.umich.edu 2047119Sgblack@eecs.umich.edubool 2057119Sgblack@eecs.umich.eduIniFile::Section::add(const std::string &assignment) 2067119Sgblack@eecs.umich.edu{ 2077119Sgblack@eecs.umich.edu string::size_type offset = assignment.find('='); 2087119Sgblack@eecs.umich.edu if (offset == string::npos) { 2097119Sgblack@eecs.umich.edu // no '=' found 2107119Sgblack@eecs.umich.edu cerr << "Can't parse .ini line " << assignment << endl; 2117119Sgblack@eecs.umich.edu return false; 2127119Sgblack@eecs.umich.edu } 2137119Sgblack@eecs.umich.edu 2147128Sgblack@eecs.umich.edu // if "+=" rather than just "=" then append value 2157128Sgblack@eecs.umich.edu bool append = (assignment[offset-1] == '+'); 2167119Sgblack@eecs.umich.edu 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} 434