CGR Localization
 All Classes Namespaces Files Functions Variables Macros Pages
configreader.cpp
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 
4 #include <math.h>
5 #include <stdio.h>
6 
7 extern "C" {
8 #include <lua.h>
9 #include <lualib.h>
10 #include <lauxlib.h>
11 };
12 
13 #include "ansicolor.h"
14 #include "util.h"
15 
16 #include "configreader.h"
17 
18 
19 static const bool Debug = false;
20 
21 /*
22  [ References ]
23 
24  Lua for configuration files:
25  Programming in Lua
26  Chapter 25. Extending your Application
27  http://www.lua.org/pil/25.html
28  Lua C API function documentation:
29  Lua 5.0 Reference Manual
30  Chapter 3 - The Application Program Interface
31  http://www.lua.org/manual/5.0/manual.html#3
32 */
33 
34 //====================================================================//
35 
36 bool FileExists(const char *filename)
37 {
38  struct stat st;
39  return(stat(filename,&st) == 0);
40 }
41 
42 //====================================================================//
43 
44 ConfigReader::SubTree::SubTree(ConfigReader &c,const char *base_exp)
45 {
46  config = &c;
47  base = base_exp;
48  errors_at_init = config->errors;
49 }
50 
51 ConfigReader::SubTree::SubTree(SubTree &s,const char *base_exp)
52 {
53  config = s.config;
54  const char *sep = (base_exp[0]=='[')? "" : ".";
55  base.printf("%s%s%s",s.base(),sep,base_exp);
56  errors_at_init = config->errors;
57 }
58 
59 const char *ConfigReader::SubTree::getFullExp(const char *exp)
60 {
61  const char *sep = (exp[0]=='[')? "" : ".";
62  full.printf("%s%s%s",base(),sep,exp);
63  return(full());
64 }
65 
66 const char *ConfigReader::SubTree::getStr(const char *exp,
67  const char *default_val)
68 {
69  return(config->getStr(getFullExp(exp),default_val));
70 }
71 
72 bool ConfigReader::SubTree::getBool(const char *exp,bool &val)
73 {
74  return(config->getBool(getFullExp(exp),val));
75 }
76 
77 bool ConfigReader::SubTree::getInt(const char *exp,int &val)
78 {
79  return(config->getInt(getFullExp(exp),val));
80 }
81 
82 bool ConfigReader::SubTree::getUInt(const char* exp, unsigned int& val)
83 {
84  return(config->getUInt(getFullExp(exp),val));
85 }
86 
87 bool ConfigReader::SubTree::getReal(const char *exp,float &val)
88 {
89  return(config->getReal(getFullExp(exp),val));
90 }
91 
92 bool ConfigReader::SubTree::getReal(const char *exp,double &val)
93 {
94  return(config->getReal(getFullExp(exp),val));
95 }
96 
97 bool ConfigReader::SubTree::getPosReal(const char *exp,float &val)
98 {
99  return(config->getPosReal(getFullExp(exp),val));
100 }
101 
102 bool ConfigReader::SubTree::getPosReal(const char *exp,double &val)
103 {
104  return(config->getPosReal(getFullExp(exp),val));
105 }
106 
107 bool ConfigReader::SubTree::getInt(const char *exp,int &val,
108  int _min,int _max)
109 {
110  return(config->getInt(getFullExp(exp),val,_min,_max));
111 }
112 
113 bool ConfigReader::SubTree::getReal(const char *exp,float &val,
114  float _min,float _max)
115 {
116  return(config->getReal(getFullExp(exp),val,_min,_max));
117 }
118 
119 bool ConfigReader::SubTree::getReal(const char *exp,double &val,
120  double _min,double _max)
121 {
122  return(config->getReal(getFullExp(exp),val,_min,_max));
123 }
124 
125 ConfigReader::FileHeader::FileHeader(const FileHeader &fh)
126 {
127  filename = fh.filename;
128  flags = fh.flags;
129  watch = fh.watch;
130 }
131 
132 //====================================================================//
133 
134 ConfigReader::ConfigReader()
135 {
136  path = NULL;
137  L = NULL;
138  errors = 0;
139  num_readfiles_calls = 0;
140  watch_files = NULL;
141  modified = false;
142 }
143 
144 ConfigReader::ConfigReader(const char* _path)
145 {
146  path = (char*) malloc(strlen(_path)+1);
147  strcpy(path,_path);
148  L = NULL;
149  errors = 0;
150  num_readfiles_calls = 0;
151  watch_files = NULL;
152  modified = false;
153 }
154 
155 bool ConfigReader::initLua()
156 {
157  if(L) closeLua();
158  L = lua_open();
159  if(!L) return(false);
160 
161  // load libraries
162  luaL_openlibs(L);
163 
164  // discard any results from initialization
165  lua_settop(L, 0);
166 
167  return(true);
168 }
169 
170 void ConfigReader::closeLua()
171 {
172  if(L) lua_close(L);
173  L = NULL;
174 }
175 
176 void ConfigReader::clearWatches()
177 {
178  for(unsigned i=0; i<files.size(); i++){
179  files[i].watch.remove();
180  }
181 }
182 
183 void ConfigReader::reset()
184 {
185  closeLua();
186  clearWatches();
187  files.clear();
188  num_readfiles_calls = 0;
189  watch_files = NULL;
190 }
191 
192 void ConfigReader::addFile(const char *filename,unsigned flags)
193 {
194  FileHeader fh;
195  if(path!=NULL){
196  fh.filename = path;
197  fh.filename.add(filename);
198  }else{
199  fh.filename = filename;
200  }
201  fh.flags = flags;
202  fh.watch.watch(watch_files,filename);
203  files.push_back(fh);
204 
205  modified = true;
206 }
207 
208 void ConfigReader::showError(int err_code,const char *filename)
209 {
210  if(err_code == 0) return;
211 
212  AnsiColor::SetFgColor(stderr,AnsiColor::Yellow);
213  AnsiColor::Bold(stderr);
214 
215  const char *err_str;
216  switch(err_code){
217  case LUA_ERRFILE: err_str="File not found"; break;
218  case LUA_ERRSYNTAX: err_str="Syntax error"; break;
219  case LUA_ERRMEM: err_str="Memory allocation error"; break;
220  case LUA_ERRRUN: err_str="Runtime error"; break;
221  case LUA_ERRERR: err_str="Error running error handler"; break;
222  default: err_str="Uknown error";
223  }
224 
225  int t = lua_gettop(L);
226  if(lua_isstring(L,t)){
227  const char *str = lua_tolstring(L,t,NULL);
228  fprintf(stderr,"ConfigReader: %s\n",str);
229  }
230 
231  fprintf(stderr,"ConfigReader: %s: %s\n",filename,err_str);
232 
233  AnsiColor::Reset(stderr);
234 }
235 
236 bool ConfigReader::readFile(const char *filename,unsigned flags)
237 {
238  if(Debug){
239  printf("ConfigReader: reading \"%s\"\n",filename);
240  }
241 
242  // it's ok if optional files don't exist
243  if((flags & Optional)!=0 && !FileExists(filename)) return(true);
244 
245  // try to load the file
246  int ret = luaL_loadfile(L, filename);
247  if(ret){
248  showError(ret,filename);
249  }else{
250  // try to execute the file
251  ret = lua_pcall(L, 0, LUA_MULTRET, 0);
252  if(ret) showError(ret,filename);
253  }
254 
255  lua_settop(L, 0); // discard any results
256 
257  return(ret == 0);
258 }
259 
260 bool ConfigReader::readFiles()
261 {
262  if(!L && !initLua()) return(false);
263  errors = 0;
264  modified = false;
265 
266  bool ok = true;
267 
268  for(unsigned i=0; i<files.size(); i++){
269  FileHeader &fh = files[i];
270  if(fh.watch.isFileModified()){
271  fh.watch.rewatch(fh.filename());
272  }
273  if(!readFile(fh.filename(),fh.flags)){
274  ok = false;
275  }
276  }
277 
278  if(ok) num_readfiles_calls++;
279 
280  return(ok);
281 }
282 
283 bool ConfigReader::isFileModified()
284 {
285  unsigned i=0;
286  while(!modified && i<files.size()){
287  modified = files[i].watch.isFileModified();
288  i++;
289  }
290 
291  return(modified);
292 }
293 
294 bool ConfigReader::needUpdate(int &client_generation) const
295 {
296  if(client_generation != getGeneration()){
297  client_generation = getGeneration();
298  return(true);
299  }else{
300  return(false);
301  }
302 }
303 
304 void ConfigReader::eval(const char *exp)
305 {
306  CharString fexp;
307  fexp.printf("_ans=(%s);",exp);
308  luaL_dostring(L,fexp());
309  lua_getglobal(L,"_ans");
310 }
311 
312 void ConfigReader::eval(const char *exp0,const char *exp1)
313 {
314  CharString fexp;
315  fexp.printf("_ans=(%s%s);",exp0,exp1);
316  luaL_dostring(L,fexp());
317  lua_getglobal(L,"_ans");
318 }
319 
320 const char *ConfigReader::getStr(const char *exp,const char *default_val)
321 {
322  eval(exp);
323 
324  const char *ret = NULL;
325  if(lua_isstring(L,-1)){
326  ret = lua_tostring(L,-1);
327  }else{
328  printf("ConfigReader: \"%s\" is not a string.\n",exp);
329  errors++;
330  }
331 
332  lua_pop(L,-1);
333  return(ret? ret : default_val);
334 }
335 
336 bool ConfigReader::getBool(const char *exp,bool &val)
337 {
338  eval(exp);
339 
340  bool ok = lua_isboolean(L,-1);
341  if(ok){
342  val = (bool)lua_toboolean(L,-1);
343  }else{
344  printf("ConfigReader: \"%s\" is not a boolean.\n",exp);
345  errors++;
346  }
347 
348  lua_pop(L,-1);
349  return(ok);
350 }
351 
352 bool ConfigReader::getInt(const char *exp,int &val)
353 {
354  eval(exp);
355 
356  bool ok = lua_isnumber(L,-1);
357  if(ok){
358  val = (int)rint(lua_tonumber(L,-1));
359  }else{
360  printf("ConfigReader: \"%s\" is not an integer.\n",exp);
361  errors++;
362  }
363 
364  lua_pop(L,-1);
365  return(ok);
366 }
367 
368 bool ConfigReader::getUInt(const char *exp,unsigned int &val)
369 {
370  eval(exp);
371 
372  bool ok = lua_isnumber(L,-1);
373  if(ok){
374  val = (int)rint(lua_tonumber(L,-1));
375  if(val<0){
376  printf("ConfigReader: \"%s\" is not an unsigned integer.\n",exp);
377  errors++;
378  ok = false;
379  }
380  }else{
381  printf("ConfigReader: \"%s\" is not an integer.\n",exp);
382  errors++;
383  }
384 
385  lua_pop(L,-1);
386  return(ok);
387 }
388 
389 bool ConfigReader::getReal(const char *exp,float &val)
390 {
391  eval(exp);
392 
393  bool ok = lua_isnumber(L,-1);
394  if(ok){
395  val = (float)lua_tonumber(L,-1);
396  }else{
397  printf("ConfigReader: \"%s\" is not a real number.\n",exp);
398  errors++;
399  }
400 
401  lua_pop(L,-1);
402  return(ok);
403 }
404 
405 bool ConfigReader::getReal(const char *exp,double &val)
406 {
407  eval(exp);
408 
409  bool ok = lua_isnumber(L,-1);
410  if(ok){
411  val = (float)lua_tonumber(L,-1);
412  }else{
413  printf("ConfigReader: \"%s\" is not a real number.\n",exp);
414  errors++;
415  }
416 
417  lua_pop(L,-1);
418  return(ok);
419 }
420 
421 bool ConfigReader::getInt(const char *exp,int &val,int _min,int _max)
422 {
423  if(!getInt(exp,val)) return(false);
424  if(val<_min || val>_max){
425  printf("ConfigReader: %s=%d is out of range [%d,%d].\n",
426  exp,val,_min,_max);
427  val = bound(val,_min,_max);
428  errors++;
429  return(false);
430  }
431  return(true);
432 }
433 
434 bool ConfigReader::getPosReal(const char *exp,float &val)
435 {
436  if(!getReal(exp,val)) return(false);
437  if(val <= 0.0){
438  printf("ConfigReader: %s=%f is non-positive\n",exp,val);
439  val = 1E-6;
440  errors++;
441  return(false);
442  }
443  return(true);
444 }
445 
446 bool ConfigReader::getPosReal(const char *exp,double &val)
447 {
448 
449  if(!getReal(exp,val)){
450  printf("failure at %s\n",exp);
451  return(false);
452  }
453  if(val <= 0.0){
454  printf("ConfigReader: %s=%f is non-positive\n",exp,val);
455  val = 1E-6;
456  errors++;
457  return(false);
458  }
459  return(true);
460 }
461 
462 bool ConfigReader::getReal(const char *exp,float &val,float _min,float _max)
463 {
464  if(!getReal(exp,val)) return(false);
465  if(val<_min || val>_max){
466  printf("ConfigReader: %s=%f is out of range [%f,%f].\n",
467  exp,val,_min,_max);
468  val = bound(val,_min,_max);
469  errors++;
470  return(false);
471  }
472  return(true);
473 }
474 
475 bool ConfigReader::getReal(const char *exp,double &val,double _min,double _max)
476 {
477  if(!getReal(exp,val)) return(false);
478  if(val<_min || val>_max){
479  printf("ConfigReader: %s=%f is out of range [%f,%f].\n",
480  exp,val,_min,_max);
481  val = bound(val,_min,_max);
482  errors++;
483  return(false);
484  }
485  return(true);
486 }
487 
488 bool ConfigReader::set(const char *name,int val)
489 {
490  CharString fexp;
491  fexp.printf("%s=%d;",name,val);
492  luaL_dostring(L,fexp());
493 
494  int v;
495  return(getInt(name,v) && v==val);
496 }
497 
498 bool ConfigReader::set(const char *name,double val)
499 {
500  CharString fexp;
501  fexp.printf("%s=%f;",name,val);
502  luaL_dostring(L,fexp());
503 
504  double v;
505  return(getReal(name,v) && fabs(val-v)<1E-9);
506 }
507 
508 void ConfigReader::addStandard()
509 {
510  // standard includes for a project go here
511  addFile("config/common.cfg");
512 }
bool needUpdate(int &client_generation) const
int getGeneration() const
get generation count in terms of # of readFiles() updates
Definition: configreader.h:110