00001 00002 /*-------------------------------------------------------------------------*/ 00003 /** 00004 @file iniparser.c 00005 @author N. Devillard 00006 @date Mar 2000 00007 @version $Revision: 2.14 $ 00008 @brief Parser for ini files. 00009 */ 00010 /*--------------------------------------------------------------------------*/ 00011 00012 /* 00013 $Id: iniparser.c,v 2.14 2002/12/12 10:49:01 ndevilla Exp $ 00014 $Author: ndevilla $ 00015 $Date: 2002/12/12 10:49:01 $ 00016 $Revision: 2.14 $ 00017 */ 00018 00019 /*--------------------------------------------------------------------------- 00020 Includes 00021 ---------------------------------------------------------------------------*/ 00022 00023 #include "iniparser.h" 00024 #include "strlib.h" 00025 00026 #define ASCIILINESZ 1024 00027 #define INI_INVALID_KEY ((char*)-1) 00028 00029 /*--------------------------------------------------------------------------- 00030 Private to this module 00031 ---------------------------------------------------------------------------*/ 00032 00033 /* Private: add an entry to the dictionary */ 00034 static void iniparser_add_entry( 00035 dictionary * d, 00036 char * sec, 00037 char * key, 00038 char * val) 00039 { 00040 char longkey[2*ASCIILINESZ+1]; 00041 00042 /* Make a key as section:keyword */ 00043 if (key!=NULL) { 00044 sprintf(longkey, "%s:%s", sec, key); 00045 } else { 00046 strcpy(longkey, sec); 00047 } 00048 00049 /* Add (key,val) to dictionary */ 00050 dictionary_set(d, longkey, val); 00051 return ; 00052 } 00053 00054 00055 /*-------------------------------------------------------------------------*/ 00056 /** 00057 @brief Get number of sections in a dictionary 00058 @param d Dictionary to examine 00059 @return int Number of sections found in dictionary 00060 00061 This function returns the number of sections found in a dictionary. 00062 The test to recognize sections is done on the string stored in the 00063 dictionary: a section name is given as "section" whereas a key is 00064 stored as "section:key", thus the test looks for entries that do not 00065 contain a colon. 00066 00067 This clearly fails in the case a section name contains a colon, but 00068 this should simply be avoided. 00069 00070 This function returns -1 in case of error. 00071 */ 00072 /*--------------------------------------------------------------------------*/ 00073 00074 int iniparser_getnsec(dictionary * d) 00075 { 00076 int i ; 00077 int nsec ; 00078 00079 if (d==NULL) return -1 ; 00080 nsec=0 ; 00081 for (i=0 ; i<d->size ; i++) { 00082 if (d->key[i]==NULL) 00083 continue ; 00084 if (strchr(d->key[i], ':')==NULL) { 00085 nsec ++ ; 00086 } 00087 } 00088 return nsec ; 00089 } 00090 00091 00092 /*-------------------------------------------------------------------------*/ 00093 /** 00094 @brief Get name for section n in a dictionary. 00095 @param d Dictionary to examine 00096 @param n Section number (from 0 to nsec-1). 00097 @return Pointer to char string 00098 00099 This function locates the n-th section in a dictionary and returns 00100 its name as a pointer to a string statically allocated inside the 00101 dictionary. Do not free or modify the returned string! 00102 00103 This function returns NULL in case of error. 00104 */ 00105 /*--------------------------------------------------------------------------*/ 00106 00107 char * iniparser_getsecname(dictionary * d, int n) 00108 { 00109 int i ; 00110 int foundsec ; 00111 00112 if (d==NULL || n<0) return NULL ; 00113 foundsec=0 ; 00114 for (i=0 ; i<d->size ; i++) { 00115 if (d->key[i]==NULL) 00116 continue ; 00117 if (strchr(d->key[i], ':')==NULL) { 00118 foundsec++ ; 00119 if (foundsec>n) 00120 break ; 00121 } 00122 } 00123 if (foundsec<=n) { 00124 return NULL ; 00125 } 00126 return d->key[i] ; 00127 } 00128 00129 00130 /*-------------------------------------------------------------------------*/ 00131 /** 00132 @brief Dump a dictionary to an opened file pointer. 00133 @param d Dictionary to dump. 00134 @param f Opened file pointer to dump to. 00135 @return void 00136 00137 This function prints out the contents of a dictionary, one element by 00138 line, onto the provided file pointer. It is OK to specify @c stderr 00139 or @c stdout as output files. This function is meant for debugging 00140 purposes mostly. 00141 */ 00142 /*--------------------------------------------------------------------------*/ 00143 void iniparser_dump(dictionary * d, FILE * f) 00144 { 00145 int i ; 00146 00147 if (d==NULL || f==NULL) return ; 00148 for (i=0 ; i<d->size ; i++) { 00149 if (d->key[i]==NULL) 00150 continue ; 00151 if (d->val[i]!=NULL) { 00152 fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); 00153 } else { 00154 fprintf(f, "[%s]=UNDEF\n", d->key[i]); 00155 } 00156 } 00157 return ; 00158 } 00159 00160 /*-------------------------------------------------------------------------*/ 00161 /** 00162 @brief Save a dictionary to a loadable ini file 00163 @param d Dictionary to dump 00164 @param f Opened file pointer to dump to 00165 @return void 00166 00167 This function dumps a given dictionary into a loadable ini file. 00168 It is Ok to specify @c stderr or @c stdout as output files. 00169 */ 00170 /*--------------------------------------------------------------------------*/ 00171 00172 void iniparser_dump_ini(dictionary * d, FILE * f) 00173 { 00174 int i, j ; 00175 char keym[ASCIILINESZ+1]; 00176 int nsec ; 00177 char * secname ; 00178 int seclen ; 00179 00180 if (d==NULL || f==NULL) return ; 00181 00182 nsec = iniparser_getnsec(d); 00183 if (nsec<1) { 00184 /* No section in file: dump all keys as they are */ 00185 for (i=0 ; i<d->size ; i++) { 00186 if (d->key[i]==NULL) 00187 continue ; 00188 fprintf(f, "%s = %s\n", d->key[i], d->val[i]); 00189 } 00190 return ; 00191 } 00192 for (i=0 ; i<nsec ; i++) { 00193 secname = iniparser_getsecname(d, i) ; 00194 seclen = (int)strlen(secname); 00195 fprintf(f, "\n[%s]\n", secname); 00196 sprintf(keym, "%s:", secname); 00197 for (j=0 ; j<d->size ; j++) { 00198 if (d->key[j]==NULL) 00199 continue ; 00200 if (!strncmp(d->key[j], keym, seclen+1)) { 00201 fprintf(f, 00202 "%-30s = %s\n", 00203 d->key[j]+seclen+1, 00204 d->val[j] ? d->val[j] : ""); 00205 } 00206 } 00207 } 00208 fprintf(f, "\n"); 00209 return ; 00210 } 00211 00212 00213 00214 00215 /*-------------------------------------------------------------------------*/ 00216 /** 00217 @brief Get the string associated to a key, return NULL if not found 00218 @param d Dictionary to search 00219 @param key Key string to look for 00220 @return pointer to statically allocated character string, or NULL. 00221 00222 This function queries a dictionary for a key. A key as read from an 00223 ini file is given as "section:key". If the key cannot be found, 00224 NULL is returned. 00225 The returned char pointer is pointing to a string allocated in 00226 the dictionary, do not free or modify it. 00227 00228 This function is only provided for backwards compatibility with 00229 previous versions of iniparser. It is recommended to use 00230 iniparser_getstring() instead. 00231 */ 00232 /*--------------------------------------------------------------------------*/ 00233 char * iniparser_getstr(dictionary * d, const char * key) 00234 { 00235 return iniparser_getstring(d, key, NULL); 00236 } 00237 00238 00239 /*-------------------------------------------------------------------------*/ 00240 /** 00241 @brief Get the string associated to a key 00242 @param d Dictionary to search 00243 @param key Key string to look for 00244 @param def Default value to return if key not found. 00245 @return pointer to statically allocated character string 00246 00247 This function queries a dictionary for a key. A key as read from an 00248 ini file is given as "section:key". If the key cannot be found, 00249 the pointer passed as 'def' is returned. 00250 The returned char pointer is pointing to a string allocated in 00251 the dictionary, do not free or modify it. 00252 */ 00253 /*--------------------------------------------------------------------------*/ 00254 char * iniparser_getstring(dictionary * d, const char * key, char * def) 00255 { 00256 char * lc_key ; 00257 char * sval ; 00258 00259 if (d==NULL || key==NULL) 00260 return def ; 00261 00262 if (!(lc_key = strdup(strlwc(key)))) { 00263 return NULL; 00264 } 00265 sval = dictionary_get(d, lc_key, def); 00266 free(lc_key); 00267 return sval ; 00268 } 00269 00270 00271 00272 /*-------------------------------------------------------------------------*/ 00273 /** 00274 @brief Get the string associated to a key, convert to an int 00275 @param d Dictionary to search 00276 @param key Key string to look for 00277 @param notfound Value to return in case of error 00278 @return integer 00279 00280 This function queries a dictionary for a key. A key as read from an 00281 ini file is given as "section:key". If the key cannot be found, 00282 the notfound value is returned. 00283 */ 00284 /*--------------------------------------------------------------------------*/ 00285 int iniparser_getint(dictionary * d, const char * key, int notfound) 00286 { 00287 char * str ; 00288 00289 str = iniparser_getstring(d, key, INI_INVALID_KEY); 00290 if (str==INI_INVALID_KEY) return notfound ; 00291 return atoi(str); 00292 } 00293 00294 00295 /*-------------------------------------------------------------------------*/ 00296 /** 00297 @brief Get the string associated to a key, convert to a double 00298 @param d Dictionary to search 00299 @param key Key string to look for 00300 @param notfound Value to return in case of error 00301 @return double 00302 00303 This function queries a dictionary for a key. A key as read from an 00304 ini file is given as "section:key". If the key cannot be found, 00305 the notfound value is returned. 00306 */ 00307 /*--------------------------------------------------------------------------*/ 00308 double iniparser_getdouble(dictionary * d, char * key, double notfound) 00309 { 00310 char * str ; 00311 00312 str = iniparser_getstring(d, key, INI_INVALID_KEY); 00313 if (str==INI_INVALID_KEY) return notfound ; 00314 return atof(str); 00315 } 00316 00317 00318 00319 /*-------------------------------------------------------------------------*/ 00320 /** 00321 @brief Get the string associated to a key, convert to a boolean 00322 @param d Dictionary to search 00323 @param key Key string to look for 00324 @param notfound Value to return in case of error 00325 @return integer 00326 00327 This function queries a dictionary for a key. A key as read from an 00328 ini file is given as "section:key". If the key cannot be found, 00329 the notfound value is returned. 00330 00331 A true boolean is found if one of the following is matched: 00332 00333 - A string starting with 'y' 00334 - A string starting with 'Y' 00335 - A string starting with 't' 00336 - A string starting with 'T' 00337 - A string starting with '1' 00338 00339 A false boolean is found if one of the following is matched: 00340 00341 - A string starting with 'n' 00342 - A string starting with 'N' 00343 - A string starting with 'f' 00344 - A string starting with 'F' 00345 - A string starting with '0' 00346 00347 The notfound value returned if no boolean is identified, does not 00348 necessarily have to be 0 or 1. 00349 */ 00350 /*--------------------------------------------------------------------------*/ 00351 int iniparser_getboolean(dictionary * d, const char * key, int notfound) 00352 { 00353 char * c ; 00354 int ret ; 00355 00356 c = iniparser_getstring(d, key, INI_INVALID_KEY); 00357 if (c==INI_INVALID_KEY) return notfound ; 00358 if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { 00359 ret = 1 ; 00360 } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { 00361 ret = 0 ; 00362 } else { 00363 ret = notfound ; 00364 } 00365 return ret; 00366 } 00367 00368 00369 /*-------------------------------------------------------------------------*/ 00370 /** 00371 @brief Finds out if a given entry exists in a dictionary 00372 @param ini Dictionary to search 00373 @param entry Name of the entry to look for 00374 @return integer 1 if entry exists, 0 otherwise 00375 00376 Finds out if a given entry exists in the dictionary. Since sections 00377 are stored as keys with NULL associated values, this is the only way 00378 of querying for the presence of sections in a dictionary. 00379 */ 00380 /*--------------------------------------------------------------------------*/ 00381 00382 int iniparser_find_entry( 00383 dictionary * ini, 00384 char * entry 00385 ) 00386 { 00387 int found=0 ; 00388 if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { 00389 found = 1 ; 00390 } 00391 return found ; 00392 } 00393 00394 00395 00396 /*-------------------------------------------------------------------------*/ 00397 /** 00398 @brief Set an entry in a dictionary. 00399 @param ini Dictionary to modify. 00400 @param entry Entry to modify (entry name) 00401 @param val New value to associate to the entry. 00402 @return int 0 if Ok, -1 otherwise. 00403 00404 If the given entry can be found in the dictionary, it is modified to 00405 contain the provided value. If it cannot be found, -1 is returned. 00406 It is Ok to set val to NULL. 00407 */ 00408 /*--------------------------------------------------------------------------*/ 00409 00410 int iniparser_setstr(dictionary * ini, char * entry, char * val) 00411 { 00412 dictionary_set(ini, strlwc(entry), val); 00413 return 0 ; 00414 } 00415 00416 /*-------------------------------------------------------------------------*/ 00417 /** 00418 @brief Delete an entry in a dictionary 00419 @param ini Dictionary to modify 00420 @param entry Entry to delete (entry name) 00421 @return void 00422 00423 If the given entry can be found, it is deleted from the dictionary. 00424 */ 00425 /*--------------------------------------------------------------------------*/ 00426 void iniparser_unset(dictionary * ini, char * entry) 00427 { 00428 dictionary_unset(ini, strlwc(entry)); 00429 } 00430 00431 00432 /*-------------------------------------------------------------------------*/ 00433 /** 00434 @brief Parse an ini file and return an allocated dictionary object 00435 @param ininame Name of the ini file to read. 00436 @return Pointer to newly allocated dictionary 00437 00438 This is the parser for ini files. This function is called, providing 00439 the name of the file to be read. It returns a dictionary object that 00440 should not be accessed directly, but through accessor functions 00441 instead. 00442 00443 The returned dictionary must be freed using iniparser_freedict(). 00444 */ 00445 /*--------------------------------------------------------------------------*/ 00446 00447 dictionary * iniparser_load(const char * ininame) 00448 { 00449 dictionary * d ; 00450 char lin[ASCIILINESZ+1]; 00451 char sec[ASCIILINESZ+1]; 00452 char key[ASCIILINESZ+1]; 00453 char val[ASCIILINESZ+1]; 00454 char * where ; 00455 FILE * ini ; 00456 int lineno ; 00457 00458 if ((ini=fopen(ininame, "r"))==NULL) { 00459 return NULL ; 00460 } 00461 00462 sec[0]=0; 00463 00464 /* 00465 * Initialize a new dictionary entry 00466 */ 00467 if (!(d = dictionary_new(0))) { 00468 fclose(ini); 00469 return NULL; 00470 } 00471 lineno = 0 ; 00472 while (fgets(lin, ASCIILINESZ, ini)!=NULL) { 00473 lineno++ ; 00474 where = strskp(lin); /* Skip leading spaces */ 00475 if (*where==';' || *where=='#' || *where==0) 00476 continue ; /* Comment lines */ 00477 else { 00478 if (sscanf(where, "[%[^]]", sec)==1) { 00479 /* Valid section name */ 00480 strcpy(sec, strlwc(sec)); 00481 iniparser_add_entry(d, sec, NULL, NULL); 00482 } else if (sscanf (where, "%[^=] = \"%[^\"]\"", key, val) == 2 00483 || sscanf (where, "%[^=] = '%[^\']'", key, val) == 2 00484 || sscanf (where, "%[^=] = %[^;#]", key, val) == 2) { 00485 strcpy(key, strlwc(strcrop(key))); 00486 /* 00487 * sscanf cannot handle "" or '' as empty value, 00488 * this is done here 00489 */ 00490 if (!strcmp(val, "\"\"") || !strcmp(val, "''")) { 00491 val[0] = (char)0; 00492 } else { 00493 strcpy(val, strcrop(val)); 00494 } 00495 iniparser_add_entry(d, sec, key, val); 00496 } 00497 } 00498 } 00499 fclose(ini); 00500 return d ; 00501 } 00502 00503 00504 00505 /*-------------------------------------------------------------------------*/ 00506 /** 00507 @brief Free all memory associated to an ini dictionary 00508 @param d Dictionary to free 00509 @return void 00510 00511 Free all memory associated to an ini dictionary. 00512 It is mandatory to call this function before the dictionary object 00513 gets out of the current context. 00514 */ 00515 /*--------------------------------------------------------------------------*/ 00516 00517 void iniparser_freedict(dictionary * d) 00518 { 00519 dictionary_del(d); 00520 } 00521 00522 /* vim: set ts=4 et sw=4 tw=75 */