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 * Authors: Nathan Binkert 29 * Steve Reinhardt 30 */ 31 32#include "base/inifile.hh" 33 34#include <algorithm> 35#include <fstream> 36#include <iostream> 37#include <string> 38#include <vector> 39 40#include "base/str.hh" 41 42using namespace std; 43 44IniFile::IniFile() 45{} 46 47IniFile::~IniFile() 48{ 49 SectionTable::iterator i = table.begin(); 50 SectionTable::iterator end = table.end(); 51 52 while (i != end) { 53 delete (*i).second; 54 ++i; 55 } 56} 57 58bool 59IniFile::load(const string &file) 60{ 61 ifstream f(file.c_str()); 62 63 if (!f.is_open()) 64 return false; 65 66 return load(f); 67} 68 69 70const string & 71IniFile::Entry::getValue() const 72{ 73 referenced = true; 74 return value; 75} 76 77 78void 79IniFile::Section::addEntry(const std::string &entryName, 80 const std::string &value, 81 bool append) 82{ 83 EntryTable::iterator ei = table.find(entryName); 84 85 if (ei == table.end()) { 86 // new entry 87 table[entryName] = new Entry(value); 88 } 89 else if (append) { 90 // append new reult to old entry 91 ei->second->appendValue(value); 92 } 93 else { 94 // override old entry 95 ei->second->setValue(value); 96 } 97} 98 99 100bool 101IniFile::Section::add(const std::string &assignment) 102{ 103 string::size_type offset = assignment.find('='); 104 if (offset == string::npos) { 105 // no '=' found 106 cerr << "Can't parse .ini line " << assignment << endl; 107 return false; 108 } 109 110 // if "+=" rather than just "=" then append value 111 bool append = (assignment[offset-1] == '+'); 112 113 string entryName = assignment.substr(0, append ? offset-1 : offset); 114 string value = assignment.substr(offset + 1); 115 116 eat_white(entryName); 117 eat_white(value); 118 119 addEntry(entryName, value, append); 120 return true; 121} 122 123 124IniFile::Entry * 125IniFile::Section::findEntry(const std::string &entryName) const 126{ 127 referenced = true; 128 129 EntryTable::const_iterator ei = table.find(entryName); 130 131 return (ei == table.end()) ? NULL : ei->second; 132} 133 134 135IniFile::Section * 136IniFile::addSection(const string §ionName) 137{ 138 SectionTable::iterator i = table.find(sectionName); 139 140 if (i != table.end()) { 141 return i->second; 142 } 143 else { 144 // new entry 145 Section *sec = new Section(); 146 table[sectionName] = sec; 147 return sec; 148 } 149} 150 151 152IniFile::Section * 153IniFile::findSection(const string §ionName) const 154{ 155 SectionTable::const_iterator i = table.find(sectionName); 156 157 return (i == table.end()) ? NULL : i->second; 158} 159 160 161// Take string of the form "<section>:<parameter>=<value>" and add to 162// database. Return true if successful, false if parse error. 163bool 164IniFile::add(const string &str) 165{ 166 // find ':' 167 string::size_type offset = str.find(':'); 168 if (offset == string::npos) // no ':' found 169 return false; 170 171 string sectionName = str.substr(0, offset); 172 string rest = str.substr(offset + 1); 173 174 eat_white(sectionName); 175 Section *s = addSection(sectionName); 176 177 return s->add(rest); 178} 179 180bool 181IniFile::load(istream &f) 182{ 183 Section *section = NULL; 184 185 while (!f.eof()) { 186 f >> ws; // Eat whitespace 187 if (f.eof()) { 188 break; 189 } 190 191 string line; 192 getline(f, line); 193 if (line.size() == 0) 194 continue; 195 196 eat_end_white(line); 197 int last = line.size() - 1; 198 199 if (line[0] == '[' && line[last] == ']') { 200 string sectionName = line.substr(1, last - 1); 201 eat_white(sectionName); 202 section = addSection(sectionName); 203 continue; 204 } 205 206 if (section == NULL) 207 continue; 208 209 if (!section->add(line)) 210 return false; 211 } 212 213 return true; 214} 215 216bool 217IniFile::find(const string §ionName, const string &entryName, 218 string &value) const 219{ 220 Section *section = findSection(sectionName); 221 if (section == NULL) 222 return false; 223 224 Entry *entry = section->findEntry(entryName); 225 if (entry == NULL) 226 return false; 227 228 value = entry->getValue(); 229 230 return true; 231} 232 233bool 234IniFile::entryExists(const string §ionName, const string &entryName) const 235{ 236 Section *section = findSection(sectionName); 237 238 if (!section) 239 return false; 240 else 241 return section->findEntry(entryName); 242} 243 244bool 245IniFile::sectionExists(const string §ionName) const 246{ 247 return findSection(sectionName) != NULL; 248} 249 250 251bool 252IniFile::Section::printUnreferenced(const string §ionName) 253{ 254 bool unref = false; 255 bool search_unref_entries = false; 256 vector<string> unref_ok_entries; 257 258 Entry *entry = findEntry("unref_entries_ok"); 259 if (entry != NULL) { 260 tokenize(unref_ok_entries, entry->getValue(), ' '); 261 if (unref_ok_entries.size()) { 262 search_unref_entries = true; 263 } 264 } 265 266 for (EntryTable::iterator ei = table.begin(); 267 ei != table.end(); ++ei) { 268 const string &entryName = ei->first; 269 entry = ei->second; 270 271 if (entryName == "unref_section_ok" || 272 entryName == "unref_entries_ok") 273 { 274 continue; 275 } 276 277 if (!entry->isReferenced()) { 278 if (search_unref_entries && 279 (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), 280 entryName) != unref_ok_entries.end())) 281 { 282 continue; 283 } 284 285 cerr << "Parameter " << sectionName << ":" << entryName 286 << " not referenced." << endl; 287 unref = true; 288 } 289 } 290 291 return unref; 292} 293 294 295void 296IniFile::getSectionNames(vector<string> &list) const 297{ 298 for (SectionTable::const_iterator i = table.begin(); 299 i != table.end(); ++i) 300 { 301 list.push_back((*i).first); 302 } 303} 304 305bool 306IniFile::printUnreferenced() 307{ 308 bool unref = false; 309 310 for (SectionTable::iterator i = table.begin(); 311 i != table.end(); ++i) { 312 const string §ionName = i->first; 313 Section *section = i->second; 314 315 if (!section->isReferenced()) { 316 if (section->findEntry("unref_section_ok") == NULL) { 317 cerr << "Section " << sectionName << " not referenced." 318 << endl; 319 unref = true; 320 } 321 } 322 else { 323 if (section->printUnreferenced(sectionName)) { 324 unref = true; 325 } 326 } 327 } 328 329 return unref; 330} 331 332 333void 334IniFile::Section::dump(const string §ionName) 335{ 336 for (EntryTable::iterator ei = table.begin(); 337 ei != table.end(); ++ei) { 338 cout << sectionName << ": " << (*ei).first << " => " 339 << (*ei).second->getValue() << "\n"; 340 } 341} 342 343void 344IniFile::dump() 345{ 346 for (SectionTable::iterator i = table.begin(); 347 i != table.end(); ++i) { 348 i->second->dump(i->first); 349 } 350} 351