LORENE
read_variable.C
1 //======================================================================
2 // some general-purpose routines for config-file reading
3 //======================================================================
4 
5 /*
6  * Copyright (c) 2003 Reinhard Prix
7  *
8  * This file is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This file is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with LORENE; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23 
24 
25 #include <cstdlib>
26 #include <cstring>
27 #include <cstdio>
28 #include <cctype>
29 
30 #include "headcpp.h"
31 #include "utilitaires.h"
32 
33 namespace Lorene {
34 
35 /*----------------------------------------------------------------------
36  * load_file: does just that plus takes care of memory allocation
37  *
38  * !!!!! --> don't forget to free the data after use !!!!!
39  *
40  * returns NULL on error
41  *----------------------------------------------------------------------*/
42 char *load_file (const char *fname)
43 {
44  FILE *fp;
45  char *data;
46  size_t size, read_size;
47 
48  if( (fp = fopen (fname, "r")) == NULL)
49  {
50  cout << "ERROR: Could not open config-file: '" << fname << "'\n";
51  return (NULL);
52  }
53 
54  size = FS_filelength (fp);
55 
56  // Now read in the raw data
57  data = static_cast<char*> (MyMalloc (size+10));
58  read_size = fread ( data, 1, size, fp);
59  data [read_size] = '\0'; // properly terminate as string!
60 
61  fclose (fp);
62 
63  return (data);
64 
65 } // load_file()
66 
67 /*----------------------------------------------------------------------
68  * char *read_file_buffered (fname)
69  *
70  * just a buffer for load_file: if fname is NULL or the same as last one,
71  * then return buffered copy, otherwise free old one and get a new one
72  *
73  * ----------------------------------------------------------------------*/
74 char *
75 load_file_buffered (const char *fname)
76 {
77  static char *prev_fname = NULL;
78  static char *data = NULL;
79 
80  if (!fname) // fname=NULL: return buffered copy
81  return (data);
82 
83  if ( prev_fname && !strcmp(prev_fname, fname) ) // fname=prev_name: return buffered copy
84  return (data);
85 
86  // we're dealing with a new file here, so read it in properly
87  if (data) // free old data
88  free(data);
89 
90  data = load_file (fname);
91 
92  return (data);
93 
94 } // load_file_buffered()
95 
96 
97 #define ERR -1
98 #define OK 0
99 #define FMT_STRING "string" // reading in strings needs some special treatment
100 
101 /*----------------------------------------------------------------------
102  * parser for config-files: can read config-variables of the form
103  * VARIABLE [=: \t] VALUE
104  * everything else is ignored as comments
105  *
106  * RETURN: -1 if VARIABLE was not found or could not be read,
107  * 0 if found&read
108  * ----------------------------------------------------------------------*/
109 int
110 read_variable (const char *fname, const char *var_name, char *fmt, void *varp)
111 {
112  char *found = NULL;
113  char *seek, *pos, *bol;
114  int ret;
115  int before, after;
116  char *data;
117  int len;
118 
119  if ( (data = load_file_buffered (fname)) == NULL )
120  return ERR;
121 
122  seek = data;
123  while (!found)
124  {
125  if ( (pos = strstr(seek, var_name)) == NULL)
126  break; // we didn't find anything
127  seek = pos + strlen (var_name); // move data-pointer beyond current position in case we continue
128 
129  // make sure we didn't just find a substring:
130  if (pos > data)
131  before = *(pos-1);
132  else
133  before = 0;
134 
135  after = *(pos+strlen(var_name));
136 
137  if ( isalnum(before) || isalnum(after) || (before == '_') || (after == '_') )
138  continue;
139 
140  // find beginning of this line: bol
141  bol = (pos > data) ? pos - 1 : data;
142  while ( (bol > data) && (*bol != '\n') )
143  bol --;
144  if ( *bol == '\n' ) bol++;
145 
146  // don't allow anything but whitespace before variable-name
147  if (pos > bol)
148  if ( strspn(bol, " \t") != static_cast<size_t>(pos - bol) )
149  continue; // must have been a commentary ...
150 
151  found = pos; // ok, that's it
152  }
153 
154  if (!found)
155  {
156  cout << "ERROR: variable " << var_name << " was not found in config-file!\n";
157  return (ERR);
158  }
159 
160  found += strlen (var_name);
161 
162  // skip {space,tab,=,:}
163  found += strspn(found, " \t=:");
164 
165  // now read the value into the variable
166 
167  // reading a string needs some special treatment:
168  if ( !strcmp(fmt, FMT_STRING) )
169  {
170  if ( *found == '"') // skip quotes
171  {
172  if ( (pos = strchr(found+1, '"')) == NULL ) // find delimiting quotes
173  {
174  cout << "ERROR: no closing quotes found \n";
175  return (ERR);
176  }
177  found ++;
178  } /* if quoted string */
179  else
180  {
181  if ( (pos = strchr (found, '\n')) == NULL) // end of line?
182  pos = data + strlen(data); // end of file
183  } /* if not quoted */
184 
185  // NOTE: varp here is supposed to be a pointer to char* !!
186  char **cstr = static_cast<char**>(varp);
187  len = int(pos - found); // length of string excluding \0
188  (*cstr) = static_cast<char*>(MyMalloc(len+1));
189  strncpy ((*cstr), found, len);
190  (*cstr)[len] = '\0';
191  ret = 1;
192  } /* if fmt == string */
193  else // the default case is just sscanf...
194  ret = sscanf (found, fmt, varp);
195 
196 
197  if ( (ret == 0) || (ret == EOF) )
198  {
199  cout << "WARNING: Variable " << var_name <<" was not readable using the format '"<<fmt<<"'\n";
200  return (ERR);
201  }
202 
203  return (OK);
204 
205 } // read_variable
206 
207 /* ----------------------------------------------------------------------
208  * specialize to a few common types:
209  *----------------------------------------------------------------------*/
210 int
211 read_variable (const char *fname, const char *var_name, int &var)
212 {
213  int ret = read_variable(fname, var_name, const_cast<char*>("%d"), &var);
214 
215  cout << "DEBUG: " << var_name << " = " << var <<endl;
216 
217  return (ret);
218 }
219 
220 int
221 read_variable (const char *fname, const char *var_name, bool &var)
222 {
223  int buf;
224  int ret = read_variable(fname, var_name, const_cast<char*>("%d"), &buf);
225 
226  var = static_cast<bool>(buf);
227 
228  cout << "DEBUG: " << var_name << " = " << var <<endl;
229 
230  return (ret);
231 }
232 
233 int
234 read_variable (const char *fname, const char *var_name, double &var)
235 {
236  int ret = read_variable(fname, var_name, const_cast<char*>("%lf"), &var);
237 
238  cout << "DEBUG: " << var_name << " = " << var <<endl;
239 
240  return (ret);
241 }
242 
243 int
244 read_variable (const char *fname, const char *var_name, char **str)
245 {
246  char *cstr;
247 
248  if (*str != NULL)
249  {
250  cout << "ERROR: return-string needs to be NULL in read_variable()\n";
251  return (ERR);
252  }
253 
254  int ret = read_variable(fname, var_name, const_cast<char*>(FMT_STRING), &cstr);
255 
256  if ((ret == OK) && cstr)
257  *str = cstr;
258 
259  cout << "DEBUG: " << var_name << " = " << *str <<endl;
260 
261  return (ret);
262 
263 }
264 
265 
266 
267 /*----------------------------------------------------------------------
268  * FS_filelength().. (taken from quake2)
269  * contrary to stat() this fct is nice and portable,
270  *----------------------------------------------------------------------*/
271 int
272 FS_filelength (FILE *f)
273 {
274  int pos;
275  int end;
276 
277  pos = int(ftell (f));
278  fseek (f, 0, SEEK_END);
279  end = int(ftell (f));
280  fseek (f, pos, SEEK_SET);
281 
282  return end;
283 }
284 
285 /*@Function============================================================
286 @Desc: This function works like malloc, except that it also checks for
287  success and terminates in case of "out of memory", so we dont
288  need to do this always in the code.
289 
290 @Ret:
291 * $Function----------------------------------------------------------*/
292 void *
293 MyMalloc (long bytes)
294 {
295  void *Mptr = NULL;
296 
297  // make Gnu-compatible even if on a broken system:
298  if (bytes == 0)
299  bytes = 1;
300 
301  if ((Mptr = calloc (1, bytes)) == NULL)
302  {
303  cout << "MyMalloc("<< bytes << ") did not succeed! Terminating...\n";
304  exit (-1);
305  }
306 
307  return (Mptr);
308 
309 } // void* MyMalloc
310 
311 }
void * MyMalloc(long bytes)
&#39;Improved&#39; malloc that sets memory to 0 and also auto-terminates on error.
Lorene prototypes.
Definition: app_hor.h:67
char * load_file(char *fname)
Read file into memory and returns pointer to data.
int FS_filelength(FILE *f)
A portable routine to determine the length of a file.
char * load_file_buffered(char *fname)
Returns pointer to data from a file using a buffer.
int read_variable(const char *fname, const char *var_name, char *fmt, void *varp)
Reads a variable from file.