inifile.cc revision 178
110612SMarco.Elver@ARM.com/*
210612SMarco.Elver@ARM.com * Copyright (c) 2003 The Regents of The University of Michigan
310612SMarco.Elver@ARM.com * All rights reserved.
410612SMarco.Elver@ARM.com *
510612SMarco.Elver@ARM.com * Redistribution and use in source and binary forms, with or without
610612SMarco.Elver@ARM.com * modification, are permitted provided that the following conditions are
710612SMarco.Elver@ARM.com * met: redistributions of source code must retain the above copyright
810612SMarco.Elver@ARM.com * notice, this list of conditions and the following disclaimer;
910612SMarco.Elver@ARM.com * redistributions in binary form must reproduce the above copyright
1010612SMarco.Elver@ARM.com * notice, this list of conditions and the following disclaimer in the
1110612SMarco.Elver@ARM.com * documentation and/or other materials provided with the distribution;
1210612SMarco.Elver@ARM.com * neither the name of the copyright holders nor the names of its
1310612SMarco.Elver@ARM.com * contributors may be used to endorse or promote products derived from
1410612SMarco.Elver@ARM.com * this software without specific prior written permission.
1510612SMarco.Elver@ARM.com *
1610612SMarco.Elver@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1710612SMarco.Elver@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1810612SMarco.Elver@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1910612SMarco.Elver@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2010612SMarco.Elver@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2110612SMarco.Elver@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2210612SMarco.Elver@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2310612SMarco.Elver@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2410612SMarco.Elver@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2510612SMarco.Elver@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2610612SMarco.Elver@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710612SMarco.Elver@ARM.com */
2810612SMarco.Elver@ARM.com
2910612SMarco.Elver@ARM.com#define USE_CPP
3010612SMarco.Elver@ARM.com// #define CPP_PIPE
3110612SMarco.Elver@ARM.com
3210612SMarco.Elver@ARM.com
3310612SMarco.Elver@ARM.com#ifdef USE_CPP
3410612SMarco.Elver@ARM.com#include <sys/signal.h>
3510612SMarco.Elver@ARM.com#include <sys/types.h>
3610612SMarco.Elver@ARM.com#include <sys/wait.h>
3710612SMarco.Elver@ARM.com
3810612SMarco.Elver@ARM.com#include <stdio.h>
3910612SMarco.Elver@ARM.com#include <stdlib.h>
4010612SMarco.Elver@ARM.com#include <unistd.h>
4110612SMarco.Elver@ARM.com#endif
4211793Sbrandon.potter@amd.com
4311793Sbrandon.potter@amd.com#include <fstream>
4410612SMarco.Elver@ARM.com#include <iostream>
4510612SMarco.Elver@ARM.com#if __GNUC__ >= 3
4613449Sgabeblack@google.com#include <ext/stdio_filebuf.h>
4710612SMarco.Elver@ARM.com#endif
4810612SMarco.Elver@ARM.com
4910612SMarco.Elver@ARM.com#include <vector>
5010612SMarco.Elver@ARM.com#include <string>
5110612SMarco.Elver@ARM.com
5213892Sgabeblack@google.com#include "base/inifile.hh"
5310612SMarco.Elver@ARM.com#include "base/str.hh"
5410612SMarco.Elver@ARM.com
5510612SMarco.Elver@ARM.comusing namespace std;
5610612SMarco.Elver@ARM.com
5710612SMarco.Elver@ARM.comIniFile::IniFile()
5810612SMarco.Elver@ARM.com{}
5910612SMarco.Elver@ARM.com
6010612SMarco.Elver@ARM.comIniFile::~IniFile()
6110612SMarco.Elver@ARM.com{
6210612SMarco.Elver@ARM.com    SectionTable::iterator i = table.begin();
6310612SMarco.Elver@ARM.com    SectionTable::iterator end = table.end();
6410612SMarco.Elver@ARM.com
6510612SMarco.Elver@ARM.com    while (i != end) {
6610612SMarco.Elver@ARM.com        delete (*i).second;
6710612SMarco.Elver@ARM.com        ++i;
6810612SMarco.Elver@ARM.com    }
6910612SMarco.Elver@ARM.com}
7010612SMarco.Elver@ARM.com
7110612SMarco.Elver@ARM.com
7210612SMarco.Elver@ARM.com#ifdef USE_CPP
7310612SMarco.Elver@ARM.combool
7410612SMarco.Elver@ARM.comIniFile::loadCPP(const string &file, vector<char *> &cppArgs)
7510612SMarco.Elver@ARM.com{
7613784Sgabeblack@google.com    int fd[2];
7713784Sgabeblack@google.com
7810612SMarco.Elver@ARM.com    // Open the file just to verify that we can.  Otherwise if the
7910612SMarco.Elver@ARM.com    // file doesn't exist or has bad permissions the user will get
8010612SMarco.Elver@ARM.com    // confusing errors from cpp/g++.
8113784Sgabeblack@google.com    ifstream tmpf(file.c_str());
8210612SMarco.Elver@ARM.com
8310612SMarco.Elver@ARM.com    if (!tmpf.is_open())
8413892Sgabeblack@google.com        return false;
8510612SMarco.Elver@ARM.com
8610612SMarco.Elver@ARM.com    tmpf.close();
8710612SMarco.Elver@ARM.com
8810612SMarco.Elver@ARM.com#ifdef CPP_PIPE
8910612SMarco.Elver@ARM.com    if (pipe(fd) == -1)
9010612SMarco.Elver@ARM.com        return false;
9110612SMarco.Elver@ARM.com#else
9210612SMarco.Elver@ARM.com    char tempfile[] = "/tmp/configXXXXXX";
9310612SMarco.Elver@ARM.com    fd[0] = fd[1] = mkstemp(tempfile);
9410612SMarco.Elver@ARM.com#endif
9510612SMarco.Elver@ARM.com
9610612SMarco.Elver@ARM.com    int pid = fork();
9710612SMarco.Elver@ARM.com
9810612SMarco.Elver@ARM.com    if (pid == -1)
9910612SMarco.Elver@ARM.com        return 1;
10010612SMarco.Elver@ARM.com
10110612SMarco.Elver@ARM.com    if (pid == 0) {
10210612SMarco.Elver@ARM.com        char filename[FILENAME_MAX];
10310612SMarco.Elver@ARM.com        string::size_type i = file.copy(filename, sizeof(filename) - 1);
10410612SMarco.Elver@ARM.com        filename[i] = '\0';
10510612SMarco.Elver@ARM.com
10610612SMarco.Elver@ARM.com        int arg_count = cppArgs.size();
10710612SMarco.Elver@ARM.com
10810612SMarco.Elver@ARM.com        char **args = new char *[arg_count + 20];
10910612SMarco.Elver@ARM.com
11010612SMarco.Elver@ARM.com        int nextArg = 0;
11110612SMarco.Elver@ARM.com        args[nextArg++] = "g++";
11210612SMarco.Elver@ARM.com        args[nextArg++] = "-E";
11310612SMarco.Elver@ARM.com        args[nextArg++] = "-P";
11410612SMarco.Elver@ARM.com        args[nextArg++] = "-nostdinc";
11510612SMarco.Elver@ARM.com        args[nextArg++] = "-nostdinc++";
11610612SMarco.Elver@ARM.com        args[nextArg++] = "-x";
11710612SMarco.Elver@ARM.com        args[nextArg++] = "c++";
11810612SMarco.Elver@ARM.com        args[nextArg++] = "-undef";
11910612SMarco.Elver@ARM.com
12010612SMarco.Elver@ARM.com        for (int i = 0; i < arg_count; i++)
12110612SMarco.Elver@ARM.com            args[nextArg++] = cppArgs[i];
12210612SMarco.Elver@ARM.com
12310612SMarco.Elver@ARM.com        args[nextArg++] = filename;
12410612SMarco.Elver@ARM.com        args[nextArg++] = NULL;
12513449Sgabeblack@google.com
12610612SMarco.Elver@ARM.com        close(STDOUT_FILENO);
12710612SMarco.Elver@ARM.com        if (dup2(fd[1], STDOUT_FILENO) == -1)
12810612SMarco.Elver@ARM.com            return 1;
12910612SMarco.Elver@ARM.com
13010612SMarco.Elver@ARM.com        execvp("g++", args);
13113449Sgabeblack@google.com
13210612SMarco.Elver@ARM.com        exit(1);
13310612SMarco.Elver@ARM.com    }
13410612SMarco.Elver@ARM.com
13510612SMarco.Elver@ARM.com    int retval;
13610612SMarco.Elver@ARM.com    waitpid(pid, &retval, 0);
13710612SMarco.Elver@ARM.com
13810612SMarco.Elver@ARM.com    // check for normal completion of CPP
13910612SMarco.Elver@ARM.com    if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0)
14010612SMarco.Elver@ARM.com        return false;
14110612SMarco.Elver@ARM.com
14210612SMarco.Elver@ARM.com#ifdef CPP_PIPE
14310612SMarco.Elver@ARM.com    close(fd[1]);
14410612SMarco.Elver@ARM.com#else
14510612SMarco.Elver@ARM.com    lseek(fd[0], 0, SEEK_SET);
14610612SMarco.Elver@ARM.com#endif
14710612SMarco.Elver@ARM.com
14810612SMarco.Elver@ARM.com    bool status = false;
14911284Sandreas.hansson@arm.com
15011489Sandreas.hansson@arm.com#if __GNUC__ >= 3
15110612SMarco.Elver@ARM.com    using namespace __gnu_cxx;
15210612SMarco.Elver@ARM.com    stdio_filebuf<char> fbuf(fd[0], ios_base::in, true,
15310612SMarco.Elver@ARM.com        static_cast<stdio_filebuf<char>::int_type>(BUFSIZ));
15410612SMarco.Elver@ARM.com
15510612SMarco.Elver@ARM.com    if (fbuf.is_open()) {
15610612SMarco.Elver@ARM.com        istream f(&fbuf);
15710612SMarco.Elver@ARM.com        status = load(f);
15813377Sodanrc@yahoo.com.br    }
15910612SMarco.Elver@ARM.com
16010612SMarco.Elver@ARM.com#else
16110612SMarco.Elver@ARM.com    ifstream f(fd[0]);
16210612SMarco.Elver@ARM.com    if (f.is_open())
16311284Sandreas.hansson@arm.com        status = load(f);
16410612SMarco.Elver@ARM.com#endif
16510612SMarco.Elver@ARM.com
16610612SMarco.Elver@ARM.com#ifndef CPP_PIPE
16710612SMarco.Elver@ARM.com    unlink(tempfile);
16810612SMarco.Elver@ARM.com#endif
16910612SMarco.Elver@ARM.com
17011284Sandreas.hansson@arm.com    return status;
17110612SMarco.Elver@ARM.com}
17210612SMarco.Elver@ARM.com#endif
17310612SMarco.Elver@ARM.com
17410612SMarco.Elver@ARM.combool
17510612SMarco.Elver@ARM.comIniFile::load(const string &file)
17610612SMarco.Elver@ARM.com{
17710612SMarco.Elver@ARM.com    ifstream f(file.c_str());
17810612SMarco.Elver@ARM.com
17910612SMarco.Elver@ARM.com    if (!f.is_open())
18010612SMarco.Elver@ARM.com        return false;
18110612SMarco.Elver@ARM.com
18210612SMarco.Elver@ARM.com    return load(f);
18310612SMarco.Elver@ARM.com}
18410612SMarco.Elver@ARM.com
18510612SMarco.Elver@ARM.com
18610612SMarco.Elver@ARM.comconst string &
18710612SMarco.Elver@ARM.comIniFile::Entry::getValue() const
18810612SMarco.Elver@ARM.com{
18910612SMarco.Elver@ARM.com    referenced = true;
19010612SMarco.Elver@ARM.com    return value;
19110612SMarco.Elver@ARM.com}
19210612SMarco.Elver@ARM.com
19310612SMarco.Elver@ARM.com
19410612SMarco.Elver@ARM.comvoid
19510612SMarco.Elver@ARM.comIniFile::Section::addEntry(const std::string &entryName,
19610612SMarco.Elver@ARM.com                           const std::string &value,
19710612SMarco.Elver@ARM.com                           bool append)
19810612SMarco.Elver@ARM.com{
19910612SMarco.Elver@ARM.com    EntryTable::iterator ei = table.find(entryName);
20010612SMarco.Elver@ARM.com
20110612SMarco.Elver@ARM.com    if (ei == table.end()) {
20210612SMarco.Elver@ARM.com        // new entry
20310612SMarco.Elver@ARM.com        table[entryName] = new Entry(value);
20410612SMarco.Elver@ARM.com    }
20510612SMarco.Elver@ARM.com    else if (append) {
20610612SMarco.Elver@ARM.com        // append new reult to old entry
20710612SMarco.Elver@ARM.com        ei->second->appendValue(value);
20810612SMarco.Elver@ARM.com    }
20910612SMarco.Elver@ARM.com    else {
21010612SMarco.Elver@ARM.com        // override old entry
21110612SMarco.Elver@ARM.com        ei->second->setValue(value);
21210612SMarco.Elver@ARM.com    }
21310612SMarco.Elver@ARM.com}
21410612SMarco.Elver@ARM.com
21510612SMarco.Elver@ARM.com
21610612SMarco.Elver@ARM.combool
21710612SMarco.Elver@ARM.comIniFile::Section::add(const std::string &assignment)
21810612SMarco.Elver@ARM.com{
21911284Sandreas.hansson@arm.com    string::size_type offset = assignment.find('=');
22011284Sandreas.hansson@arm.com    if (offset == string::npos) {
22110612SMarco.Elver@ARM.com        // no '=' found
22210612SMarco.Elver@ARM.com        cerr << "Can't parse .ini line " << assignment << endl;
22310612SMarco.Elver@ARM.com        return false;
22410612SMarco.Elver@ARM.com    }
22510612SMarco.Elver@ARM.com
22610612SMarco.Elver@ARM.com    // if "+=" rather than just "=" then append value
22710612SMarco.Elver@ARM.com    bool append = (assignment[offset-1] == '+');
22810612SMarco.Elver@ARM.com
22910612SMarco.Elver@ARM.com    string entryName = assignment.substr(0, append ? offset-1 : offset);
23010612SMarco.Elver@ARM.com    string value = assignment.substr(offset + 1);
23110612SMarco.Elver@ARM.com
23210612SMarco.Elver@ARM.com    eat_white(entryName);
23310612SMarco.Elver@ARM.com    eat_white(value);
23410612SMarco.Elver@ARM.com
23510612SMarco.Elver@ARM.com    addEntry(entryName, value, append);
23610612SMarco.Elver@ARM.com    return true;
23710612SMarco.Elver@ARM.com}
23810612SMarco.Elver@ARM.com
23911489Sandreas.hansson@arm.com
24010612SMarco.Elver@ARM.comIniFile::Entry *
24110612SMarco.Elver@ARM.comIniFile::Section::findEntry(const std::string &entryName) const
24210612SMarco.Elver@ARM.com{
24310612SMarco.Elver@ARM.com    referenced = true;
24410612SMarco.Elver@ARM.com
24510612SMarco.Elver@ARM.com    EntryTable::const_iterator ei = table.find(entryName);
24610612SMarco.Elver@ARM.com
24713377Sodanrc@yahoo.com.br    return (ei == table.end()) ? NULL : ei->second;
24810612SMarco.Elver@ARM.com}
24910612SMarco.Elver@ARM.com
25010612SMarco.Elver@ARM.com
25110612SMarco.Elver@ARM.comIniFile::Section *
25210612SMarco.Elver@ARM.comIniFile::addSection(const string &sectionName)
25310612SMarco.Elver@ARM.com{
25410612SMarco.Elver@ARM.com    SectionTable::iterator i = table.find(sectionName);
25510612SMarco.Elver@ARM.com
25610612SMarco.Elver@ARM.com    if (i != table.end()) {
25710612SMarco.Elver@ARM.com        return i->second;
25810612SMarco.Elver@ARM.com    }
25910612SMarco.Elver@ARM.com    else {
26010612SMarco.Elver@ARM.com        // new entry
26110612SMarco.Elver@ARM.com        Section *sec = new Section();
26210612SMarco.Elver@ARM.com        table[sectionName] = sec;
26310612SMarco.Elver@ARM.com        return sec;
26410612SMarco.Elver@ARM.com    }
26510612SMarco.Elver@ARM.com}
26610612SMarco.Elver@ARM.com
26710612SMarco.Elver@ARM.com
26810612SMarco.Elver@ARM.comIniFile::Section *
26910612SMarco.Elver@ARM.comIniFile::findSection(const string &sectionName) const
27010612SMarco.Elver@ARM.com{
27110612SMarco.Elver@ARM.com    SectionTable::const_iterator i = table.find(sectionName);
27210612SMarco.Elver@ARM.com
27310612SMarco.Elver@ARM.com    return (i == table.end()) ? NULL : i->second;
27410612SMarco.Elver@ARM.com}
27510612SMarco.Elver@ARM.com
27610612SMarco.Elver@ARM.com
27710612SMarco.Elver@ARM.com// Take string of the form "<section>:<parameter>=<value>" and add to
27810612SMarco.Elver@ARM.com// database.  Return true if successful, false if parse error.
27910612SMarco.Elver@ARM.combool
28010612SMarco.Elver@ARM.comIniFile::add(const string &str)
28110612SMarco.Elver@ARM.com{
28210612SMarco.Elver@ARM.com    // find ':'
28310612SMarco.Elver@ARM.com    string::size_type offset = str.find(':');
28410612SMarco.Elver@ARM.com    if (offset == string::npos)  // no ':' found
28510612SMarco.Elver@ARM.com        return false;
28610612SMarco.Elver@ARM.com
28710612SMarco.Elver@ARM.com    string sectionName = str.substr(0, offset);
28810612SMarco.Elver@ARM.com    string rest = str.substr(offset + 1);
28910612SMarco.Elver@ARM.com
29010612SMarco.Elver@ARM.com    eat_white(sectionName);
29110612SMarco.Elver@ARM.com    Section *s = addSection(sectionName);
29210612SMarco.Elver@ARM.com
29310612SMarco.Elver@ARM.com    return s->add(rest);
29410612SMarco.Elver@ARM.com}
29510612SMarco.Elver@ARM.com
29610612SMarco.Elver@ARM.combool
29710612SMarco.Elver@ARM.comIniFile::load(istream &f)
29810612SMarco.Elver@ARM.com{
29910612SMarco.Elver@ARM.com    Section *section = NULL;
30010612SMarco.Elver@ARM.com
30110612SMarco.Elver@ARM.com    while (!f.eof()) {
30210612SMarco.Elver@ARM.com        f >> ws; // Eat whitespace
30310612SMarco.Elver@ARM.com        if (f.eof()) {
30410612SMarco.Elver@ARM.com            break;
30510612SMarco.Elver@ARM.com        }
30610612SMarco.Elver@ARM.com
30710612SMarco.Elver@ARM.com        string line;
30810612SMarco.Elver@ARM.com        getline(f, line);
30910612SMarco.Elver@ARM.com        if (line.size() == 0)
31010612SMarco.Elver@ARM.com            continue;
31110612SMarco.Elver@ARM.com
31210612SMarco.Elver@ARM.com        eat_end_white(line);
31310612SMarco.Elver@ARM.com        int last = line.size() - 1;
31410612SMarco.Elver@ARM.com
31510612SMarco.Elver@ARM.com        if (line[0] == '[' && line[last] == ']') {
31610612SMarco.Elver@ARM.com            string sectionName = line.substr(1, last - 1);
31710612SMarco.Elver@ARM.com            eat_white(sectionName);
31810612SMarco.Elver@ARM.com            section = addSection(sectionName);
31910612SMarco.Elver@ARM.com            continue;
32010612SMarco.Elver@ARM.com        }
32110612SMarco.Elver@ARM.com
32210612SMarco.Elver@ARM.com        if (section == NULL)
32310612SMarco.Elver@ARM.com            continue;
32410612SMarco.Elver@ARM.com
32510612SMarco.Elver@ARM.com        if (!section->add(line))
32610612SMarco.Elver@ARM.com            return false;
32710612SMarco.Elver@ARM.com    }
32810612SMarco.Elver@ARM.com
32910612SMarco.Elver@ARM.com    return true;
33010612SMarco.Elver@ARM.com}
33110612SMarco.Elver@ARM.com
33210612SMarco.Elver@ARM.combool
33310612SMarco.Elver@ARM.comIniFile::find(const string &sectionName, const string &entryName,
33410612SMarco.Elver@ARM.com              string &value) const
33510612SMarco.Elver@ARM.com{
33610612SMarco.Elver@ARM.com    Section *section = findSection(sectionName);
33710612SMarco.Elver@ARM.com    if (section == NULL)
33810612SMarco.Elver@ARM.com        return false;
33910612SMarco.Elver@ARM.com
34010612SMarco.Elver@ARM.com    Entry *entry = section->findEntry(entryName);
34110612SMarco.Elver@ARM.com    if (entry == NULL)
34210612SMarco.Elver@ARM.com        return false;
34310612SMarco.Elver@ARM.com
34410612SMarco.Elver@ARM.com    value = entry->getValue();
34510612SMarco.Elver@ARM.com
34610612SMarco.Elver@ARM.com    return true;
34710612SMarco.Elver@ARM.com}
34810612SMarco.Elver@ARM.com
34910713Sandreas.hansson@arm.combool
35010612SMarco.Elver@ARM.comIniFile::findDefault(const string &_section, const string &entry,
35110713Sandreas.hansson@arm.com                     string &value) const
35210612SMarco.Elver@ARM.com{
35310612SMarco.Elver@ARM.com    string section = _section;
35410612SMarco.Elver@ARM.com    while (!find(section, entry, value)) {
35510713Sandreas.hansson@arm.com        if (!find(section, "default", section))
35610612SMarco.Elver@ARM.com            return false;
35710713Sandreas.hansson@arm.com    }
35810612SMarco.Elver@ARM.com
35910612SMarco.Elver@ARM.com    return true;
36010612SMarco.Elver@ARM.com}
36110612SMarco.Elver@ARM.com
36210612SMarco.Elver@ARM.com
36310612SMarco.Elver@ARM.combool
36410612SMarco.Elver@ARM.comIniFile::Section::printUnreferenced(const string &sectionName)
365{
366    bool unref = false;
367    bool search_unref_entries = false;
368    vector<string> unref_ok_entries;
369
370    Entry *entry = findEntry("unref_entries_ok");
371    if (entry != NULL) {
372        tokenize(unref_ok_entries, entry->getValue(), ' ');
373        if (unref_ok_entries.size()) {
374            search_unref_entries = true;
375        }
376    }
377
378    for (EntryTable::iterator ei = table.begin();
379         ei != table.end(); ++ei) {
380        const string &entryName = ei->first;
381        Entry *entry = ei->second;
382
383        if (entryName == "unref_section_ok" ||
384            entryName == "unref_entries_ok")
385        {
386            continue;
387        }
388
389        if (!entry->isReferenced()) {
390            if (search_unref_entries &&
391                (std::find(unref_ok_entries.begin(), unref_ok_entries.end(),
392                           entryName) != unref_ok_entries.end()))
393            {
394                continue;
395            }
396
397            cerr << "Parameter " << sectionName << ":" << entryName
398                 << " not referenced." << endl;
399            unref = true;
400        }
401    }
402
403    return unref;
404}
405
406
407bool
408IniFile::printUnreferenced()
409{
410    bool unref = false;
411
412    for (SectionTable::iterator i = table.begin();
413         i != table.end(); ++i) {
414        const string &sectionName = i->first;
415        Section *section = i->second;
416
417        if (!section->isReferenced()) {
418            if (section->findEntry("unref_section_ok") == NULL) {
419                cerr << "Section " << sectionName << " not referenced."
420                     << endl;
421                unref = true;
422            }
423        }
424        else {
425            if (section->printUnreferenced(sectionName)) {
426                unref = true;
427            }
428        }
429    }
430
431    return unref;
432}
433
434
435void
436IniFile::Section::dump(const string &sectionName)
437{
438    for (EntryTable::iterator ei = table.begin();
439         ei != table.end(); ++ei) {
440        cout << sectionName << ": " << (*ei).first << " => "
441             << (*ei).second->getValue() << "\n";
442    }
443}
444
445void
446IniFile::dump()
447{
448    for (SectionTable::iterator i = table.begin();
449         i != table.end(); ++i) {
450        i->second->dump(i->first);
451    }
452}
453