File: config_parser.h

package info (click to toggle)
arb 6.0.6-8
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid, trixie
  • size: 66,204 kB
  • sloc: ansic: 394,911; cpp: 250,290; makefile: 19,644; sh: 15,879; perl: 10,473; fortran: 6,019; ruby: 683; xml: 503; python: 53; awk: 32
file content (295 lines) | stat: -rw-r--r-- 10,449 bytes parent folder | download | duplicates (6)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
//  ==================================================================== //
//                                                                       //
//    File      : config_parser.h                                        //
//    Purpose   : reads config files                                     //
//                                                                       //
//                                                                       //
//  Coded by Ralf Westram (coder@reallysoft.de) in October 2003          //
//  Copyright Department of Microbiology (Technical University Munich)   //
//                                                                       //
//  Visit our web site at: http://www.arb-home.de/                       //
//                                                                       //
//                                                                       //
//  ==================================================================== //

#ifndef CONFIG_PARSER_H
#define CONFIG_PARSER_H

// format of config files:
//
// # comment
// key = value
// # comment
// key = value
//
// # comment
// key = value
//


#ifndef _GLIBCXX_MAP
#include <map>
#endif
#ifndef _GLIBCXX_CSTDIO
#include <cstdio>
#endif
#ifndef _GLIBCXX_STRING
#include <string>
#endif

#define MAXCONFIGLINESIZE 200

namespace {

    class ConfigParser {
        typedef std::map<std::string, std::string> ConfigMap;

        ConfigMap entries;
        std::string    filename;
        GB_ERROR  error;

        ConfigParser(const ConfigParser& other); // copying not allowed
        ConfigParser& operator = (const ConfigParser& other); // assignment not allowed

        static char *unwhite(char *s) {
            while (s[0] == ' ') ++s;
            char *e = strchr(s, 0)-1;

            while (e>s && isspace(e[0])) --e;
            if (e<s) e = s;

            e[isspace(e[0]) ? 0 : 1] = 0;

            return s;
        }

    public:

        ConfigParser(const std::string& filename_)
            : filename(filename_)
            , error(0)
        {
            FILE *in = fopen(filename.c_str(), "rt");
            if (!in) {
                error = GBS_global_string("Can't open config '%s'", filename.c_str());
            }
            else {
                char buffer[MAXCONFIGLINESIZE+1];
                int  lineno = 0;
                while (!error && fgets(buffer, MAXCONFIGLINESIZE, in) != 0) {
                    ++lineno;
                    char *content = unwhite(buffer);
                    if (content[0] && content[0] != '#') { // skip empty and comment lines
                        char *key = 0, *value = 0;
                        error     = splitText(content, '=', key, value);
                        if (!error && value[0] == 0) {
                            error = "content missing behind '='";
                        }

                        if (!error) {
                            ConfigMap::const_iterator found = entries.find(key);
                            if (found == entries.end()) {
                                entries[key] = value;
                            }
                            else {
                                error = GBS_global_string("entry '%s' redefined", key);
                            }
                        }

                        if (error) error = makeError(lineno, error);
                    }
                }
                fclose(in);
            }
        }

        GB_ERROR getError() { return error; }

        GB_ERROR makeError(const std::string& forEntry, const char *msg) {
            return GBS_global_string("%s (at entry '%s' in %s)", msg, forEntry.c_str(), filename.c_str());
        }
        GB_ERROR makeError(int lineno, const char *msg) {
            return GBS_global_string("%s (at line #%i in %s)", msg, lineno, filename.c_str());
        }
        GB_ERROR makeError(const char *msg) {
            return GBS_global_string("%s (in %s)", msg, filename.c_str());
        }

        static GB_ERROR splitText(char *text, char separator, char*& lhs, char*& rhs) {
            text      = unwhite(text);
            char *sep = strchr(text, separator);
            if (!sep) return GBS_global_string("'%c' expected in '%s'", separator, text);

            sep[0] = 0;
            lhs    = unwhite(text);
            rhs    = unwhite(sep+1);

            return 0;
        }

        const std::string *getValue(const std::string& key, GB_ERROR& err) {
            ConfigMap::const_iterator found = entries.find(key);
            if (found == entries.end()) {
                err = makeError(GBS_global_string("Entry '%s' expected", key.c_str()));
                return 0;
            }

            return &(found->second);
        }
    };

    // --------------------------------------------------------------------------------

