00001
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include <stdlib.h>
00012 #include <ctype.h>
00013 #include <core/config.h>
00014 #include <misc/debug.h>
00015 #include <misc/result.h>
00016 #include <misc/generic_types.h>
00017
00018
00019 #define CONFIG_OPTION_DEFVALUE(name, \
00020 typename, \
00021 store_type, \
00022 parse_type, \
00023 defvalue, \
00024 validvalues, \
00025 num_validvalues) \
00026 defvalue,
00027
00028
00029 #define DEFVALUES \
00030 { \
00031 FOREACH_RUNTIME_CONFIG_OPTION(CONFIG_OPTION_DEFVALUE) \
00032 }
00033
00034
00035 #define CONFIG_OPTION_VALID_VALUES_ENTRY(name, \
00036 typename, \
00037 store_type, \
00038 parse_type, \
00039 defvalue, \
00040 validvalues, \
00041 num_validvalues) \
00042 parse_type name[num_validvalues];
00043
00044
00045 #define CONFIG_OPTION_VALID_VALUES(name, \
00046 typename, \
00047 store_type, \
00048 parse_type, \
00049 defvalue, \
00050 validvalues, \
00051 num_validvalues) \
00052 validvalues,
00053
00054
00055 #define VALIDVALUES \
00056 { \
00057 FOREACH_RUNTIME_CONFIG_OPTION(CONFIG_OPTION_VALID_VALUES) \
00058 }
00059
00060
00061 #define CONFIG_OPTION_KEY(name, \
00062 typename, \
00063 store_type, \
00064 parse_type, \
00065 defvalue, \
00066 validvalues, \
00067 num_validvalues) \
00068 { \
00069 #name, \
00070 txc_config_##typename##_data, \
00071 &(txc_runtime_settings.name), \
00072 &(valid_values.name), \
00073 num_validvalues \
00074 },
00075
00076
00077 txc_runtime_settings_t txc_runtime_settings = DEFVALUES;
00078 static char *txc_init_filename = "txc.ini";
00079
00080
00081 typedef enum {
00082 txc_config_integer_data,
00083 txc_config_string_data,
00084 txc_config_boolean_data
00085 } option_valuetype_t;
00086
00087 typedef enum {
00088 parse_result_pair,
00089 parse_result_EOF,
00090 parse_result_error,
00091 parse_result_comment
00092 } parse_result_t;
00093
00094
00095 typedef struct option_s option_t;
00096
00097 struct option_s {
00098 char *name;
00099 option_valuetype_t type;
00100 void *value_ptr;
00101 void *validvalues_ptr;
00102 int num_validvalues;
00103 };
00104
00105 static struct {
00106 FOREACH_RUNTIME_CONFIG_OPTION(CONFIG_OPTION_VALID_VALUES_ENTRY)
00107 } valid_values = VALIDVALUES;
00108
00109 static void
00110 strtrim_whitespace(char **str)
00111 {
00112 char *p, *end;
00113 int len;
00114
00115 p = *str;
00116
00117 len = strlen(p);
00118 while ( *p && len) {
00119 end = p + len-1;
00120 if( ' ' == *end) {
00121 *end = 0;
00122 } else if ( '\t' == *end) {
00123 *end = 0;
00124 } else {
00125 break;
00126 }
00127 len = strlen( p);
00128 }
00129
00130 while ( *p && *p != 0 && len) {
00131 if( ' ' == *p) {
00132 *p = 0;
00133 } else if ( '\t' == *p) {
00134 *p = 0;
00135 } else {
00136 break;
00137 }
00138 p++;
00139 len = strlen( p);
00140 }
00141 *str = p;
00142
00143 return;
00144 }
00145
00146 static
00147 parse_result_t
00148 parse(FILE *fin, char *option, char *value)
00149 {
00150 char buf1[1024];
00151 char buf2[1024];
00152 char *subtoken, *ret, *trimmed;
00153
00154 ret = fgets(buf1, 1024, fin);
00155 if (ret == NULL) {
00156 return parse_result_EOF;
00157 }
00158 subtoken = strtok(buf1, "=");
00159 if (subtoken == NULL) {
00160 return parse_result_error;
00161 }
00162 strcpy(buf2, subtoken);
00163 trimmed = buf2;
00164 strtrim_whitespace(&trimmed);
00165 if (trimmed[0] == '#') {
00166 return parse_result_comment;
00167 }
00168 strcpy(option, trimmed);
00169
00170 subtoken = strtok(NULL, "\n");
00171 if (subtoken == NULL) {
00172 return parse_result_error;
00173 }
00174 strcpy(trimmed, subtoken);
00175 strtrim_whitespace(&trimmed);
00176 strcpy(value, trimmed);
00177
00178 return parse_result_pair;
00179 }
00180
00181
00182 static void
00183 config_print()
00184 {
00185 int i;
00186
00187 option_t options[] = {
00188 FOREACH_RUNTIME_CONFIG_OPTION(CONFIG_OPTION_KEY)
00189 };
00190
00191 fprintf(TXC_DEBUG_OUT, "Configuration parameters\n");
00192 fprintf(TXC_DEBUG_OUT, "========================\n");
00193 for (i=0; i < sizeof (options) / sizeof(option_t); i++) {
00194 fprintf(TXC_DEBUG_OUT, "%s=", options[i].name);
00195 switch(options[i].type) {
00196 case txc_config_integer_data:
00197 fprintf(TXC_DEBUG_OUT, "%d\n", *((int *) options[i].value_ptr));
00198 break;
00199 case txc_config_string_data:
00200 fprintf(TXC_DEBUG_OUT, "%s\n", *((char **) options[i].value_ptr));
00201 break;
00202 case txc_config_boolean_data:
00203 fprintf(TXC_DEBUG_OUT, "%s\n",
00204 *((txc_bool_t *) options[i].value_ptr) == TXC_BOOL_TRUE ?
00205 "enable": "disable");
00206 break;
00207 default:
00208 TXC_INTERNALERROR("Not supported configuration parameter type");
00209 }
00210 }
00211 }
00212
00213
00214 static
00215 void
00216 option_set(option_t *option, char *value)
00217 {
00218 int j, value_is_valid;
00219 int int_value;
00220
00221 switch (option->type) {
00222 case txc_config_integer_data:
00223 if (option->num_validvalues != 2) {
00224 TXC_INTERNALERROR("config.h has wrong range definition");
00225 }
00226 int_value = atoi(value);
00227 value_is_valid = 1;
00228 if ((int_value < ((int *) option->validvalues_ptr)[0])
00229 || (int_value > ((int *) option->validvalues_ptr)[1]))
00230 {
00231 value_is_valid = 0;
00232 TXC_WARNING("Value given for parameter '%s' is out of range. Using default value.",
00233 option->name);
00234 }
00235 if (value_is_valid) {
00236 *((int *) option->value_ptr) = int_value;
00237 }
00238 break;
00239 case txc_config_string_data:
00240 if (option->num_validvalues > 0) {
00241 value_is_valid = 0;
00242 for (j=0; j < option->num_validvalues; j++) {
00243 if (strcmp(value, ((char **) option->validvalues_ptr)[j]) == 0) {
00244 value_is_valid = 1;
00245 }
00246 }
00247 } else {
00248 value_is_valid = 1;
00249 }
00250 if (value_is_valid == 0) {
00251 TXC_WARNING("Value given for parameter '%s' is not recognized. Using default value.",
00252 option->name);
00253 } else {
00254 char *bufp;
00255 bufp = (char *) malloc(strlen(value)+1);
00256 strcpy(bufp, value);
00257 *( (char **) option->value_ptr) = bufp;
00258 }
00259 break;
00260 case txc_config_boolean_data:
00261 if (option->num_validvalues > 0) {
00262 value_is_valid = 0;
00263 for (j=0; j < option->num_validvalues; j++) {
00264 if (strcmp(value, ((char **) option->validvalues_ptr)[j]) == 0) {
00265 value_is_valid = 1;
00266 }
00267 }
00268 } else {
00269 value_is_valid = 1;
00270 }
00271 if (value_is_valid == 0) {
00272 TXC_WARNING("Value given for parameter '%s' is not recognized. Using default value.",
00273 option->name);
00274 } else {
00275 if (strcmp(value, "enable") == 0) {
00276 *((txc_bool_t *) option->value_ptr) = TXC_BOOL_TRUE;
00277 } else {
00278 *((txc_bool_t *) option->value_ptr) = TXC_BOOL_FALSE;
00279 }
00280 }
00281 break;
00282 default:
00283 TXC_INTERNALERROR("Not supported configuration parameter type");
00284 }
00285 }
00286
00287
00288 static
00289 txc_result_t
00290 config_init_use_env()
00291 {
00292 int i, j;
00293 char buf_option[128];
00294 char *env_value;
00295 int len;
00296
00297 option_t options[] = {
00298 FOREACH_RUNTIME_CONFIG_OPTION(CONFIG_OPTION_KEY)
00299 };
00300
00301 strcpy(buf_option, "TXC_");
00302
00303 for (i=0; i < sizeof (options) / sizeof(option_t); i++) {
00304 len = strlen(options[i].name);
00305 for (j=0; j < len; j++) {
00306 buf_option[4+j] = (char) toupper(options[i].name[j]);
00307 }
00308 buf_option[4+len] = '\0';
00309 if ((env_value = getenv(buf_option)) != NULL) {
00310 option_set(&(options[i]), env_value);
00311 }
00312 }
00313
00314 return TXC_R_SUCCESS;
00315 }
00316
00317
00318 static
00319 txc_result_t
00320 config_init_use_file(char *filename)
00321 {
00322 int i;
00323 int known_parameter;
00324 FILE *fin;
00325 char buf_option[128];
00326 char buf_value[128];
00327 int done;
00328
00329 option_t options[] = {
00330 FOREACH_RUNTIME_CONFIG_OPTION(CONFIG_OPTION_KEY)
00331 };
00332
00333
00334 if ((fin = fopen(filename, "r")) == NULL) {
00335 return TXC_R_INVALIDFILE;
00336 }
00337 done = 0;
00338
00339
00340 while (!done) {
00341 switch(parse(fin, buf_option, buf_value)) {
00342 case parse_result_EOF:
00343 done = 1;
00344 continue;
00345 case parse_result_error:
00346 TXC_ERROR("Error while parsing file %s.", txc_init_filename);
00347 TXC_ASSERT(0);
00348 case parse_result_comment:
00349 continue;
00350 }
00351 known_parameter = 0;
00352 for (i=0; i < sizeof (options) / sizeof(option_t); i++) {
00353 if (strcmp(options[i].name, buf_option) == 0) {
00354 option_set(&options[i], buf_value);
00355 known_parameter = 1;
00356 break;
00357 }
00358 }
00359 if (known_parameter == 0) {
00360 TXC_WARNING("Ignoring unknown parameter '%s'.", buf_option);
00361 }
00362 }
00363
00364 return TXC_R_SUCCESS;
00365 }
00366
00367 txc_result_t
00368 txc_config_init ()
00369 {
00370 config_init_use_file(txc_init_filename);
00371 config_init_use_env();
00372
00373 if (txc_runtime_settings.printconf == TXC_BOOL_TRUE) {
00374 config_print();
00375 }
00376
00377 return TXC_R_SUCCESS;
00378 }
00379
00380
00381 txc_result_t
00382 txc_config_set_option(char *option, char *value)
00383 {
00384 int i;
00385 int known_parameter;
00386
00387 option_t options[] = {
00388 FOREACH_RUNTIME_CONFIG_OPTION(CONFIG_OPTION_KEY)
00389 };
00390
00391 known_parameter = 0;
00392 for (i=0; i < sizeof (options) / sizeof(option_t); i++) {
00393 if (strcmp(options[i].name, option) == 0) {
00394 option_set(&options[i], value);
00395 known_parameter = 1;
00396 break;
00397 }
00398 }
00399 if (known_parameter == 0) {
00400 TXC_WARNING("Ignoring unknown parameter '%s'.", option);
00401 }
00402
00403 return TXC_R_SUCCESS;
00404 }