Main Page | Data Structures | File List | Data Fields | Globals

confloader.c

Go to the documentation of this file.
00001 /* This file is part of confloader
00002  *
00003  * Copyright (c) 2004 Nicolas Bernard <n.bernard@lafraze.net>
00004  *
00005  * Permission to use, copy, modify, and distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00010  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00011  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00012  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00013  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00014  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00015  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* 
00019    This is the confloader configuration file loader.
00020    See confparser.h or the doxygen generated documentation
00021    for instructions.
00022 */
00023 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <ctype.h>
00037 #include <errno.h>
00038 #include <limits.h>
00039 #include <math.h>
00040 #include <string.h>
00041 #include <strings.h>
00042 
00043 #include "confloader.h"
00044 
00045 static unsigned int linenum = 0;
00046 
00047 static int
00048 withret(/*@null@*/ char* str)
00049 {
00050         unsigned int i = 0;
00051         if (str == NULL)
00052                 return 0;
00053         while(str[i] != '\0') {
00054                 if (str[i++] == '\n')
00055                         return 1;
00056         }
00057         return 0;
00058 }
00059 
00060 static int
00061 onlyblank(char* str)
00062 {
00063         unsigned int i = 0;
00064         while(str[i] != '\0')
00065                 if (!isspace(str[i++]))
00066                         return 0;
00067         return 1;
00068 }
00069 
00070 static /*@null@*/ char*
00071 getline(FILE* file)
00072 {
00073         unsigned int size = 0;
00074         char* buf = NULL;
00075         while(!withret(buf)) {
00076                 unsigned int osize = size;
00077                 size *= 2;
00078                 size += 256;
00079                 buf = realloc(buf, size * sizeof(char));
00080                 if (buf == NULL)
00081                         return NULL;
00082                 memset(buf + osize, 0, size - osize);
00083                 if (osize) osize--;
00084                 if (fgets(buf + osize, size, file) == NULL) {
00085                         if (feof(file) && (withret(buf) || onlyblank(buf))) {
00086                                 linenum++;
00087                                 return buf;
00088                         }
00089                         free(buf);
00090                         return NULL;
00091                 }
00092         }
00093         linenum++;
00094         return buf;
00095 }
00096 
00097 static int
00098 readyesno(char* line)
00099 {
00100         int ret = -1;
00101         unsigned int i = 0;
00102         unsigned int j = 0;
00103         while(line[i] != '=' && line[i] != '\0') {i++;}
00104         if (line[i++] == '\0') return -1;
00105         while(isspace(line[i])) {i++;}
00106         if (line[i] == '\0') return -1;
00107         j = i;
00108         while (line[j] != '\0' && !isspace(line[j])) {j++;}
00109         switch (j - i) {
00110         case 5:
00111                 if (!strncasecmp(line + i, "false", 5)) ret = 0;
00112                 else return -1;
00113                 break;
00114         case 4:
00115                 if (!strncasecmp(line + i, "true", 4)) ret = 1;
00116                 else return -1;
00117                 break;
00118         case 3:
00119                 if (!strncasecmp(line + i, "yes", 3)) ret = 1;
00120                 else return -1;
00121                 break;
00122         case 2:
00123                 if (!strncasecmp(line + i, "no", 2)) ret = 0;
00124                 else return -1;
00125                 break;
00126         case 1:
00127                 if (line[i] == 'Y' || line[i] == 'y' || line[i] == '1') ret = 1;
00128                 else if (line[i] == 'N' || line[i] == 'n' || line[i] == '0') ret = 0;
00129                 else return -1;
00130                 break;
00131         default:
00132                 return -1;
00133         }
00134         while (line[j] != '\0' && line[j] != '#') {
00135                 if (!isspace(line[j])) return -1;
00136                 j++;
00137         }
00138         return ret;
00139 }
00140 
00141 static int
00142 readint(char* line, long int* value, FILE* fderr)
00143 {
00144         long int tmp = 0;
00145         unsigned int i = 0;
00146         char* end = NULL;
00147         while(line[i] != '=' && line[i] != '\0') {i++;}
00148         if (line[i++] == '\0') return -1;
00149         while(line[i] != '\0' && isspace(line[i])) {i++;}
00150         if (line[i] == '\0') return -1;
00151         
00152         tmp = strtol(line + i, &end, 0);
00153         if ((tmp == LONG_MIN || tmp == LONG_MAX) && errno == ERANGE) {
00154                 if (fderr != NULL) {
00155                         fprintf(fderr, "line %d: value out of range\n", linenum);
00156                 }
00157                 return -1;
00158         }
00159         while (*end != '\0' && *end != '#') {
00160                 if (!isspace(*end))
00161                         return -1;
00162                 end++;
00163         }
00164         *value = tmp;
00165         return 1;
00166 }
00167 
00168 static int
00169 readfloat(char* line, double* value, FILE* fderr)
00170 {
00171         double tmp = 0;
00172         unsigned int i = 0;
00173         char* end = NULL;
00174         while(line[i] != '=' && line[i] != '\0') {i++;}
00175         if (line[i++] == '\0') return -1;
00176         while(line[i] != '\0' && isspace(line[i])) {i++;}
00177         if (line[i] == '\0') return -1;
00178         tmp = strtod(line + i, &end);
00179         if ((tmp == -HUGE_VAL || tmp == HUGE_VAL || value == 0)
00180             && errno == ERANGE) {
00181                 if (fderr != NULL) {
00182                         fprintf(fderr, "line %d: value out of range\n", linenum);
00183                 }
00184                 return -1;
00185         }
00186         while (*end != '\0' && *end != '#') {
00187                 if (!isspace(*end)) return -1;
00188                 end++;
00189         }
00190         *value = tmp;
00191         return 1;
00192 }
00193 
00194 /*
00195    returns -1 in case of error, or the size of the 
00196    string, excluding the \0 of the end
00197 */
00198 static int
00199 readstring(char* line, char** value, char caselogfile)
00200 {
00201         char* tmp = NULL;
00202         unsigned int i = 0;
00203         unsigned int j = 0;
00204         unsigned int bscount = 0;
00205         char* end = NULL;
00206         if (!caselogfile) {
00207                 while(line[i] != '=' && line[i] != '\0') {i++;}
00208                 if (line[i++] == '\0') return -1;
00209         }
00210         while(line[i] != '\0' && isspace(line[i])) {i++;}
00211         if (line[i] != '"' && line[i] != '\'') 
00212                 return -1;
00213 
00214         i++;
00215         j = i;
00216 LOOP:
00217         bscount = 0;
00218         while(line[i] != '"' && line[i] != '\'' && line[i] != '\0') { 
00219                 if (line[i] == '\\')
00220                         bscount++;
00221                 else
00222                         bscount = 0;
00223                 i++;
00224         }
00225         if ((line[i] == '"' || line[i] == '\'') && bscount % 2 == 1)
00226                 goto LOOP;
00227 
00228         end = line + i + 1;
00229         while (*end != '\0' && *end != '#') {
00230                 if (!isspace(*end)) return -1;
00231                 end++;
00232         }
00233 
00234         tmp = (char*) malloc(sizeof(char) * (i - j + 1));
00235         memcpy(tmp, line + j, i - j);
00236         tmp[i - j] = '\0';
00237 
00238         *value = tmp;
00239         return i - j;
00240 }
00241 
00242 /* 
00243    returns 10 in case of error.
00244    0 --> logtype = none
00245    1 --> syslog
00246    2 --> file, with filename in value
00247 */
00248 static log_t
00249 readlogtype(char* line, char** value, FILE* fderr)
00250 {
00251         log_t tmp = LOG__NOTDEF;
00252         char* filename = NULL;
00253         unsigned int i = 0;
00254         char* end = NULL;
00255         int len = 0;
00256         while(line[i] != '=' && line[i] != '\0') {i++;}
00257         if (line[i++] == '\0') return ELOG;
00258         while(line[i] != '\0' && isspace(line[i])) {i++;}
00259         if (line[i] == '\0') return ELOG;
00260         len = strlen(line+i);
00261         if (len >= 4) {
00262                 if (strncasecmp(line+i, "none", 4) == 0) {
00263                         tmp = LOG__NONE;
00264                         end = line + i + 4;
00265                         goto LENOK;
00266                 }
00267         } 
00268         if (len >= 6) {
00269                 if (strncasecmp(line+i, "syslog", 6) == 0) {
00270                         tmp = LOG__SYSLOG;
00271                         end = line + i + 6;
00272                 }
00273                 if (strncasecmp(line+i, "stderr", 6) == 0) {
00274                         tmp = LOG__STDERR;
00275                         end = line + i + 6;
00276                 }
00277                 if (strncasecmp(line+i, "stdout", 6) == 0) {
00278                         tmp = LOG__STDOUT;
00279                         end = line + i + 6;
00280                 }
00281                 if (strncasecmp(line+i, "file ", 5) == 0)
00282                         tmp = LOG__FILE;
00283                 goto LENOK;
00284         }
00285         return ELOG;
00286 LENOK:
00287         if (tmp == LOG__FILE) {
00288                 int filenamelen = -1;
00289                 int spc = 0;
00290                 while(line[5 + i + spc] != '\0' && isspace(line[5 + i + spc])) {spc++;}
00291                 filenamelen = readstring(line + i + 5, &filename, 1);
00292                 if (filenamelen == -1)
00293                         return ELOG;
00294                 end = line + 7 + i + filenamelen + spc;
00295         }
00296         while (*end != '\0' && *end != '#') {
00297                 if (!isspace(*end)) return ELOG;
00298                 end++;
00299         }
00300         *value = filename;
00301         return tmp;
00302 }
00303 
00304 static int
00305 lineparse(FILE* file, FILE* fderr)
00306 {
00307         char* line = getline(file);
00308         unsigned int i = 0;
00309         unsigned int j = i;
00310         int size = 0;
00311         int n = 0;
00312         if (line == NULL)
00313                 return -1;
00314         while(isspace(line[i])) {i++;}
00315         if (line[i] == '\0' || line[i] == '#') {
00316                 free(line);
00317                 return 0;
00318         }
00319         while(line[j] != '\0' && !isspace(line[j])
00320               && line[j] != '=') {j++;}
00321         if (line[j] == '\0') {
00322                 free(line);
00323                 return -1;
00324         }
00325         size = j - i;
00326         while (conf[n].name != NULL) {
00327                 if (strlen(conf[n].name) < size) {
00328                         n++;
00329                         continue;
00330                 }
00331                 if (!strncmp(conf[n].name, line + i, size)) {
00332                         switch (conf[n].type) {
00333                         case YESNO:
00334 #ifdef _DEBUGCONFLOADER_
00335                                 fprintf(stderr, "case yesno");
00336 #endif
00337                                 conf[n].value.yn = readyesno(line + i);
00338                                 free(line);
00339                                 if (conf[n].value.yn == -1) return -1;
00340                                 if (conf[n].mandatory) conf[n].mandatory++;
00341 #ifdef _DEBUGCONFLOADER_
00342                                 fprintf(stderr, " (%d)\n", conf[n].value.yn);
00343 #endif
00344                                 return 1;
00345                         case INTOPT:
00346                         {
00347                                 long int val = 0;
00348 #ifdef _DEBUGCONFLOADER_
00349                                 fprintf(stderr, "case intopt");
00350 #endif
00351                                 if (readint(line, &val, fderr) != -1) {
00352                                         free(line);
00353                                         conf[n].value.i = val;
00354                                         if (conf[n].mandatory) conf[n].mandatory++;
00355 #ifdef _DEBUGCONFLOADER_
00356                                         fprintf(stderr, " (%ld)\n", val);
00357 #endif
00358                                         return 1;
00359                                 }
00360                                 free(line);
00361                                 return -1;
00362                         }
00363                         case FLOATOPT:
00364                         {
00365                                 double val = 0;
00366 #ifdef _DEBUGCONFLOADER_
00367                                 fprintf(stderr, "case floatopt");
00368 #endif
00369                                 if (readfloat(line, &val, fderr) != -1) {
00370                                         free(line);
00371                                         conf[n].value.f = val;
00372                                         if (conf[n].mandatory) conf[n].mandatory++;
00373 #ifdef _DEBUGCONFLOADER_
00374                                         fprintf(stderr, " (%f)\n", val);
00375 #endif
00376                                         return 1;
00377                                 }
00378                                 free(line);
00379                                 return -1;
00380                         }
00381                         case STRINGOPT:
00382                         {
00383                                 char* val = NULL;
00384 #ifdef _DEBUGCONFLOADER_
00385                                 fprintf(stderr, "case stringopt");
00386 #endif
00387                                 if (readstring(line, &val, 0) != -1) {
00388                                         free(line);
00389                                         conf[n].value.str = val;
00390                                         if (conf[n].mandatory) conf[n].mandatory++;
00391 #ifdef _DEBUGCONFLOADER_
00392                                         fprintf(stderr, " (%s)\n", val);
00393 #endif
00394                                         return 1;
00395                                 }
00396                                 free(line);
00397                                 return -1;
00398                         }
00399                         case FILEOPT:
00400                         {
00401                                 char* val = NULL;
00402 #ifdef _DEBUGCONFLOADER_
00403                                 fprintf(stderr, "case fileopt (not fully implemented)");
00404 #endif
00405                                 if (readstring(line, &val, 0) != -1) {
00406                                         free(line);
00407                                         conf[n].value.str = val;
00408                                         if (conf[n].mandatory) conf[n].mandatory++;
00409 #ifdef _DEBUGCONFLOADER_
00410                                         fprintf(stderr, " (%s)\n", val);
00411 #endif
00412 
00413                                         return 1;
00414                                 }
00415                                 free(line);
00416                                 return -1;
00417                         }
00418                         case LOGOPT:
00419                         {
00420                                 char* val = NULL;
00421                                 unsigned int logtype = 0;
00422 #ifdef _DEBUGCONFLOADER_
00423                                 fprintf(stderr, "case logopt");
00424 #endif
00425                                 logtype = readlogtype(line, &val, fderr);
00426                                 free(line);
00427                                 if (logtype != ELOG) {
00428                                         conf[n].value.log.logtype = logtype;
00429                                         conf[n].value.log.filename = val;
00430                                         if (conf[n].mandatory) conf[n].mandatory++;
00431 #ifdef _DEBUGCONFLOADER_
00432                                         if (conf[n].value.log.logtype == LOG__FILE)
00433                                                 fprintf(stderr, " (file: %s)\n", conf[n].value.log.filename);
00434                                         if (conf[n].value.log.logtype == LOG__SYSLOG)
00435                                                 fprintf(stderr, " (syslog)\n");
00436                                         if (conf[n].value.log.logtype == LOG__STDERR)
00437                                                 fprintf(stderr, " (stderr)\n");
00438                                         if (conf[n].value.log.logtype == LOG__STDOUT)
00439                                                 fprintf(stderr, " (stdout)\n");
00440                                         if (conf[n].value.log.logtype == LOG__NONE)
00441                                                 fprintf(stderr, " (none)\n");
00442 #endif /* _DEBUGCONFLOADER_ */
00443                                         return 1;
00444                                 }
00445                                 return -1;
00446                         }
00447                         default:
00448 #ifdef _DEBUGCONFLOADER_
00449                                 fprintf(stderr, "unknown case\n");
00450 #endif
00451                                 if (fderr != NULL) {
00452                                         line[j] = '\0';
00453                                         fprintf(fderr, "%s: bad type in confoptions\n", line + i);
00454                                 }
00455                                 free(line);
00456                                 return -1;
00457                         }
00458                 }
00459                 n++;
00460         }
00461         if (fderr != NULL) {
00462                 line[j] = '\0';
00463                 fprintf(fderr, "%s: unknown option\n", line + i);
00464         }
00465         free(line);
00466         return -1;
00467 }
00468 
00469 int 
00470 confparse(char* conffile, FILE* fderr)
00471 {
00472         FILE* file = fopen(conffile, "r");
00473         int nboptset = 0;
00474         int i = 0;
00475         if (file == NULL) {
00476                 fprintf(fderr, "confparser: unable to open configuration file. ");
00477                 perror("fopen: ");
00478                 return -1;
00479         }
00480 
00481         while(!feof(file)) {
00482                 int ret = lineparse(file, fderr);
00483                 if (ret == -1) {
00484                         if (fderr != NULL)
00485                                 fprintf(fderr, "Parse error line %d\n", linenum);
00486                         (void) fclose(file);
00487                         return -1;
00488                 }
00489                 if (ret == 1) 
00490                         nboptset++;
00491                     
00492         }
00493         (void) fclose(file);
00494         while (conf[i].name != NULL) {
00495                 if (conf[i].mandatory == 1) {
00496                         fprintf(fderr, "Mandatory option '%s' missing in the specified configuration file...\n", conf[i].name);
00497                         return -1;
00498                 }
00499                 i++;
00500         }
00501         return nboptset;
00502 }
00503 
00504 option
00505 getconf(const char* name)
00506 {
00507         unsigned int namelen = strlen(name);
00508         unsigned int n = 0;
00509         while(conf[n].name != NULL) {
00510                 if (strlen(conf[n].name) == namelen) {
00511                         if (strncmp(conf[n].name, name, namelen) == 0) {
00512                                 return conf[n];
00513                         }
00514                 }
00515                 n++;
00516         }
00517         return conf[n];
00518 }

Generated on Wed Jan 5 12:01:39 2005 for Confloader by doxygen 1.3.6