    class ConfigBase {
        ConfigBase(const ConfigBase& other); // copying not allowed
        ConfigBase& operator = (const ConfigBase& other); // assignment not allowed

    protected:

        ConfigParser parser;
        GB_ERROR     error;

        GB_ERROR parse_double(const char *s, double& d) {
            if (s[0] == 0) return "floating point number expected";

            char *end = 0;
            d         = strtod(s, &end);
            if (end[0] != 0) {
                return GBS_global_string("Unexpected '%s' behind floating point number", end);
            }
            return 0;
        }

        GB_ERROR check_int_range(int value, int min_value, int max_value) {
            if (value<min_value || value>max_value) {
                return GBS_global_string("%i outside allowed range [%i .. %i]", value, min_value, max_value);
            }
            return 0;
        }
        GB_ERROR check_double_range(double value, double min_value, double max_value) {
            if (value<min_value || value>max_value) {
                return GBS_global_string("%f outside allowed range [%f .. %f]", value, min_value, max_value);
            }
            return 0;
        }
        GB_ERROR check_bool_range(int value) {
            if (value<0 || value>1) {
                return GBS_global_string("%i is not boolean (has to be 0 or 1).", value);
            }
            return 0;
        }

        void parseInt(const std::string& key, int& value) {
            const std::string *val = parser.getValue(key, error);
            if (val) value = atoi(val->c_str());
        }

        void parseInt_checked(const std::string& key, int& value, int min_value, int max_value) {
            parseInt(key, value);
            if (!error) {
                error            = check_int_range(value, min_value, max_value);
                if (error) error = parser.makeError(key, error);
            }
        }

        void parseIntRange(const std::string& key, int& low, int& high) {
            const std::string *val = parser.getValue(key, error);
            if (val) {
                char *range = strdup(val->c_str());
                char *lhs, *rhs;

                error             = ConfigParser::splitText(range, ',', lhs, rhs);
                if (!error) {
                    low  = atoi(lhs);
                    high = atoi(rhs);
                    if (low>high) {
                        error = GBS_global_string("Invalid range (%i has to be smaller than %i)", low, high);
                    }
                }

                free(range);

                if (error) error = parser.makeError(key, error);
            }
        }

        void parseIntRange_checked(const std::string& key, int& low, int& high, int min_value, int max_value) {
            parseIntRange(key, low, high);
            if (!error) {
                error             = check_int_range(low, min_value, max_value);
                if (!error) error = check_int_range(high, min_value, max_value);
                if (error) error  = parser.makeError(key, error);
            }
        }

        void parseBool(const std::string& key, bool& boolean) {
            int b = 0;
            parseInt(key, b);
            if (!error) {
                error            = check_bool_range(b);
                if (error) error = parser.makeError(key, error);
                else boolean     = static_cast<bool>(b);
            }
        }

        void parseDouble(const std::string& key, double& value) {
            const std::string *val = parser.getValue(key, error);
            if (val) {
                error = parse_double(val->c_str(), value);
            }
        }

        void parseDouble_checked(const std::string& key, double& value, double min_value, double max_value) {
            parseDouble(key, value);
            if (!error) {
                error            = check_double_range(value, min_value, max_value);
                if (error) error = parser.makeError(key, error);
            }
        }

        void parseDoubleRange(const std::string& key, double& low, double& high) {
            const std::string *val = parser.getValue(key, error);
            if (val) {
                char *range = strdup(val->c_str());
                char *lhs, *rhs;

                error             = ConfigParser::splitText(range, ',', lhs, rhs);
                if (!error) error = parse_double(lhs, low);
                if (!error) error = parse_double(rhs, high);
                if (!error && low>high) {
                    error = GBS_global_string("Invalid range (%f has to be smaller than %f)", low, high);
                }

                free(range);

                if (error) error = parser.makeError(key, error);
            }
        }

        void parseDoubleRange_checked(const std::string& key, double& low, double& high, double min_value, double max_value) {
            parseDoubleRange(key, low, high);
            if (!error) {
                error             = check_double_range(low, min_value, max_value);
                if (!error) error = check_double_range(high, min_value, max_value);
                if (error) error  = parser.makeError(key, error);
            }
        }

    public:
        ConfigBase(const std::string &filename)
            : parser(filename)
            , error(0)
        {}
        virtual ~ConfigBase() {}

        GB_ERROR getError() const { return error; }
    };
}

#undef MAXCONFIGLINESIZE


#else
#error config_parser.h included twice
#endif // CONFIG_PARSER_H