Flow123d  release_3.0.0-1105-g32a483d
read_ini.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file read_ini.cc
15  * @ingroup io
16  * @brief OPTIONS RUTINES - get program parameters, reading from options/ini file
17  * @section DESCRIPTION
18  *
19  * Functions OptGet* are implemented through OptGetStr - only one interface routine for
20  * various implementation the parameter default is always char *, which can be NULL in the case that
21  * explicit value is necessary and program should produce an error if corresponding
22  * parameter is not given.
23  *
24  * Current implementation is based on SimpleINI C++ library.
25  *
26  */
27 
28 #include <strings.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <limits.h>
32 
33 #include "system/system.hh"
34 #include "system/xio.h"
35 #include "io/read_ini.h"
36 
37 #include <boost/tokenizer.hpp>
38 #include "boost/lexical_cast.hpp"
39 #include <boost/algorithm/string.hpp>
40 
41 static struct Read_ini *read_ini = NULL;
42 
43 #define FOR_INI_ITEMS(i) for((i)=read_ini->ini_item;(i)!=NULL;(i)=(i)->next)
44 
45 static void make_ini_item_list(const char *fname);
46 static char *section_test(char *section);
47 static char *strip_spaces(char *string);
48 static struct Ini_item *new_item(struct Ini_item *prev,char *section, char *key, char *value);
49 
50 //#define xOptGetStr(s,k) (ini.GetValue(s,k,NULL))
51 
52 
53 
54 
55 /*!
56  * @brief STRTOK WITH ERROR HANDLING and whitespace delimiters
57  * @param[in] s strtok string pointer
58  * @param[in] position requested position of the token
59  * @return strtok return
60  */
61 char *xstrtok(char *s, int position)
62 {
63  char *rc;
64  const char * const whitespace_delim=" \t\r\n";
65 
66  rc = xstrtok( s, whitespace_delim, position);
67  return(rc);
68 }
69 
70 /*!
71  * @brief STRTOK WITH ERROR HANDLING and user specified delimiters
72  * @param[in] s1 strtok string pointer
73  * @param[in] delim delimiters
74  * @param[in] position requested position of the token
75  * @return strtok return
76  *
77  * Function behaves like original strtok
78  */
79 char *xstrtok( char *s1, const char *delim, int position )
80 {
81  char *rc;
82  static char * full_string = NULL;
83  static int token_count;
84 
85  OLD_ASSERT(!( delim == NULL ),"NULL pointer as delimiter in xstrtok()\n");
86 
87  if ( s1 )
88  {
89  if ( !full_string )
90  {
91  full_string = (char *)xmalloc( LINE_SIZE );
92  full_string[0] = 0x0;
93  }
94 
95  strncpy( full_string, s1, LINE_SIZE );
96  token_count = 0;
97  }
98 
99  INPUT_CHECK( token_count == position || position < 0, "Requested position %d dosn't match token position %d", position, token_count);
100  rc = strtok( s1, delim );
101  token_count++;
102 
103  INPUT_CHECK(!( rc == NULL ),"Missing token no. %d: original string '%s' with delimiters '%s'\n", token_count, full_string, delim );
104 
105  return(rc);
106 }
107 
108 
109 
110 //=============================================================================
111 // MAKE INI KEYS LIST
112 //=============================================================================
113 void make_ini_item_list(const char *fname)
114 {
115  FILE *ini;
116 
117  char line[ LINE_SIZE ];
118  char string[ LINE_SIZE ];
119  char section[ LINE_SIZE ];//="";
120  char *section_ptr;
121  char *key;
122  char *value;
123  char *tmp;
124  struct Ini_item *prev = NULL;
125 
126  read_ini=(struct Read_ini*)xmalloc(sizeof(struct Read_ini));
127 
128  ini=xfopen(fname,"rt");
129  ASSERT(ini)(fname).error("Failed to open the ini file");
130 
131 
132  while( xfgets( line, LINE_SIZE - 2, ini ) != NULL ) {
133  sscanf( line, "%s", string ); // store first substring in the string
134 
135 
136  if (strlen(string)==0) // skips start blank lines
137  continue;
138 
139  // READ SECTION
140  section_ptr = section_test(string);
141  if ( section_ptr ) { // test of new section
142  strcpy(section,section_ptr);
143  continue; // go to next line
144  }
145 
146  if(strchr(line,'=') == NULL) // test of "=" character on the line
147  continue;
148 
149  // CLEAR COMMENTS
150  tmp = strstr(line,"#"); // find comment position
151  if(tmp != NULL){
152  sprintf(tmp,"%s",""); // force ends string on comment position
153  if(strlen(line) == 0) // continue if line contains only comment
154  continue; // go to next line
155  }
156 
157  // READ KEY
158  tmp = xstrtok(line,"="); // read characters before "="
159  sscanf(tmp,"%s",string); // strip spaces
160  if(strlen(string) == 0)
161  continue;
162  else
163  key = xstrcpy(string);
164 
165 
166  //READ VALUE
167  tmp = xstrtok(NULL,"=");
168  tmp = strip_spaces(tmp);
169  if(strlen(tmp) == 0){ //string
170  xfree(key);
171  continue;
172  }
173  else
174  value = xstrcpy(tmp);
175 
176 /*
177  printf("%s\n",section);
178  printf("%s\n",key);
179  printf("%s\n\n",value);
180 */
181 
182  prev = new_item(prev,section,key,value);
183  xfree(key);
184  xfree(value);
185  };
186 };
187 //=============================================================================
188 // STRIP START AND END BLANK CHARACTERS
189 //=============================================================================
190 char *strip_spaces(char *string)
191 {
192  int i;
193  while((string[0] ==' ') || (string[0] =='\t')){
194  string++;
195  }
196  i = strlen(string) - 1;
197  while((string[i] ==' ') || (string[i] =='\t') || (string[i] =='\n') || (string[i] =='\r')){
198  string[i--] = 0;
199  }
200  return string;
201 }
202 //=============================================================================
203 // ADD NEW KEY TO INI-LIST
204 //=============================================================================
205 struct Ini_item *new_item(struct Ini_item *prev,char *section, char *key, char *value)
206 {
207  struct Ini_item *ini_item;
208 
209  if((section != NULL) && (key != NULL) && (value != NULL)){
210  ini_item=(struct Ini_item*)xmalloc(sizeof(struct Ini_item));
211 
212  if(prev == NULL){
213  read_ini->ini_item = ini_item;
214  ini_item->prev = NULL;
215  }
216  else{
217  ini_item->prev = prev;
218  ini_item->next = NULL;
219  prev->next = ini_item;
220  }
221 
222  ini_item->section = xstrcpy(section);
223  ini_item->key = xstrcpy(key);
224  ini_item->value = xstrcpy(value);
225  return ini_item;
226  }
227  else
228  return prev;
229 
230 }
231 //=============================================================================
232 // TEST OF SECTION STRING
233 //=============================================================================
234 char *section_test(char *line)
235 {
236  if(line == NULL) return NULL;
237 
238  if( (line[0] == '[') && (line[strlen(line)-1] == ']') && (strlen(line) > 2))
239  return (xstrtok(line,"[]"));
240  else
241  return (NULL);
242 };
243 
244 /*!
245  * @brief Create new string from selected variable from ini file
246  * @param[in] section Inifile section
247  * @param[in] key Inifile key
248  * @param[in] defval Default value, if key is not found in inifile
249  * @return Ptr to new string with option value from Inifile or to default value
250  */
251 char *OptGetStr(const char *section,const char *key,const char *defval)
252 {
253  xprintf(Err, "OptGetXXX input interface is not supported anymore.\n");
254 
255 
256  const char *rc = NULL;
257  struct Ini_item *ini_item;
258 
259  FOR_INI_ITEMS(ini_item)
260  if( (!strcmp(ini_item->section,section)) && (!strcmp(ini_item->key,key)) ){
261  rc = ini_item->value;
262  break;
263  }
264 
265  if (rc == NULL) {
266  if (defval == NULL)
267  xprintf(UsrErr,"Required parameter: section '%s' key '%s' is not given.\n",section,key);
268  else
269  rc = defval;
270  }
271 
272  return xstrcpy(rc);
273 }
274 
275 //=============================================================================
276 // GET FILE NAME VARIABLE FROM INI FILE
277 //=============================================================================
278 char *OptGetFileName(const char *section,const char *key,const char *defval)
279 {
280 
281 
282  return OptGetStr(section,key,defval);
283 }
284 
285 //=============================================================================
286 // GET INT VARIABLE FROM INI FILE
287 //=============================================================================
288 long int OptGetInt( const char *section,const char *key,const char *defval )
289 {
290  char *str;
291  long int res;
292 
293  str=OptGetStr(section,key,defval);
294  if (sscanf(str,"%ld",&res) == 0) {
295  if (defval == NULL) xprintf(UsrErr,"Can not convert to integer parameter: [%s] %s.\n",section,key);
296  xprintf(PrgErr,"Default value %s of parameter: [%s] %s is not an integer.\n",defval,section,key);
297  }
298 
299  xfree( str );
300  return res;
301 }
302 
303 //=============================================================================
304 // GET DOUBLE VARIABLE FROM INI FILE
305 //=============================================================================
306 double OptGetDbl( const char *section,const char *key,const char *defval )
307 {
308  char *str;
309  double res;
310 
311  str=OptGetStr(section,key,defval);
312  if (sscanf(str,"%lg",&res) == 0) {
313  if (defval == NULL) xprintf(UsrErr,"Can not convert to double parameter: [%s] %s.\n",section,key);
314  if (sscanf(defval,"%lg",&res) == 0)
315  xprintf(PrgErr,"Default value \"%s\" of parameter: [%s] %s is not an double.\n",defval,section,key);
316  }
317 
318  xfree( str );
319  return res;
320 }
321 
322 //=============================================================================
323 // GET BOOL VARIABLE FROM INI FILE
324 //=============================================================================
325 bool OptGetBool( const char *section,const char *key,const char *defval )
326 {
327  char *str;
328  char res=false;
329  str = OptGetStr(section, key, defval);
330 
331  if ( boost::iequals(str, "yes") || boost::iequals(str, "true") || boost::iequals(str, "1") ) res=true;
332  else if ( boost::iequals(str, "no") || boost::iequals(str, "false") || boost::iequals(str, "0") ) res=false;
333  else {
334  xfree(str);
335  if (defval == NULL) xprintf(UsrErr,"Required parameter: [%s] %s is not a boolen.\n",section,key);
336  str=(char *)defval;
337  if ( boost::iequals(str, "yes") || boost::iequals(str, "true") || boost::iequals(str, "1") ) res=true;
338  else if ( boost::iequals(str, "no") || boost::iequals(str, "false") || boost::iequals(str, "0") ) res=false;
339  else xprintf(PrgErr,"Default value \"%s\" of parameter: [%s] %s is not a boolean.\n",defval,section,key);
340  }
341  return res;
342 }
343 /*!
344  * @brief Load options file
345  * @param[in] fname File name
346  */
347 void OptionsInit(const char *fname )
348 {
349  //char *path;
350  //int len;
351 
352  ASSERT(fname).error("NULL file name.\n");
353 
354  // take absolute path to the file
355  // this is completly wrong in the case the absolute path is alredy given
356  // since we should remain in the workdir when calling this it is not critical
357  // to hava correct function for path manipulation (see BOOST)
358  /*
359  path=xgetcwd();
360  len=strlen(path)+strlen(fname)+1;
361  if ( len > PATH_MAX )
362  {
363  xprintf(UsrErr, "Path too long\n");
364  }
365  strcpy( options_fname, path ); xfree(path);
366  strcat( options_fname, PATH_SEP );
367  strcat( options_fname, fname );
368 */
369 
370  // initialization of the INI reader
371  make_ini_item_list(fname);
372 
373 }
374 
375 //=============================================================================
376 // GET DOUBLE ARRAY VARIABLE FROM INI FILE
377 //=============================================================================
378 void OptGetDblArray( const char *section,const char *key,const char *defval, std::vector<double> &array)
379 // ArrSize contain number of Array members (length), *Array is the adress of array which should be filled up
380 {
381 
382  char * tmp_str = OptGetStr(section,key,defval);
383  std::string str = tmp_str;
384  free(tmp_str);
385  boost::tokenizer<boost::char_separator<char> > line_tokenizer(str, boost::char_separator<char>("\t "));
386  boost::tokenizer<boost::char_separator<char> >::iterator tok;
387 
388  double value;
389  try {
390  for( tok = line_tokenizer.begin();
391  tok != line_tokenizer.end();
392  ++tok) {
393  value = boost::lexical_cast<double> (*tok);
394  array.push_back(value);
395  }
396  } catch (boost::bad_lexical_cast &) {
397  xprintf(UsrErr, "INI file: Can not convert token `%s` of key `[%s] %s` to double.\n", (*tok).c_str(), section, key);
398  }
399 }
400 
401 
402 //=============================================================================
403 // GET Int ARRAY VARIABLE FROM INI FILE
404 //=============================================================================
405 void OptGetIntArray( const char *section,const char *key,const char *defval, int ArrSize, int *Array)// ArrSize contain number of Array members (length), *Array is the adress of array which should be filled up
406 {
407  char *str;
408  int res;
409  int i;
410 
411  str=OptGetStr(section,key,defval);
412  for(i = 1; i < ArrSize; i++){
413  if (sscanf(str,"%d",&res) == 0) {
414  if (defval == NULL) xprintf(UsrErr,"Can not convert %d. ini-file entry to integer parameter: [%s] %s.\n",i,section,key);
415  if (sscanf(defval,"%d",&res) == 0)
416  xprintf(PrgErr,"Default value \"%s\" of parameter: [%s] %s is not an integer.\n",defval,section,key);
417  }else{
418  *(Array + (i-1)*sizeof(double)) = res;
419  }
420  }
421 
422  free( str );
423  return;
424 }
425 
426 //=============================================================================
427 // GET string ARRAY VARIABLE FROM INI FILE
428 //=============================================================================
429 /*char *OptGetStrArray(const char *section,const char *key, int sb_count, struct TS_lat *dest)
430 {
431  const char **rc = NULL;
432  struct Ini_item *ini_item;
433  int i;
434 
435  FOR_INI_ITEMS(ini_item)
436  if( (!strcmp(ini_item->section,section)) && (!strcmp(ini_item->key,key)) ){
437  for(i=0; i < sb_count; i++)
438  {
439  if(sscanf(ini_item->value,"%s",dest[i].nazev) == NULL)
440  {
441  printf("\nerror during required %d-th parameter initialization occured\n",i);
442  }else{
443  printf("\nthe name of %d-th substance is %s\n",i,dest[i].nazev);
444  }
445  }
446  //
447  *rc = ini_item->value;
448  break;
449  }
450 
451  if (rc == NULL) {
452  if (defval == NULL)
453  xprintf(UsrErr,"Required parameter: [%s] %s is not given.\n",section,key);
454  else
455  *rc = defval;
456  }
457  return xstrcpy(*rc);
458 }*/
459 
struct Ini_item * ini_item
Definition: read_ini.h:32
void OptGetDblArray(const char *section, const char *key, const char *defval, std::vector< double > &array)
Definition: read_ini.cc:378
char * xfgets(char *s, int n, FILE *in)
FGETS WITH ERROR HANDLING and line count.
Definition: xio.cc:563
bool OptGetBool(const char *section, const char *key, const char *defval)
Definition: read_ini.cc:325
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
struct Ini_item * next
Definition: read_ini.h:37
char * value
Definition: read_ini.h:41
I/O functions with filename storing, able to track current line in opened file. All standard stdio fu...
char * OptGetFileName(const char *section, const char *key, const char *defval)
Definition: read_ini.cc:278
static struct Read_ini * read_ini
Definition: read_ini.cc:41
#define FOR_INI_ITEMS(i)
Definition: read_ini.cc:43
static constexpr bool value
Definition: json.hpp:87
#define OLD_ASSERT(...)
Definition: global_defs.h:131
void OptGetIntArray(const char *section, const char *key, const char *defval, int ArrSize, int *Array)
Definition: read_ini.cc:405
void OptionsInit(const char *fname)
Load options file.
Definition: read_ini.cc:347
std::string sprintf(CStringRef format, ArgList args)
Definition: printf.h:457
#define xprintf(...)
Definition: system.hh:92
#define LINE_SIZE
Definition: xio.h:37
char * section
Definition: read_ini.h:39
static char * section_test(char *section)
Definition: read_ini.cc:234
static struct Ini_item * new_item(struct Ini_item *prev, char *section, char *key, char *value)
Definition: read_ini.cc:205
long int OptGetInt(const char *section, const char *key, const char *defval)
Definition: read_ini.cc:288
char * xstrtok(char *s, int position)
STRTOK WITH ERROR HANDLING and whitespace delimiters.
Definition: read_ini.cc:61
double OptGetDbl(const char *section, const char *key, const char *defval)
Definition: read_ini.cc:306
char * key
Definition: read_ini.h:40
#define INPUT_CHECK(i,...)
Debugging macros.
Definition: global_defs.h:51
static void make_ini_item_list(const char *fname)
Definition: read_ini.cc:113
Definition: system.hh:64
Definition: system.hh:64
struct Ini_item * prev
Definition: read_ini.h:38
Definition: system.hh:64
static char * strip_spaces(char *string)
Definition: read_ini.cc:190
FILE * xfopen(const std::string &fname, const char *mode)
Definition: xio.cc:229
char * OptGetStr(const char *section, const char *key, const char *defval)
Create new string from selected variable from ini file.
Definition: read_ini.cc:251