ARB
config_parser.h
Go to the documentation of this file.
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 
42 namespace {
43 
44  class ConfigParser : virtual Noncopyable {
45  typedef std::map<std::string, std::string> ConfigMap;
46 
47  ConfigMap entries;
48  std::string filename;
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 
const char * GB_ERROR
Definition: arb_core.h:25
return string(buffer, length)
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define MAXCONFIGLINESIZE
Definition: config_parser.h:40
#define NULp
Definition: cxxforward.h:97
GB_write_int const char s
Definition: AW_awar.cxx:156