diff options
Diffstat (limited to 'src/base/inifile.cc')
-rw-r--r-- | src/base/inifile.cc | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/src/base/inifile.cc b/src/base/inifile.cc new file mode 100644 index 000000000..eb5a1335f --- /dev/null +++ b/src/base/inifile.cc @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define USE_CPP + +#ifdef USE_CPP +#include <sys/signal.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <libgen.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#endif + +#include <fstream> +#include <iostream> + +#include <vector> +#include <string> + +#include "base/inifile.hh" +#include "base/str.hh" + +using namespace std; + +IniFile::IniFile() +{} + +IniFile::~IniFile() +{ + SectionTable::iterator i = table.begin(); + SectionTable::iterator end = table.end(); + + while (i != end) { + delete (*i).second; + ++i; + } +} + + +#ifdef USE_CPP +bool +IniFile::loadCPP(const string &file, vector<char *> &cppArgs) +{ + // Open the file just to verify that we can. Otherwise if the + // file doesn't exist or has bad permissions the user will get + // confusing errors from cpp/g++. + ifstream tmpf(file.c_str()); + + if (!tmpf.is_open()) + return false; + + tmpf.close(); + + char *cfile = strncpy(new char[file.size() + 1], file.c_str(), + file.size()); + char *dir = dirname(cfile); + char *dir_arg = NULL; + if (*dir != '.') { + string arg = "-I"; + arg += dir; + + dir_arg = new char[arg.size() + 1]; + strncpy(dir_arg, arg.c_str(), arg.size()); + } + + delete [] cfile; + + char tempfile[] = "/tmp/configXXXXXX"; + int tmp_fd = mkstemp(tempfile); + + int pid = fork(); + + if (pid == -1) + return false; + + if (pid == 0) { + char filename[FILENAME_MAX]; + string::size_type i = file.copy(filename, sizeof(filename) - 1); + filename[i] = '\0'; + + int arg_count = cppArgs.size(); + + char **args = new char *[arg_count + 20]; + + int nextArg = 0; + args[nextArg++] = "g++"; + args[nextArg++] = "-E"; + args[nextArg++] = "-P"; + args[nextArg++] = "-nostdinc"; + args[nextArg++] = "-nostdinc++"; + args[nextArg++] = "-x"; + args[nextArg++] = "c++"; + args[nextArg++] = "-undef"; + + for (int i = 0; i < arg_count; i++) + args[nextArg++] = cppArgs[i]; + + if (dir_arg) + args[nextArg++] = dir_arg; + + args[nextArg++] = filename; + args[nextArg++] = NULL; + + close(STDOUT_FILENO); + if (dup2(tmp_fd, STDOUT_FILENO) == -1) + exit(1); + + execvp("g++", args); + + exit(0); + } + + int retval; + waitpid(pid, &retval, 0); + + delete [] dir_arg; + + // check for normal completion of CPP + if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0) + return false; + + close(tmp_fd); + + bool status = false; + + status = load(tempfile); + + unlink(tempfile); + + return status; +} +#endif + +bool +IniFile::load(const string &file) +{ + ifstream f(file.c_str()); + + if (!f.is_open()) + return false; + + return load(f); +} + + +const string & +IniFile::Entry::getValue() const +{ + referenced = true; + return value; +} + + +void +IniFile::Section::addEntry(const std::string &entryName, + const std::string &value, + bool append) +{ + EntryTable::iterator ei = table.find(entryName); + + if (ei == table.end()) { + // new entry + table[entryName] = new Entry(value); + } + else if (append) { + // append new reult to old entry + ei->second->appendValue(value); + } + else { + // override old entry + ei->second->setValue(value); + } +} + + +bool +IniFile::Section::add(const std::string &assignment) +{ + string::size_type offset = assignment.find('='); + if (offset == string::npos) { + // no '=' found + cerr << "Can't parse .ini line " << assignment << endl; + return false; + } + + // if "+=" rather than just "=" then append value + bool append = (assignment[offset-1] == '+'); + + string entryName = assignment.substr(0, append ? offset-1 : offset); + string value = assignment.substr(offset + 1); + + eat_white(entryName); + eat_white(value); + + addEntry(entryName, value, append); + return true; +} + + +IniFile::Entry * +IniFile::Section::findEntry(const std::string &entryName) const +{ + referenced = true; + + EntryTable::const_iterator ei = table.find(entryName); + + return (ei == table.end()) ? NULL : ei->second; +} + + +IniFile::Section * +IniFile::addSection(const string §ionName) +{ + SectionTable::iterator i = table.find(sectionName); + + if (i != table.end()) { + return i->second; + } + else { + // new entry + Section *sec = new Section(); + table[sectionName] = sec; + return sec; + } +} + + +IniFile::Section * +IniFile::findSection(const string §ionName) const +{ + SectionTable::const_iterator i = table.find(sectionName); + + return (i == table.end()) ? NULL : i->second; +} + + +// Take string of the form "<section>:<parameter>=<value>" and add to +// database. Return true if successful, false if parse error. +bool +IniFile::add(const string &str) +{ + // find ':' + string::size_type offset = str.find(':'); + if (offset == string::npos) // no ':' found + return false; + + string sectionName = str.substr(0, offset); + string rest = str.substr(offset + 1); + + eat_white(sectionName); + Section *s = addSection(sectionName); + + return s->add(rest); +} + +bool +IniFile::load(istream &f) +{ + Section *section = NULL; + + while (!f.eof()) { + f >> ws; // Eat whitespace + if (f.eof()) { + break; + } + + string line; + getline(f, line); + if (line.size() == 0) + continue; + + eat_end_white(line); + int last = line.size() - 1; + + if (line[0] == '[' && line[last] == ']') { + string sectionName = line.substr(1, last - 1); + eat_white(sectionName); + section = addSection(sectionName); + continue; + } + + if (section == NULL) + continue; + + if (!section->add(line)) + return false; + } + + return true; +} + +bool +IniFile::find(const string §ionName, const string &entryName, + string &value) const +{ + Section *section = findSection(sectionName); + if (section == NULL) + return false; + + Entry *entry = section->findEntry(entryName); + if (entry == NULL) + return false; + + value = entry->getValue(); + + return true; +} + +bool +IniFile::sectionExists(const string §ionName) const +{ + return findSection(sectionName) != NULL; +} + + +bool +IniFile::Section::printUnreferenced(const string §ionName) +{ + bool unref = false; + bool search_unref_entries = false; + vector<string> unref_ok_entries; + + Entry *entry = findEntry("unref_entries_ok"); + if (entry != NULL) { + tokenize(unref_ok_entries, entry->getValue(), ' '); + if (unref_ok_entries.size()) { + search_unref_entries = true; + } + } + + for (EntryTable::iterator ei = table.begin(); + ei != table.end(); ++ei) { + const string &entryName = ei->first; + Entry *entry = ei->second; + + if (entryName == "unref_section_ok" || + entryName == "unref_entries_ok") + { + continue; + } + + if (!entry->isReferenced()) { + if (search_unref_entries && + (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), + entryName) != unref_ok_entries.end())) + { + continue; + } + + cerr << "Parameter " << sectionName << ":" << entryName + << " not referenced." << endl; + unref = true; + } + } + + return unref; +} + + +bool +IniFile::printUnreferenced() +{ + bool unref = false; + + for (SectionTable::iterator i = table.begin(); + i != table.end(); ++i) { + const string §ionName = i->first; + Section *section = i->second; + + if (!section->isReferenced()) { + if (section->findEntry("unref_section_ok") == NULL) { + cerr << "Section " << sectionName << " not referenced." + << endl; + unref = true; + } + } + else { + if (section->printUnreferenced(sectionName)) { + unref = true; + } + } + } + + return unref; +} + + +void +IniFile::Section::dump(const string §ionName) +{ + for (EntryTable::iterator ei = table.begin(); + ei != table.end(); ++ei) { + cout << sectionName << ": " << (*ei).first << " => " + << (*ei).second->getValue() << "\n"; + } +} + +void +IniFile::dump() +{ + for (SectionTable::iterator i = table.begin(); + i != table.end(); ++i) { + i->second->dump(i->first); + } +} |