summaryrefslogtreecommitdiff
path: root/ext/dsent/libutil/Config.cc
blob: f858c6926e0bf725d515ac5addd9dbc6ccabf050 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "Config.h"

#include <fstream>

#include "Assert.h"

namespace LibUtil
{
    Config::Config(const String& delimiter_, const String& comment_, const String& sentry_)
        : mDelimiter(delimiter_), mComment(comment_), mSentry(sentry_)
    {}

    Config::Config(const Config& config_)
        : StringMap(config_)
    {
        mDelimiter = config_.mDelimiter;
        mComment = config_.mComment;
        mSentry = config_.mSentry;
    }

    Config::~Config()
    {}

    Config* Config::clone() const
    {
        return new Config(*this);
    }

    void Config::readFile(const String& filename_)
    {
        std::ifstream fin(filename_.c_str());

        ASSERT(fin, "File not found: " + filename_);
        fin >> (*this);
        return;
    }

    void Config::readString(const String& str_)
    {
        String newString = str_;
        newString.substitute(";", "\n");
        std::istringstream iss(newString, std::istringstream::in);

        iss >> (*this);
    }

    std::ostream& operator<<(std::ostream& ost_, const Config& config_)
    {
        Config::ConstIterator it;
        for(it = config_.begin(); it != config_.end(); it++)
        {
            ost_ << it->first << " " << config_.mDelimiter << " ";
            ost_ << it->second << std::endl;
        }
        return ost_;
    }

    std::istream& operator>>(std::istream& ist_, Config& config_)
    {
        // Set a Config from ist_
        // Read in keys and values, keeping internal whitespace
        typedef String::size_type pos;
        const String& delim  = config_.mDelimiter;  // separator
        const String& comm   = config_.mComment;    // comment
        const String& sentry = config_.mSentry;     // end of file sentry
        const pos skip = delim.length();        // length of separator

        String nextline = "";  // might need to read ahead to see where value ends

        while(ist_ || nextline.length() > 0)
        {
            // Read an entire line at a time
            String line;
            if(nextline.length() > 0)
            {
                line = nextline;  // we read ahead; use it now
                nextline = "";
            }
            else
            {
                //std::getline(ist_, line);
                safeGetline(ist_, line);
            }

            // Ignore comments and the spaces on both ends
            line = line.substr(0, line.find(comm));
            line.trim();

            // Check for end of file sentry
            if((sentry != "") && (line.find(sentry) != String::npos)) return ist_;

            if(line.length() == 0)
                continue;

            // Parse the line if it contains a delimiter
            pos delimPos = line.find(delim);
            ASSERT((delimPos < String::npos), "Invalid config line: '" + line + "'");

            // Extract the key
            String key = line.substr(0, delimPos);
            line.replace(0, delimPos+skip, "");

            // See if value continues on the next line
            // Stop at blank line, next line with a key, end of stream,
            // or end of file sentry
            bool terminate = false;
            while(!terminate && ist_)
            {
                if(line.at(line.size() - 1) == '\\')
                    line.erase(line.size() - 1);
                else
                    break;

                //std::getline(ist_, nextline);
                safeGetline(ist_, nextline);
                terminate = true;

                String nlcopy = nextline;
                nlcopy.trim();
                if(nlcopy == "") continue;

                nextline = nextline.substr(0, nextline.find(comm));
                //if(nextline.find(delim) != String::npos)
                //    continue;
                if((sentry != "") && (nextline.find(sentry) != String::npos))
                    continue;

                //nlcopy = nextline;
                //nlcopy.trim();
                //if(nlcopy != "") line += "\n";
                line += nextline;
                nextline = "";
                terminate = false;
            }

            // Store key and value
            key.trim();
            line.trim();
            config_.set(key, line);  // overwrites if key is repeated
        }
        return ist_;
    }
}