source: branches/stable/TEMPLATES/config_parser.h

Last change on this file was 16763, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.0 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 : virtual Noncopyable {
45        typedef std::map<std::string, std::string> ConfigMap;
46
47        ConfigMap   entries;
48        std::string filename;
49        GB_ERROR    error;
50
51        static char *unwhite(char *s) {
52            while (s[0] == ' ') ++s;
53            char *e = strchr(s, 0)-1;
54
55            while (e>s && isspace(e[0])) --e;
56            if (e<s) e = s;
57
58            e[isspace(e[0]) ? 0 : 1] = 0;
59
60            return s;
61        }
62
63    public:
64
65        ConfigParser(const std::string& filename_) :
66            filename(filename_),
67            error(NULp)
68        {
69            FILE *in = fopen(filename.c_str(), "rt");
70            if (!in) {
71                error = GBS_global_string("Can't open config '%s'", filename.c_str());
72            }
73            else {
74                char buffer[MAXCONFIGLINESIZE+1];
75                int  lineno = 0;
76                while (!error && fgets(buffer, MAXCONFIGLINESIZE, in) != 0) {
77                    ++lineno;
78                    char *content = unwhite(buffer);
79                    if (content[0] && content[0] != '#') { // skip empty and comment lines
80                        char *key = 0, *value = 0;
81                        error     = splitText(content, '=', key, value);
82                        if (!error && value[0] == 0) {
83                            error = "content missing behind '='";
84                        }
85
86                        if (!error) {
87                            ConfigMap::const_iterator found = entries.find(key);
88                            if (found == entries.end()) {
89                                entries[key] = value;
90                            }
91                            else {
92                                error = GBS_global_string("entry '%s' redefined", key);
93                            }
94                        }
95
96                        if (error) error = makeError(lineno, error);
97                    }
98                }
99                fclose(in);
100            }
101        }
102
103        GB_ERROR getError() { return error; }
104
105        GB_ERROR makeError(const std::string& forEntry, const char *msg) {
106            return GBS_global_string("%s (at entry '%s' in %s)", msg, forEntry.c_str(), filename.c_str());
107        }
108        GB_ERROR makeError(int lineno, const char *msg) {
109            return GBS_global_string("%s (at line #%i in %s)", msg, lineno, filename.c_str());
110        }
111        GB_ERROR makeError(const char *msg) {
112            return GBS_global_string("%s (in %s)", msg, filename.c_str());
113        }
114
115        static GB_ERROR splitText(char *text, char separator, char*& lhs, char*& rhs) {
116            text      = unwhite(text);
117            char *sep = strchr(text, separator);
118            if (!sep) return GBS_global_string("'%c' expected in '%s'", separator, text);
119
120            sep[0] = 0;
121            lhs    = unwhite(text);
122            rhs    = unwhite(sep+1);
123
124            return 0;
125        }
126
127        const std::string *getValue(const std::string& key, GB_ERROR& err) {
128            ConfigMap::const_iterator found = entries.find(key);
129            if (found == entries.end()) {
130                err = makeError(GBS_global_string("Entry '%s' expected", key.c_str()));
131                return 0;
132            }
133
134            return &(found->second);
135        }
136    };
137
138    // --------------------------------------------------------------------------------
139
140    class ConfigBase : virtual Noncopyable {
141    protected:
142
143        ConfigParser parser;
144        GB_ERROR     error;
145
146        GB_ERROR parse_double(const char *s, double& d) {
147            if (s[0] == 0) return "floating point number expected";
148
149            char *end = 0;
150            d         = strtod(s, &end);
151            if (end[0] != 0) {
152                return GBS_global_string("Unexpected '%s' behind floating point number", end);
153            }
154            return 0;
155        }
156
157        GB_ERROR check_int_range(int value, int min_value, int max_value) {
158            if (value<min_value || value>max_value) {
159                return GBS_global_string("%i outside allowed range [%i .. %i]", value, min_value, max_value);
160            }
161            return 0;
162        }
163        GB_ERROR check_double_range(double value, double min_value, double max_value) {
164            if (value<min_value || value>max_value) {
165                return GBS_global_string("%f outside allowed range [%f .. %f]", value, min_value, max_value);
166            }
167            return 0;
168        }
169        GB_ERROR check_bool_range(int value) {
170            if (value<0 || value>1) {
171                return GBS_global_string("%i is not boolean (has to be 0 or 1).", value);
172            }
173            return 0;
174        }
175
176        void parseInt(const std::string& key, int& value) {
177            const std::string *val = parser.getValue(key, error);
178            if (val) value = atoi(val->c_str());
179        }
180
181        void parseInt_checked(const std::string& key, int& value, int min_value, int max_value) {
182            parseInt(key, value);
183            if (!error) {
184                error            = check_int_range(value, min_value, max_value);
185                if (error) error = parser.makeError(key, error);
186            }
187        }
188
189        void parseIntRange(const std::string& key, int& low, int& high) {
190            const std::string *val = parser.getValue(key, error);
191            if (val) {
192                char *range = ARB_strdup(val->c_str());
193                char *lhs, *rhs;
194
195                error             = ConfigParser::splitText(range, ',', lhs, rhs);
196                if (!error) {
197                    low  = atoi(lhs);
198                    high = atoi(rhs);
199                    if (low>high) {
200                        error = GBS_global_string("Invalid range (%i has to be smaller than %i)", low, high);
201                    }
202                }
203
204                free(range);
205
206                if (error) error = parser.makeError(key, error);
207            }
208        }
209
210        void parseIntRange_checked(const std::string& key, int& low, int& high, int min_value, int max_value) {
211            parseIntRange(key, low, high);
212            if (!error) {
213                error             = check_int_range(low, min_value, max_value);
214                if (!error) error = check_int_range(high, min_value, max_value);
215                if (error) error  = parser.makeError(key, error);
216            }
217        }
218
219        void parseBool(const std::string& key, bool& boolean) {
220            int b = 0;
221            parseInt(key, b);
222            if (!error) {
223                error            = check_bool_range(b);
224                if (error) error = parser.makeError(key, error);
225                else boolean     = static_cast<bool>(b);
226            }
227        }
228
229        void parseDouble(const std::string& key, double& value) {
230            const std::string *val = parser.getValue(key, error);
231            if (val) {
232                error = parse_double(val->c_str(), value);
233            }
234        }
235
236        void parseDouble_checked(const std::string& key, double& value, double min_value, double max_value) {
237            parseDouble(key, value);
238            if (!error) {
239                error            = check_double_range(value, min_value, max_value);
240                if (error) error = parser.makeError(key, error);
241            }
242        }
243
244        void parseDoubleRange(const std::string& key, double& low, double& high) {
245            const std::string *val = parser.getValue(key, error);
246            if (val) {
247                char *range = ARB_strdup(val->c_str());
248                char *lhs, *rhs;
249
250                error             = ConfigParser::splitText(range, ',', lhs, rhs);
251                if (!error) error = parse_double(lhs, low);
252                if (!error) error = parse_double(rhs, high);
253                if (!error && low>high) {
254                    error = GBS_global_string("Invalid range (%f has to be smaller than %f)", low, high);
255                }
256
257                free(range);
258
259                if (error) error = parser.makeError(key, error);
260            }
261        }
262
263        void parseDoubleRange_checked(const std::string& key, double& low, double& high, double min_value, double max_value) {
264            parseDoubleRange(key, low, high);
265            if (!error) {
266                error             = check_double_range(low, min_value, max_value);
267                if (!error) error = check_double_range(high, min_value, max_value);
268                if (error) error  = parser.makeError(key, error);
269            }
270        }
271
272    public:
273        ConfigBase(const std::string &filename) :
274            parser(filename),
275            error(NULp)
276        {}
277        virtual ~ConfigBase() {}
278
279        GB_ERROR getError() const { return error; }
280    };
281}
282
283#undef MAXCONFIGLINESIZE
284
285
286#else
287#error config_parser.h included twice
288#endif // CONFIG_PARSER_H
289
Note: See TracBrowser for help on using the repository browser.