MASA-Core
ConfigParser.cpp
Go to the documentation of this file.
00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2010-2015   Edans Sandes
00004  *
00005  * This file is part of MASA-Core.
00006  * 
00007  * MASA-Core is free software: you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation, either version 3 of the License, or
00010  * (at your option) any later version.
00011  * 
00012  * MASA-Core is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with MASA-Core.  If not, see <http://www.gnu.org/licenses/>.
00019  *
00020  ******************************************************************************/
00021 
00022 #include "ConfigParser.hpp"
00023 #include "../exceptions/IllegalArgumentException.hpp"
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <wordexp.h>
00029 #include <sstream>
00030 using namespace std;
00031 
00032 #define DEBUG (0)
00033 
00034 ConfigParser::ConfigParser(config_option_t* options) {
00035         config_option_t* ptr = options;
00036         while (ptr->name != NULL && ptr->section != NULL) {
00037                 this->options[ptr->section][ptr->name] = ptr;
00038                 if (DEBUG) fprintf(stderr, "v: %s:%s %p def:%s\n", ptr->section, ptr->name, this->options[ptr->section][ptr->name], ptr->default_value_str.c_str());
00039 
00040                 if (ptr->pointer == NULL) {
00041                         //throw IllegalArgumentException("ConfigParser cannot be created. Missing flag pointer.", ptr->name);
00042                         fprintf(stderr, "ConfigParser cannot be created. Missing flag pointer. %s:%s\n", ptr->section, ptr->name);
00043                         return;
00044                 }
00045                 ptr->resolved_value_str = ptr->default_value_str;
00046 
00047                 ptr++;
00048         }
00049 
00050         strcpy(section, "[global]");
00051 }
00052 
00053 ConfigParser::~ConfigParser() {
00054 
00055 }
00056 
00057 string ConfigParser::resolve_env(string in) {
00058         wordexp_t p;
00059         char **w;
00060         int i;
00061 
00062         if (in.length() == 0) {
00063                 throw IllegalArgumentException("Empty argument.");
00064         }
00065 
00066         int ret = wordexp(in.c_str(), &p, WRDE_NOCMD | WRDE_UNDEF);
00067         std::stringstream var;
00068         var << "Variable: " << in;
00069         if (ret == WRDE_BADVAL) {
00070                 throw IllegalArgumentException("An undefined environment variable was referenced.", var.str().c_str());
00071         } else if (ret != 0) {
00072                 throw IllegalArgumentException("Wrong environment variable expansion.", var.str().c_str());
00073         } else if (p.we_wordc == 0) {
00074                 throw IllegalArgumentException("No wildcard ('*') expansion.", var.str().c_str());
00075         } else if (p.we_wordc > 1) {
00076                 throw IllegalArgumentException("Ambiguous wildcard ('*') expansion.", var.str().c_str());
00077         }
00078         w = p.we_wordv;
00079         string out = w[0];
00080         wordfree(&p);
00081 
00082         return out;
00083 }
00084 
00085 void ConfigParser::printFile(FILE* file, bool resolve) {
00086         for(map<string, map<string, config_option_t*> >::iterator iter_sections = options.begin(); iter_sections != options.end(); ++iter_sections)     {
00087                 const char* section = iter_sections->first.c_str();
00088                 if (DEBUG) printf("\n%s\n", section);
00089                 for(map<string, config_option_t*>::iterator iter = iter_sections->second.begin(); iter != iter_sections->second.end(); ++iter)  {
00090                         const char* k = iter->first.c_str();
00091                         const config_option_t* option = iter->second;
00092                         fprintf(file, "%s\t%s\n", k, resolve ? option->resolved_value_str.c_str() : option->original_value_str.c_str());
00093                 }
00094         }
00095 }
00096 
00097 void ConfigParser::tokenize(const char* _line, char* _param, char* _value) {
00098         char line[512];
00099         char* param;
00100         char* value;
00101         strcpy(line, _line);
00102         while (line[strlen(line) - 1] == '\n' || line[strlen(line) - 1] == '\r') {
00103                 line[strlen(line) - 1] = '\0';
00104         }
00105         char* sharp = strchr(line, '#');
00106         if (sharp != NULL) {
00107                 *sharp = '\0';
00108         }
00109         param = line;
00110         while (*param == '\t' || *param == ' ') {
00111                 param++;
00112         }
00113         if (*param == '\0') {
00114                 _param[0] = '\0';
00115                 return;
00116         }
00117         value = param;
00118         while (*value != '\t' && *value != ' ' && *value != '\0') {
00119                 value++;
00120         }
00121         if (*value != '\0') {
00122                 *value = '\0'; // terminating the parameter name token.
00123                 value++;
00124                 while (*value == '\t' || *value == ' ') {
00125                         value++;
00126                 }
00127         }
00128 
00129         strcpy(_param, param);
00130         strcpy(_value, value);
00131         if (DEBUG) fprintf(stderr, "%s -> %s\n", param, value);
00132 }
00133 
00134 void ConfigParser::parseValue(const char* section, const char* param, const char* value) {
00135         if (options[section][param] == NULL) {
00136                 char msg[128];
00137                 sprintf(msg, "Unknown parameter `%s'.", param);
00138                 throw IllegalArgumentException(msg);
00139         }
00140         config_option_t* option = options[section][param];
00141         if (*value == '\0') {
00142                 char msg[128];
00143                 sprintf(msg, "An argument must be supplied to the parameter: %s.\n",
00144                                 param);
00145                 throw IllegalArgumentException(msg);
00146         } else {
00147                 char *cpy_value = new char[strlen(value)+1];
00148                 strcpy(cpy_value, value);
00149                 option->original_value_str = cpy_value;
00150                 option->resolved_value_str = cpy_value;
00151 
00152                 option->parser(value, option);
00153         }
00154 }
00155 
00156 void ConfigParser::parseLine(const char* line) {
00157         char param[128];
00158         char value[128];
00159 
00160         tokenize(line, param, value);
00161         if (*param == '\0') {
00162                 return;
00163         }
00164         if (*param == '[') {
00165                 strcpy(section, param);
00166                 if (options[section].size() == 0) {
00167                         char msg[128];
00168                         sprintf(msg, "Unknown section `%s'.", param);
00169                         throw IllegalArgumentException(msg);
00170                 }
00171                 return;
00172         }
00173         parseValue(section, param, value);
00174 }
00175 
00176 void ConfigParser::parse_int (const char* value, config_option_t* option) {
00177         int* i = (int*)option->pointer;
00178         if ( sscanf ( value, "%d", i ) != 1 ) {
00179                 char msg[128];
00180                 sprintf(msg, "Value must be an integer");
00181                 throw IllegalArgumentException(msg);
00182         }
00183 }
00184 
00185 
00186 void ConfigParser::parse_int_range (const char* value, config_option_t* option) {
00187         int* i = (int*)option->pointer;
00188         sscanf ( value, "%d", i );
00189         int min;
00190         int max;
00191         sscanf (option->option, "%d %d", &min, &max);
00192         if ( *i < min || *i > max ) {
00193                 char msg[128];
00194                 sprintf(msg, "Value must be in range %d..%d", min, max);
00195                 throw IllegalArgumentException(msg);
00196         }
00197 }
00198 
00199 void ConfigParser::parse_int_min (const char* value, config_option_t* option) {
00200         int* i = (int*)option->pointer;
00201         sscanf ( value, "%d", i );
00202         int min;
00203         sscanf (option->option, "%d", &min);
00204         if ( *i < min ) {
00205                 char msg[128];
00206                 sprintf(msg, "Value must be greater or equal to %d", min);
00207                 throw IllegalArgumentException(msg);
00208         }
00209 }
00210 
00211 void ConfigParser::parse_int_max (const char* value, config_option_t* option) {
00212         int* i = (int*)option->pointer;
00213         sscanf ( value, "%d", i );
00214         int max;
00215         sscanf (option->option, "%d", &max);
00216         if ( *i > max ) {
00217                 char msg[128];
00218                 sprintf(msg, "Value must be less or equal to %d", max);
00219                 throw IllegalArgumentException(msg);
00220         }
00221 }
00222 
00223 void ConfigParser::parse_longlong_size (const char* value, config_option_t* option) {
00224         long long* ll = (long long*)option->pointer;
00225         if (strcmp(value, "none") == 0) {
00226                 *ll = 0;
00227                 return;
00228         }
00229 
00230         string str = value;
00231         char suffix = str[str.length()-1];
00232         str[str.length()-1] = 0;
00233         switch ( suffix ) {
00234         case 'K':
00235                 *ll = ( long long ) ( atof ( str.c_str() ) *1024LL );
00236                 break;
00237         case 'M':
00238                 *ll = ( long long ) ( atof ( str.c_str() ) *1024*1024LL );
00239                 break;
00240         case 'G':
00241                 *ll = ( long long ) ( atof ( str.c_str() ) *1024*1024*1024LL );
00242                 break;
00243         default:
00244                 throw IllegalArgumentException("Wrong size suffix (use 'K', 'M' or 'G').");
00245         }
00246         if ( *ll == 0 ) {
00247                 throw IllegalArgumentException("Wrong disk size limit.");
00248         }
00249         char tmp[256];
00250         sprintf(tmp, "%lld", *ll);
00251         option->resolved_value_str = tmp;
00252 }
00253 
00254 void ConfigParser::parse_int_enum(const char* value, config_option_t* option) {
00255         int* i = (int*)option->pointer;
00256 
00257         char option_cpy[256];
00258         strncpy(option_cpy, option->option, sizeof(option_cpy));
00259         option_cpy[sizeof(option_cpy)-1] = '\0';
00260 
00261         char* tok = strtok(option_cpy, ";");
00262         int id = 0;
00263         while (tok != NULL) {
00264                 if (strcmp(tok, value) == 0) {
00265                         *i = id;
00266                         return;
00267                 }
00268                 id++;
00269                 tok = strtok(NULL, ";");
00270         }
00271 
00272         char msg[128];
00273         sprintf(msg, "Option `%s' not recognized. Possible values are: %s", value, option->option);
00274         throw IllegalArgumentException(msg);
00275 }
00276 
00277 void ConfigParser::parse_bool (const char* value, config_option_t* option) {
00278         int* b = (int*)option->pointer;
00279         if (strcmp(value, "enabled") == 0 || strcmp(value, "true") == 0) {
00280                 *b = 1;
00281                 return;
00282         } else if (strcmp(value, "disabled") == 0 || strcmp(value, "false") == 0) {
00283                 *b = 0;
00284                 return;
00285         } else {
00286                 char msg[128];
00287                 sprintf(msg, "Value must be enabled/disable or true/false");
00288                 throw IllegalArgumentException(msg);
00289         }
00290 }
00291 
00292 void ConfigParser::parse_path (const char* value, config_option_t* option) {
00293         string* path = (string*)option->pointer;
00294         *path = resolve_env(string(value));
00295         option->resolved_value_str = *path;
00296 }