inifile.cc revision 8229:78bf55f23338
12036SN/A/* 22036SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 32036SN/A * All rights reserved. 42036SN/A * 52036SN/A * Redistribution and use in source and binary forms, with or without 62036SN/A * modification, are permitted provided that the following conditions are 72036SN/A * met: redistributions of source code must retain the above copyright 82036SN/A * notice, this list of conditions and the following disclaimer; 92036SN/A * redistributions in binary form must reproduce the above copyright 102036SN/A * notice, this list of conditions and the following disclaimer in the 112036SN/A * documentation and/or other materials provided with the distribution; 122036SN/A * neither the name of the copyright holders nor the names of its 132036SN/A * contributors may be used to endorse or promote products derived from 142036SN/A * this software without specific prior written permission. 152036SN/A * 162036SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172036SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182036SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192036SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202036SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212036SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222036SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232036SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242036SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252036SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262036SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282772Ssaidi@eecs.umich.edu * Authors: Nathan Binkert 292772Ssaidi@eecs.umich.edu * Steve Reinhardt 302036SN/A */ 312036SN/A 322036SN/A#include <fstream> 332036SN/A#include <iostream> 342036SN/A#include <string> 352036SN/A#include <vector> 362036SN/A 372036SN/A#include "base/inifile.hh" 382036SN/A#include "base/str.hh" 392036SN/A 402036SN/Ausing namespace std; 412036SN/A 422036SN/AIniFile::IniFile() 432036SN/A{} 442565SN/A 452565SN/AIniFile::~IniFile() 462565SN/A{ 472565SN/A SectionTable::iterator i = table.begin(); 482036SN/A SectionTable::iterator end = table.end(); 492036SN/A 502036SN/A while (i != end) { 512036SN/A delete (*i).second; 522778Ssaidi@eecs.umich.edu ++i; 532778Ssaidi@eecs.umich.edu } 542778Ssaidi@eecs.umich.edu} 552778Ssaidi@eecs.umich.edu 562036SN/Abool 572036SN/AIniFile::load(const string &file) 582036SN/A{ 592036SN/A ifstream f(file.c_str()); 602036SN/A 612565SN/A if (!f.is_open()) 622565SN/A return false; 632778Ssaidi@eecs.umich.edu 642778Ssaidi@eecs.umich.edu return load(f); 652565SN/A} 662036SN/A 672036SN/A 682036SN/Aconst string & 692036SN/AIniFile::Entry::getValue() const 702036SN/A{ 712036SN/A referenced = true; 722036SN/A return value; 732036SN/A} 742565SN/A 752036SN/A 762036SN/Avoid 772036SN/AIniFile::Section::addEntry(const std::string &entryName, 782036SN/A const std::string &value, 792036SN/A bool append) 802565SN/A{ 812565SN/A EntryTable::iterator ei = table.find(entryName); 822778Ssaidi@eecs.umich.edu 832778Ssaidi@eecs.umich.edu if (ei == table.end()) { 842565SN/A // new entry 852036SN/A table[entryName] = new Entry(value); 862036SN/A } 872036SN/A else if (append) { 882565SN/A // append new reult to old entry 892036SN/A ei->second->appendValue(value); 902036SN/A } 912036SN/A else { 922036SN/A // override old entry 932036SN/A ei->second->setValue(value); 942565SN/A } 952565SN/A} 962778Ssaidi@eecs.umich.edu 972778Ssaidi@eecs.umich.edu 982565SN/Abool 992036SN/AIniFile::Section::add(const std::string &assignment) 1002036SN/A{ 1012565SN/A string::size_type offset = assignment.find('='); 1022036SN/A if (offset == string::npos) { 1032036SN/A // no '=' found 1042764Sstever@eecs.umich.edu cerr << "Can't parse .ini line " << assignment << endl; 1052764Sstever@eecs.umich.edu return false; 1062764Sstever@eecs.umich.edu } 1072764Sstever@eecs.umich.edu 1082764Sstever@eecs.umich.edu // if "+=" rather than just "=" then append value 1092764Sstever@eecs.umich.edu bool append = (assignment[offset-1] == '+'); 1102764Sstever@eecs.umich.edu 1112764Sstever@eecs.umich.edu string entryName = assignment.substr(0, append ? offset-1 : offset); 1122764Sstever@eecs.umich.edu string value = assignment.substr(offset + 1); 1132764Sstever@eecs.umich.edu 1142764Sstever@eecs.umich.edu eat_white(entryName); 1152764Sstever@eecs.umich.edu eat_white(value); 1162764Sstever@eecs.umich.edu 1172764Sstever@eecs.umich.edu addEntry(entryName, value, append); 1182764Sstever@eecs.umich.edu return true; 1192764Sstever@eecs.umich.edu} 1202764Sstever@eecs.umich.edu 1212036SN/A 1222036SN/AIniFile::Entry * 1232036SN/AIniFile::Section::findEntry(const std::string &entryName) const 1242036SN/A{ 1252036SN/A referenced = true; 1262036SN/A 1272036SN/A EntryTable::const_iterator ei = table.find(entryName); 1282036SN/A 1292036SN/A return (ei == table.end()) ? NULL : ei->second; 1302036SN/A} 1312036SN/A 1322036SN/A 1332036SN/AIniFile::Section * 1342036SN/AIniFile::addSection(const string §ionName) 1352036SN/A{ 1362036SN/A SectionTable::iterator i = table.find(sectionName); 1372036SN/A 1382036SN/A if (i != table.end()) { 1392036SN/A return i->second; 1402036SN/A } 1412036SN/A else { 1422036SN/A // new entry 1432036SN/A Section *sec = new Section(); 1442036SN/A table[sectionName] = sec; 1452036SN/A return sec; 1462036SN/A } 1472036SN/A} 1482036SN/A 1492036SN/A 1502036SN/AIniFile::Section * 1512036SN/AIniFile::findSection(const string §ionName) const 1522036SN/A{ 1532036SN/A SectionTable::const_iterator i = table.find(sectionName); 1542036SN/A 1552036SN/A return (i == table.end()) ? NULL : i->second; 1562036SN/A} 1572036SN/A 1582036SN/A 1592036SN/A// Take string of the form "<section>:<parameter>=<value>" and add to 1602036SN/A// database. Return true if successful, false if parse error. 1612036SN/Abool 1622036SN/AIniFile::add(const string &str) 1632036SN/A{ 1642036SN/A // find ':' 1652036SN/A string::size_type offset = str.find(':'); 1662036SN/A if (offset == string::npos) // no ':' found 1672036SN/A return false; 1682036SN/A 1692036SN/A string sectionName = str.substr(0, offset); 1702036SN/A string rest = str.substr(offset + 1); 1712036SN/A 1722036SN/A eat_white(sectionName); 1732036SN/A Section *s = addSection(sectionName); 1742036SN/A 175 return s->add(rest); 176} 177 178bool 179IniFile::load(istream &f) 180{ 181 Section *section = NULL; 182 183 while (!f.eof()) { 184 f >> ws; // Eat whitespace 185 if (f.eof()) { 186 break; 187 } 188 189 string line; 190 getline(f, line); 191 if (line.size() == 0) 192 continue; 193 194 eat_end_white(line); 195 int last = line.size() - 1; 196 197 if (line[0] == '[' && line[last] == ']') { 198 string sectionName = line.substr(1, last - 1); 199 eat_white(sectionName); 200 section = addSection(sectionName); 201 continue; 202 } 203 204 if (section == NULL) 205 continue; 206 207 if (!section->add(line)) 208 return false; 209 } 210 211 return true; 212} 213 214bool 215IniFile::find(const string §ionName, const string &entryName, 216 string &value) const 217{ 218 Section *section = findSection(sectionName); 219 if (section == NULL) 220 return false; 221 222 Entry *entry = section->findEntry(entryName); 223 if (entry == NULL) 224 return false; 225 226 value = entry->getValue(); 227 228 return true; 229} 230 231bool 232IniFile::sectionExists(const string §ionName) const 233{ 234 return findSection(sectionName) != NULL; 235} 236 237 238bool 239IniFile::Section::printUnreferenced(const string §ionName) 240{ 241 bool unref = false; 242 bool search_unref_entries = false; 243 vector<string> unref_ok_entries; 244 245 Entry *entry = findEntry("unref_entries_ok"); 246 if (entry != NULL) { 247 tokenize(unref_ok_entries, entry->getValue(), ' '); 248 if (unref_ok_entries.size()) { 249 search_unref_entries = true; 250 } 251 } 252 253 for (EntryTable::iterator ei = table.begin(); 254 ei != table.end(); ++ei) { 255 const string &entryName = ei->first; 256 Entry *entry = ei->second; 257 258 if (entryName == "unref_section_ok" || 259 entryName == "unref_entries_ok") 260 { 261 continue; 262 } 263 264 if (!entry->isReferenced()) { 265 if (search_unref_entries && 266 (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), 267 entryName) != unref_ok_entries.end())) 268 { 269 continue; 270 } 271 272 cerr << "Parameter " << sectionName << ":" << entryName 273 << " not referenced." << endl; 274 unref = true; 275 } 276 } 277 278 return unref; 279} 280 281 282bool 283IniFile::printUnreferenced() 284{ 285 bool unref = false; 286 287 for (SectionTable::iterator i = table.begin(); 288 i != table.end(); ++i) { 289 const string §ionName = i->first; 290 Section *section = i->second; 291 292 if (!section->isReferenced()) { 293 if (section->findEntry("unref_section_ok") == NULL) { 294 cerr << "Section " << sectionName << " not referenced." 295 << endl; 296 unref = true; 297 } 298 } 299 else { 300 if (section->printUnreferenced(sectionName)) { 301 unref = true; 302 } 303 } 304 } 305 306 return unref; 307} 308 309 310void 311IniFile::Section::dump(const string §ionName) 312{ 313 for (EntryTable::iterator ei = table.begin(); 314 ei != table.end(); ++ei) { 315 cout << sectionName << ": " << (*ei).first << " => " 316 << (*ei).second->getValue() << "\n"; 317 } 318} 319 320void 321IniFile::dump() 322{ 323 for (SectionTable::iterator i = table.begin(); 324 i != table.end(); ++i) { 325 i->second->dump(i->first); 326 } 327} 328