inifile.cc revision 10385
113221Sodanrc@yahoo.com.br/*
213221Sodanrc@yahoo.com.br * Copyright (c) 2001-2005 The Regents of The University of Michigan
313221Sodanrc@yahoo.com.br * All rights reserved.
413221Sodanrc@yahoo.com.br *
513221Sodanrc@yahoo.com.br * Redistribution and use in source and binary forms, with or without
613221Sodanrc@yahoo.com.br * modification, are permitted provided that the following conditions are
713221Sodanrc@yahoo.com.br * met: redistributions of source code must retain the above copyright
813221Sodanrc@yahoo.com.br * notice, this list of conditions and the following disclaimer;
913221Sodanrc@yahoo.com.br * redistributions in binary form must reproduce the above copyright
1013221Sodanrc@yahoo.com.br * notice, this list of conditions and the following disclaimer in the
1113221Sodanrc@yahoo.com.br * documentation and/or other materials provided with the distribution;
1213221Sodanrc@yahoo.com.br * neither the name of the copyright holders nor the names of its
1313221Sodanrc@yahoo.com.br * contributors may be used to endorse or promote products derived from
1413221Sodanrc@yahoo.com.br * this software without specific prior written permission.
1513221Sodanrc@yahoo.com.br *
1613221Sodanrc@yahoo.com.br * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1713221Sodanrc@yahoo.com.br * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1813221Sodanrc@yahoo.com.br * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1913221Sodanrc@yahoo.com.br * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2013221Sodanrc@yahoo.com.br * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2113221Sodanrc@yahoo.com.br * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2213221Sodanrc@yahoo.com.br * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2313221Sodanrc@yahoo.com.br * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2413221Sodanrc@yahoo.com.br * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2513221Sodanrc@yahoo.com.br * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2613221Sodanrc@yahoo.com.br * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2713221Sodanrc@yahoo.com.br *
2813221Sodanrc@yahoo.com.br * Authors: Nathan Binkert
2913221Sodanrc@yahoo.com.br *          Steve Reinhardt
3013221Sodanrc@yahoo.com.br */
3113221Sodanrc@yahoo.com.br
3213221Sodanrc@yahoo.com.br#include <algorithm>
3313221Sodanrc@yahoo.com.br#include <fstream>
3413221Sodanrc@yahoo.com.br#include <iostream>
3513221Sodanrc@yahoo.com.br#include <string>
3613221Sodanrc@yahoo.com.br#include <vector>
3713221Sodanrc@yahoo.com.br
3813221Sodanrc@yahoo.com.br#include "base/inifile.hh"
3913221Sodanrc@yahoo.com.br#include "base/str.hh"
4013221Sodanrc@yahoo.com.br
4113221Sodanrc@yahoo.com.brusing namespace std;
4213221Sodanrc@yahoo.com.br
4313221Sodanrc@yahoo.com.brIniFile::IniFile()
4413221Sodanrc@yahoo.com.br{}
4513221Sodanrc@yahoo.com.br
4613221Sodanrc@yahoo.com.brIniFile::~IniFile()
4713221Sodanrc@yahoo.com.br{
4813221Sodanrc@yahoo.com.br    SectionTable::iterator i = table.begin();
4913221Sodanrc@yahoo.com.br    SectionTable::iterator end = table.end();
5013221Sodanrc@yahoo.com.br
5113221Sodanrc@yahoo.com.br    while (i != end) {
5213221Sodanrc@yahoo.com.br        delete (*i).second;
5313221Sodanrc@yahoo.com.br        ++i;
5413221Sodanrc@yahoo.com.br    }
5513221Sodanrc@yahoo.com.br}
5613221Sodanrc@yahoo.com.br
5713221Sodanrc@yahoo.com.brbool
5813221Sodanrc@yahoo.com.brIniFile::load(const string &file)
5913221Sodanrc@yahoo.com.br{
6013221Sodanrc@yahoo.com.br    ifstream f(file.c_str());
6113221Sodanrc@yahoo.com.br
6213221Sodanrc@yahoo.com.br    if (!f.is_open())
6313221Sodanrc@yahoo.com.br        return false;
6413221Sodanrc@yahoo.com.br
6513221Sodanrc@yahoo.com.br    return load(f);
6613221Sodanrc@yahoo.com.br}
6713221Sodanrc@yahoo.com.br
6813221Sodanrc@yahoo.com.br
6913221Sodanrc@yahoo.com.brconst string &
7013221Sodanrc@yahoo.com.brIniFile::Entry::getValue() const
7113221Sodanrc@yahoo.com.br{
7213221Sodanrc@yahoo.com.br    referenced = true;
7313221Sodanrc@yahoo.com.br    return value;
7413221Sodanrc@yahoo.com.br}
7513221Sodanrc@yahoo.com.br
7613221Sodanrc@yahoo.com.br
7713221Sodanrc@yahoo.com.brvoid
7813221Sodanrc@yahoo.com.brIniFile::Section::addEntry(const std::string &entryName,
7913221Sodanrc@yahoo.com.br                           const std::string &value,
8013221Sodanrc@yahoo.com.br                           bool append)
8113221Sodanrc@yahoo.com.br{
8213221Sodanrc@yahoo.com.br    EntryTable::iterator ei = table.find(entryName);
8313221Sodanrc@yahoo.com.br
8413221Sodanrc@yahoo.com.br    if (ei == table.end()) {
8513221Sodanrc@yahoo.com.br        // new entry
8613221Sodanrc@yahoo.com.br        table[entryName] = new Entry(value);
8713221Sodanrc@yahoo.com.br    }
8813221Sodanrc@yahoo.com.br    else if (append) {
8913221Sodanrc@yahoo.com.br        // append new reult to old entry
9013221Sodanrc@yahoo.com.br        ei->second->appendValue(value);
9113221Sodanrc@yahoo.com.br    }
9213221Sodanrc@yahoo.com.br    else {
9313221Sodanrc@yahoo.com.br        // override old entry
9413221Sodanrc@yahoo.com.br        ei->second->setValue(value);
9513221Sodanrc@yahoo.com.br    }
9613221Sodanrc@yahoo.com.br}
9713221Sodanrc@yahoo.com.br
9813221Sodanrc@yahoo.com.br
9913221Sodanrc@yahoo.com.brbool
10013221Sodanrc@yahoo.com.brIniFile::Section::add(const std::string &assignment)
10113221Sodanrc@yahoo.com.br{
10213221Sodanrc@yahoo.com.br    string::size_type offset = assignment.find('=');
10313221Sodanrc@yahoo.com.br    if (offset == string::npos) {
10413221Sodanrc@yahoo.com.br        // no '=' found
10513221Sodanrc@yahoo.com.br        cerr << "Can't parse .ini line " << assignment << endl;
10613221Sodanrc@yahoo.com.br        return false;
10713221Sodanrc@yahoo.com.br    }
10813221Sodanrc@yahoo.com.br
10913221Sodanrc@yahoo.com.br    // if "+=" rather than just "=" then append value
11013221Sodanrc@yahoo.com.br    bool append = (assignment[offset-1] == '+');
11113221Sodanrc@yahoo.com.br
11213221Sodanrc@yahoo.com.br    string entryName = assignment.substr(0, append ? offset-1 : offset);
11313221Sodanrc@yahoo.com.br    string value = assignment.substr(offset + 1);
11413221Sodanrc@yahoo.com.br
11513221Sodanrc@yahoo.com.br    eat_white(entryName);
11613221Sodanrc@yahoo.com.br    eat_white(value);
11713221Sodanrc@yahoo.com.br
11813221Sodanrc@yahoo.com.br    addEntry(entryName, value, append);
11913221Sodanrc@yahoo.com.br    return true;
12013221Sodanrc@yahoo.com.br}
12113221Sodanrc@yahoo.com.br
12213221Sodanrc@yahoo.com.br
12313221Sodanrc@yahoo.com.brIniFile::Entry *
12413221Sodanrc@yahoo.com.brIniFile::Section::findEntry(const std::string &entryName) const
12513221Sodanrc@yahoo.com.br{
12613221Sodanrc@yahoo.com.br    referenced = true;
12713221Sodanrc@yahoo.com.br
12813221Sodanrc@yahoo.com.br    EntryTable::const_iterator ei = table.find(entryName);
12913221Sodanrc@yahoo.com.br
13013221Sodanrc@yahoo.com.br    return (ei == table.end()) ? NULL : ei->second;
13113221Sodanrc@yahoo.com.br}
13213221Sodanrc@yahoo.com.br
13313221Sodanrc@yahoo.com.br
13413221Sodanrc@yahoo.com.brIniFile::Section *
13513221Sodanrc@yahoo.com.brIniFile::addSection(const string &sectionName)
13613221Sodanrc@yahoo.com.br{
13713221Sodanrc@yahoo.com.br    SectionTable::iterator i = table.find(sectionName);
13813221Sodanrc@yahoo.com.br
13913221Sodanrc@yahoo.com.br    if (i != table.end()) {
14013221Sodanrc@yahoo.com.br        return i->second;
14113221Sodanrc@yahoo.com.br    }
14213221Sodanrc@yahoo.com.br    else {
14313221Sodanrc@yahoo.com.br        // new entry
14413221Sodanrc@yahoo.com.br        Section *sec = new Section();
14513221Sodanrc@yahoo.com.br        table[sectionName] = sec;
14613221Sodanrc@yahoo.com.br        return sec;
14713221Sodanrc@yahoo.com.br    }
14813221Sodanrc@yahoo.com.br}
14913221Sodanrc@yahoo.com.br
15013221Sodanrc@yahoo.com.br
15113221Sodanrc@yahoo.com.brIniFile::Section *
15213221Sodanrc@yahoo.com.brIniFile::findSection(const string &sectionName) const
15313221Sodanrc@yahoo.com.br{
15413221Sodanrc@yahoo.com.br    SectionTable::const_iterator i = table.find(sectionName);
15513221Sodanrc@yahoo.com.br
15613221Sodanrc@yahoo.com.br    return (i == table.end()) ? NULL : i->second;
15713221Sodanrc@yahoo.com.br}
15813221Sodanrc@yahoo.com.br
15913221Sodanrc@yahoo.com.br
16013221Sodanrc@yahoo.com.br// Take string of the form "<section>:<parameter>=<value>" and add to
16113221Sodanrc@yahoo.com.br// database.  Return true if successful, false if parse error.
16213221Sodanrc@yahoo.com.brbool
16313221Sodanrc@yahoo.com.brIniFile::add(const string &str)
16413221Sodanrc@yahoo.com.br{
16513221Sodanrc@yahoo.com.br    // find ':'
16613221Sodanrc@yahoo.com.br    string::size_type offset = str.find(':');
16713221Sodanrc@yahoo.com.br    if (offset == string::npos)  // no ':' found
16813221Sodanrc@yahoo.com.br        return false;
16913221Sodanrc@yahoo.com.br
17013221Sodanrc@yahoo.com.br    string sectionName = str.substr(0, offset);
17113221Sodanrc@yahoo.com.br    string rest = str.substr(offset + 1);
17213221Sodanrc@yahoo.com.br
17313221Sodanrc@yahoo.com.br    eat_white(sectionName);
17413221Sodanrc@yahoo.com.br    Section *s = addSection(sectionName);
17513221Sodanrc@yahoo.com.br
17613221Sodanrc@yahoo.com.br    return s->add(rest);
17713221Sodanrc@yahoo.com.br}
17813221Sodanrc@yahoo.com.br
17913221Sodanrc@yahoo.com.brbool
18013221Sodanrc@yahoo.com.brIniFile::load(istream &f)
18113221Sodanrc@yahoo.com.br{
18213221Sodanrc@yahoo.com.br    Section *section = NULL;
18313221Sodanrc@yahoo.com.br
18413221Sodanrc@yahoo.com.br    while (!f.eof()) {
18513221Sodanrc@yahoo.com.br        f >> ws; // Eat whitespace
18613221Sodanrc@yahoo.com.br        if (f.eof()) {
18713221Sodanrc@yahoo.com.br            break;
18813221Sodanrc@yahoo.com.br        }
18913221Sodanrc@yahoo.com.br
19013221Sodanrc@yahoo.com.br        string line;
19113221Sodanrc@yahoo.com.br        getline(f, line);
19213221Sodanrc@yahoo.com.br        if (line.size() == 0)
19313221Sodanrc@yahoo.com.br            continue;
19413221Sodanrc@yahoo.com.br
19513221Sodanrc@yahoo.com.br        eat_end_white(line);
19613221Sodanrc@yahoo.com.br        int last = line.size() - 1;
19713221Sodanrc@yahoo.com.br
19813221Sodanrc@yahoo.com.br        if (line[0] == '[' && line[last] == ']') {
19913221Sodanrc@yahoo.com.br            string sectionName = line.substr(1, last - 1);
20013221Sodanrc@yahoo.com.br            eat_white(sectionName);
20113221Sodanrc@yahoo.com.br            section = addSection(sectionName);
20213221Sodanrc@yahoo.com.br            continue;
20313221Sodanrc@yahoo.com.br        }
20413221Sodanrc@yahoo.com.br
20513221Sodanrc@yahoo.com.br        if (section == NULL)
20613221Sodanrc@yahoo.com.br            continue;
20713221Sodanrc@yahoo.com.br
20813221Sodanrc@yahoo.com.br        if (!section->add(line))
20913221Sodanrc@yahoo.com.br            return false;
21013221Sodanrc@yahoo.com.br    }
21113221Sodanrc@yahoo.com.br
21213221Sodanrc@yahoo.com.br    return true;
21313221Sodanrc@yahoo.com.br}
214
215bool
216IniFile::find(const string &sectionName, const string &entryName,
217              string &value) const
218{
219    Section *section = findSection(sectionName);
220    if (section == NULL)
221        return false;
222
223    Entry *entry = section->findEntry(entryName);
224    if (entry == NULL)
225        return false;
226
227    value = entry->getValue();
228
229    return true;
230}
231
232bool
233IniFile::sectionExists(const string &sectionName) const
234{
235    return findSection(sectionName) != NULL;
236}
237
238
239bool
240IniFile::Section::printUnreferenced(const string &sectionName)
241{
242    bool unref = false;
243    bool search_unref_entries = false;
244    vector<string> unref_ok_entries;
245
246    Entry *entry = findEntry("unref_entries_ok");
247    if (entry != NULL) {
248        tokenize(unref_ok_entries, entry->getValue(), ' ');
249        if (unref_ok_entries.size()) {
250            search_unref_entries = true;
251        }
252    }
253
254    for (EntryTable::iterator ei = table.begin();
255         ei != table.end(); ++ei) {
256        const string &entryName = ei->first;
257        entry = ei->second;
258
259        if (entryName == "unref_section_ok" ||
260            entryName == "unref_entries_ok")
261        {
262            continue;
263        }
264
265        if (!entry->isReferenced()) {
266            if (search_unref_entries &&
267                (std::find(unref_ok_entries.begin(), unref_ok_entries.end(),
268                           entryName) != unref_ok_entries.end()))
269            {
270                continue;
271            }
272
273            cerr << "Parameter " << sectionName << ":" << entryName
274                 << " not referenced." << endl;
275            unref = true;
276        }
277    }
278
279    return unref;
280}
281
282
283void
284IniFile::getSectionNames(vector<string> &list) const
285{
286    for (SectionTable::const_iterator i = table.begin();
287         i != table.end(); ++i)
288    {
289        list.push_back((*i).first);
290    }
291}
292
293bool
294IniFile::printUnreferenced()
295{
296    bool unref = false;
297
298    for (SectionTable::iterator i = table.begin();
299         i != table.end(); ++i) {
300        const string &sectionName = i->first;
301        Section *section = i->second;
302
303        if (!section->isReferenced()) {
304            if (section->findEntry("unref_section_ok") == NULL) {
305                cerr << "Section " << sectionName << " not referenced."
306                     << endl;
307                unref = true;
308            }
309        }
310        else {
311            if (section->printUnreferenced(sectionName)) {
312                unref = true;
313            }
314        }
315    }
316
317    return unref;
318}
319
320
321void
322IniFile::Section::dump(const string &sectionName)
323{
324    for (EntryTable::iterator ei = table.begin();
325         ei != table.end(); ++ei) {
326        cout << sectionName << ": " << (*ei).first << " => "
327             << (*ei).second->getValue() << "\n";
328    }
329}
330
331void
332IniFile::dump()
333{
334    for (SectionTable::iterator i = table.begin();
335         i != table.end(); ++i) {
336        i->second->dump(i->first);
337    }
338}
339