source: tags/arb-6.0/TEMPLATES/config_parser.h

Last change on this file was 7044, checked in by westram, 14 years ago
  • fixed include wrappers (merges [7006] [7007])
    • use gcc-style include-wrappers
    • use same convention for local wrappers in TREEGEN as rest of ARB
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1//  ==================================================================== //
2//                                                                       //
3//    File      : config_parser.h                                        //
4//    Purpose   : reads config files                                     //
5//                                                                       //
6//                                                                       //
7//  Coded by Ralf Westram (coder@reallysoft.de) in October 2003          //
8//  Copyright Department of Microbiology (Technical University Munich)   //
9//                                                                       //
10//  Visit our web site at: http://www.arb-home.de/                       //
11//                                                                       //
12//                                                                       //
13//  ==================================================================== //
14
15#ifndef CONFIG_PARSER_H
16#define CONFIG_PARSER_H
17
18// format of config files:
19//
20// # comment
21// key = value
22// # comment
23// key = value
24//
25// # comment
26// key = value
27//
28
29
30#ifndef _GLIBCXX_MAP
31#include <map>
32#endif
33#ifndef _GLIBCXX_CSTDIO
34#include <cstdio>
35#endif
36#ifndef _GLIBCXX_STRING
37#include <string>
38#endif
39
40#define MAXCONFIGLINESIZE 200
41
42namespace {
43
44    class ConfigParser {
45        typedef std::map<std::string, std::string> ConfigMap;
46
47        ConfigMap entries;
48        std::string    filename;
49        GB_ERROR  error;
50
51        ConfigParser(const ConfigParser& other); // copying not allowed
52        ConfigParser& operator = (const ConfigParser& other); // assignment not allowed
53
54        static char *unwhite(char *s) {
55            while (s[0] == ' ') ++s;
56            char *e = strchr(s, 0)-1;
57
58            while (e>s && isspace(e[0])) --e;
59            if (e<s) e = s;
60
61            e[isspace(e[0]) ? 0 : 1] = 0;
62
63            return s;
64        }
65
66    public:
67
68        ConfigParser(const std::string& filename_)
69            : filename(filename_)
70            , error(0)
71        {
72            FILE *in = fopen(filename.c_str(), "rt");
73            if (!in) {
74                error = GBS_global_string("Can't open config '%s'", filename.c_str());
75            }
76            else {
77                char buffer[MAXCONFIGLINESIZE+1];
78                int  lineno = 0;
79                while (!error && fgets(buffer, MAXCONFIGLINESIZE, in) != 0) {
80                    ++lineno;
81                    char *content = unwhite(buffer);
82                    if (content[0] && content[0] != '#') { // skip empty and comment lines
83                        char *key = 0, *value = 0;
84                        error     = splitText(content, '=', key, value);
85                        if (!error && value[0] == 0) {
86                            error = "content missing behind '='";
87                        }
88
89                        if (!error) {
90                            ConfigMap::const_iterator found = entries.find(key);
91                            if (found == entries.end()) {
92                                entries[key] = value;
93                            }
94                            else {
95                                error = GBS_global_string("entry '%s' redefined", key);
96                            }
97                        }
98
99                        if (error) error = makeError(lineno, error);
100                    }
101                }
102                fclose(in);
103            }
104        }
105
106        GB_ERROR getError() { return error; }
107
108        GB_ERROR makeError(const std::string& forEntry, const char *msg) {
109            return GBS_global_string("%s (at entry '%s' in %s)", msg, forEntry.c_str(), filename.c_str());
110        }
111        GB_ERROR makeError(int lineno, const char *msg) {
112            return GBS_global_string("%s (at line #%i in %s)", msg, lineno, filename.c_str());
113        }
114        GB_ERROR makeError(const char *msg) {
115            return GBS_global_string("%s (in %s)", msg, filename.c_str());
116        }
117
118        static GB_ERROR splitText(char *text, char separator, char*& lhs, char*& rhs) {
119            text      = unwhite(text);
120            char *sep = strchr(text, separator);
121            if (!sep) return GBS_global_string("'%c' expected in '%s'", separator, text);
122
123            sep[0] = 0;
124            lhs    = unwhite(text);
125            rhs    = unwhite(sep+1);
126
127            return 0;
128        }
129
130        const std::string *getValue(const std::string& key, GB_ERROR& err) {
131            ConfigMap::const_iterator found = entries.find(key);
132            if (found == entries.end()) {
133                err = makeError(GBS_global_string("Entry '%s' expected", key.c_str()));
134                return 0;
135            }
136
137            return &(found->second);
138        }
139    };
140
141    // --------------------------------------------------------------------------------
142
143    class ConfigBase {
144        ConfigBase(const ConfigBase& other); // copying not allowed
145        ConfigBase& operator = (const ConfigBase& other); // assignment not allowed
146
147    protected:
148
149        ConfigParser parser;
150        GB_ERROR     error;
151
152        GB_ERROR parse_double(const char *s, double& d) {
153            if (s[0] == 0) return "floating point number expected";
154
155            char *end = 0;
156            d         = strtod(s, &end);
157            if (end[0] != 0) {
158                return GBS_global_string("Unexpected '%s' behind floating point number", end);
159            }
160            return 0;
161        }
162
163        GB_ERROR check_int_range(int value, int min_value, int max_value) {
164            if (value<min_value || value>max_value) {
165                return GBS_global_string("%i outside allowed range [%i .. %i]", value, min_value, max_value);
166            }
167            return 0;
168        }
169        GB_ERROR check_double_range(double value, double min_value, double max_value) {
170            if (value<min_value || value>max_value) {
171                return GBS_global_string("%f outside allowed range [%f .. %f]", value, min_value, max_value);
172            }
173            return 0;
174        }
175        GB_ERROR check_bool_range(int value) {
176            if (value<0 || value>1) {
177                return GBS_global_string("%i is not boolean (has to be 0 or 1).", value);
178            }
179            return 0;
180        }
181
182        void parseInt(const std::string& key, int& value) {
183            const std::string *val = parser.getValue(key, error);
184            if (val) value = atoi(val->c_str());
185        }
186
187        void parseInt_checked(const std::string& key, int& value, int min_value, int max_value) {
188            parseInt(key, value);
189            if (!error) {
190                error            = check_int_range(value, min_value, max_value);
191                if (error) error = parser.makeError(key, error);
192            }
193        }
194
195        void parseIntRange(const std::string& key, int& low, int& high) {
196            const std::string *val = parser.getValue(key, error);
197            if (val) {
198                char *range = strdup(val->c_str());
199                char *lhs, *rhs;
200
201                error             = ConfigParser::splitText(range, ',', lhs, rhs);
202                if (!error) {
203                    low  = atoi(lhs);
204                    high = atoi(rhs);
205                    if (low>high) {
206                        error = GBS_global_string("Invalid range (%i has to be smaller than %i)", low, high);
207                    }
208                }
209
210                free(range);
211
212                if (error) error = parser.makeError(key, error);
213            }
214        }
215
216        void parseIntRange_checked(const std::string& key, int& low, int& high, int min_value, int max_value) {
217            parseIntRange(key, low, high);
218            if (!error) {
219                error             = check_int_range(low, min_value, max_value);
220                if (!error) error = check_int_range(high, min_value, max_value);
221                if (error) error  = parser.makeError(key, error);
222            }
223        }
224
225        void parseBool(const std::string& key, bool& boolean) {
226            int b = 0;
227            parseInt(key, b);
228            if (!error) {
229                error            = check_bool_range(b);
230                if (error) error = parser.makeError(key, error);
231                else boolean     = static_cast<bool>(b);
232            }
233        }
234
235        void parseDouble(const std::string& key, double& value) {
236            const std::string *val = parser.getValue(key, error);
237            if (val) {
238                error = parse_double(val->c_str(), value);
239            }
240        }
241
242        void parseDouble_checked(const std::string& key, double& value, double min_value, double max_value) {
243            parseDouble(key, value);
244            if (!error) {
245                error            = check_double_range(value, min_value, max_value);
246                if (error) error = parser.makeError(key, error);
247            }
248        }
249
250        void parseDoubleRange(const std::string& key, double& low, double& high) {
251            const std::string *val = parser.getValue(key, error);
252            if (val) {
253                char *range = strdup(val->c_str());
254                char *lhs, *rhs;
255
256                error             = ConfigParser::splitText(range, ',', lhs, rhs);
257                if (!error) error = parse_double(lhs, low);
258                if (!error) error = parse_double(rhs, high);
259                if (!error && low>high) {
260                    error = GBS_global_string("Invalid range (%f has to be smaller than %f)", low, high);
261                }
262
263                free(range);
264
265                if (error) error = parser.makeError(key, error);
266            }
267        }
268
269        void parseDoubleRange_checked(const std::string& key, double& low, double& high, double min_value, double max_value) {
270            parseDoubleRange(key, low, high);
271            if (!error) {
272                error             = check_double_range(low, min_value, max_value);
273                if (!error) error = check_double_range(high, min_value, max_value);
274                if (error) error  = parser.makeError(key, error);
275            }
276        }
277
278    public:
279        ConfigBase(const std::string &filename)
280            : parser(filename)
281            , error(0)
282        {}
283        virtual ~ConfigBase() {}
284
285        GB_ERROR getError() const { return error; }
286    };
287}
288
289#undef MAXCONFIGLINESIZE
290
291
292#else
293#error config_parser.h included twice
294#endif // CONFIG_PARSER_H
295
Note: See TracBrowser for help on using the repository browser.