read_variable.C

00001 //======================================================================
00002 // some general-purpose routines for config-file reading
00003 //======================================================================
00004 
00005 /*
00006  *   Copyright (c) 2003 Reinhard Prix
00007  *
00008  *   This file is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  *   This file is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  *   You should have received a copy of the GNU General Public License
00019  *   along with LORENE; if not, write to the Free Software
00020  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 char read_variable_C[] = "$Header: /cvsroot/Lorene/C++/Source/Non_class_members/Utilities/read_variable.C,v 1.8 2009/01/19 15:23:17 j_novak Exp $";
00024 
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <stdio.h>
00028 #include <ctype.h>
00029 
00030 #include "headcpp.h"
00031 #include "utilitaires.h"
00032 
00033 
00034 /*----------------------------------------------------------------------
00035  * load_file: does just that plus takes care of memory allocation
00036  *
00037  *    !!!!! --> don't forget to free the data after use !!!!!
00038  *
00039  * returns NULL on error
00040  *----------------------------------------------------------------------*/
00041 char *
00042 load_file (char *fname)
00043 {
00044   FILE *fp;
00045   char *data;
00046   size_t size, read_size;
00047   
00048   if( (fp = fopen (fname, "r")) == NULL)
00049     {
00050       cout << "ERROR: Could not open config-file: '" << fname << "'\n";
00051       return (NULL);
00052     }
00053   
00054   size = FS_filelength (fp);
00055   
00056   // Now read in the raw data
00057   data = static_cast<char*> (MyMalloc (size+10));
00058   read_size = fread ( data, 1, size, fp);
00059   data [read_size] = '\0';  // properly terminate as string!
00060   
00061   fclose (fp);
00062   
00063   return (data);
00064 
00065 } // load_file()
00066 
00067 /*----------------------------------------------------------------------
00068  *  char *read_file_buffered (fname)
00069  *  
00070  *  just a buffer for load_file: if fname is NULL or the same as last one, 
00071  *  then return buffered copy, otherwise free old one and get a new one
00072  *  
00073  * ----------------------------------------------------------------------*/
00074 char *
00075 load_file_buffered (char *fname)
00076 {
00077   static char *prev_fname = NULL;
00078   static char *data = NULL;
00079 
00080   if (!fname)   // fname=NULL: return buffered copy
00081     return (data);
00082 
00083   if ( prev_fname && !strcmp(prev_fname, fname) )   // fname=prev_name: return buffered copy
00084     return (data);
00085 
00086   // we're dealing with a new file here, so read it in properly
00087   if (data)   // free old data
00088     free(data);
00089   
00090   data = load_file (fname);
00091 
00092   return (data);
00093 
00094 } // load_file_buffered()
00095 
00096 
00097 #define ERR -1
00098 #define OK  0
00099 #define FMT_STRING "string"    // reading in strings needs some special treatment
00100 
00101 /*----------------------------------------------------------------------
00102  *  parser for config-files: can read config-variables of the form
00103  *  VARIABLE [=: \t] VALUE
00104  *  everything else is ignored as comments
00105  *
00106  * RETURN:  -1 if VARIABLE was not found or could not be read, 
00107  *      0 if found&read
00108  * ----------------------------------------------------------------------*/
00109 int
00110 read_variable (char *fname, char *var_name, char *fmt, void *varp)
00111 {
00112   char *found = NULL;
00113   char *seek, *pos, *bol;
00114   int ret;
00115   int before, after;
00116   char *data;
00117   int len;
00118 
00119   if ( (data = load_file_buffered (fname)) == NULL )
00120     return ERR;
00121 
00122   seek = data;
00123   while (!found)
00124     {
00125       if ( (pos = strstr(seek, var_name)) == NULL)
00126     break;  // we didn't find anything
00127       seek = pos + strlen (var_name);       // move data-pointer beyond current position in case we continue
00128 
00129       // make sure we didn't just find a substring:
00130       if (pos > data)
00131     before = *(pos-1);
00132       else
00133     before = 0;
00134 
00135       after = *(pos+strlen(var_name));
00136 
00137       if ( isalnum(before) || isalnum(after) || (before == '_') || (after == '_') )
00138     continue;
00139 
00140       // find beginning of this line: bol
00141       bol = (pos > data) ? pos - 1 : data;
00142       while ( (bol > data) && (*bol != '\n') ) 
00143     bol --;
00144       if ( *bol == '\n' ) bol++;
00145 
00146       // don't allow anything but whitespace before variable-name
00147       if (pos > bol)
00148     if ( strspn(bol, " \t") != static_cast<size_t>(pos - bol) )
00149       continue;  // must have been a commentary ...
00150 
00151       found = pos;  // ok, that's it
00152     }
00153 
00154   if (!found)
00155     {
00156       cout << "ERROR: variable " << var_name << " was not found in config-file!\n";
00157       return (ERR);
00158     }
00159 
00160   found += strlen (var_name);
00161   
00162   // skip {space,tab,=,:}
00163   found += strspn(found, " \t=:");
00164 
00165   // now read the value into the variable
00166   
00167   // reading a string needs some special treatment:
00168   if ( !strcmp(fmt, FMT_STRING) )
00169     {
00170       if ( *found == '"')  // skip quotes
00171     {
00172       if ( (pos = strchr(found+1, '"')) == NULL )  // find delimiting quotes
00173         {
00174           cout << "ERROR: no closing quotes found \n";
00175           return (ERR);
00176         }
00177       found ++;
00178     } /* if quoted string */
00179       else
00180     {
00181       if ( (pos = strchr (found, '\n')) == NULL)  // end of line? 
00182         pos = data + strlen(data);      // end of file
00183     } /* if not quoted */
00184 
00185       // NOTE: varp here is supposed to be a pointer to char* !!
00186       char **cstr = static_cast<char**>(varp);
00187       len = int(pos - found);  // length of string excluding \0
00188       (*cstr) = static_cast<char*>(MyMalloc(len+1)); 
00189       strncpy ((*cstr), found, len);
00190       (*cstr)[len] = '\0'; 
00191       ret = 1;  
00192     } /* if fmt == string */
00193   else  // the default case is just sscanf...
00194     ret = sscanf (found, fmt, varp);
00195 
00196 
00197   if ( (ret == 0) || (ret == EOF) )
00198     {
00199       cout << "WARNING: Variable " << var_name <<" was not readable using the format '"<<fmt<<"'\n";
00200       return (ERR);
00201     }
00202 
00203   return (OK);
00204 
00205 } // read_variable
00206 
00207 /* ----------------------------------------------------------------------
00208  * specialize to a few common types:
00209  *----------------------------------------------------------------------*/
00210 int 
00211 read_variable (char *fname, char *var_name, int &var)
00212 {
00213     int ret = read_variable(fname, var_name, const_cast<char*>("%d"), &var);
00214 
00215   cout << "DEBUG: " << var_name << " = " << var <<endl;
00216 
00217   return (ret);
00218 }
00219 
00220 int 
00221 read_variable (char *fname, char *var_name, bool &var)
00222 {
00223   int buf;
00224   int ret = read_variable(fname, var_name, const_cast<char*>("%d"), &buf);
00225 
00226   var = static_cast<bool>(buf);
00227 
00228   cout << "DEBUG: " << var_name << " = " << var <<endl;
00229 
00230   return (ret);
00231 }
00232 
00233 int 
00234 read_variable (char *fname, char *var_name, double &var)
00235 {
00236     int ret = read_variable(fname, var_name, const_cast<char*>("%lf"), &var);
00237 
00238   cout << "DEBUG: " << var_name << " = " << var <<endl;
00239 
00240   return (ret);
00241 }
00242 
00243 int
00244 read_variable (char *fname, char *var_name, char **str)
00245 {
00246   char *cstr;
00247 
00248   if (*str != NULL)
00249     {
00250       cout << "ERROR: return-string needs to be NULL in read_variable()\n";
00251       return (ERR);
00252     }
00253 
00254   int ret = read_variable(fname, var_name, const_cast<char*>(FMT_STRING), &cstr);
00255 
00256   if ((ret == OK) && cstr)
00257     *str = cstr;
00258 
00259   cout << "DEBUG: " << var_name << " = " << *str <<endl;
00260 
00261   return (ret);
00262 
00263 }
00264 
00265 
00266 
00267 /*----------------------------------------------------------------------
00268  * FS_filelength().. (taken from quake2)
00269  *      contrary to stat() this fct is nice and portable, 
00270  *----------------------------------------------------------------------*/
00271 int
00272 FS_filelength (FILE *f)
00273 {
00274   int       pos;
00275   int       end;
00276 
00277   pos = int(ftell (f));
00278   fseek (f, 0, SEEK_END);
00279   end = int(ftell (f));
00280   fseek (f, pos, SEEK_SET);
00281   
00282   return end;
00283 }
00284 
00285 /*@Function============================================================
00286 @Desc: This function works like malloc, except that it also checks for
00287        success and terminates in case of "out of memory", so we dont
00288        need to do this always in the code.
00289 
00290 @Ret: 
00291 * $Function----------------------------------------------------------*/
00292 void *
00293 MyMalloc (long bytes)
00294 {
00295   void *Mptr = NULL;
00296 
00297   // make Gnu-compatible even if on a broken system:
00298   if (bytes == 0)
00299     bytes = 1;
00300 
00301   if ((Mptr = calloc (1, bytes)) == NULL)
00302     {
00303       cout << "MyMalloc("<< bytes << ") did not succeed! Terminating...\n";
00304       exit (-1);
00305     }
00306 
00307   return (Mptr);
00308 
00309 } // void* MyMalloc
00310 

Generated on Tue Feb 7 01:35:19 2012 for LORENE by  doxygen 1.4.6