| version 1.14, 2001/12/09 15:07:37 |
version 1.15, 2001/12/16 20:44:37 |
|
|
| #include <math.h> |
#include <string.h> |
| #include <limits.h> |
#include <stdlib.h> |
| #include <float.h> |
|
| #include <ctype.h> |
|
| #include <errno.h> |
|
| |
|
| #include "str/strplus.h" |
#include "str/strplus.h" |
| #include "str/strdyn.h" |
#include "str/strdyn.h" |
| |
|
| |
#include "cfg.h" |
| |
#include "shared.h" |
| |
|
| static int cfg_cmdline_get_next_opt(const CFG_CONTEXT con); |
int cfg_cmdline_get_next_opt(const CFG_CONTEXT con) |
| static int process_currents(const CFG_CONTEXT con, int *ret_val, int *arg_used); |
|
| static void free_currents(const CFG_CONTEXT con); |
|
| static int cmdline_set_currents(const CFG_CONTEXT con); |
|
| static int search_cur_opt_idx(const CFG_CONTEXT con); |
|
| static int add_to_used_opt_idx(const CFG_CONTEXT con, int opt_idx); |
|
| static int store_multi_arg(const int type, const char **multi_arg, void ***ar); |
|
| static int store_single_arg(const int type, const char *arg, const void *where); |
|
| |
|
| |
|
| static int cfg_cmdline_get_next_opt(const CFG_CONTEXT con) |
|
| { |
{ |
| /* register int opt_idx; */ |
/* register int opt_idx; */ |
| register int ret; |
register int ret; |
| Line 66 static int cfg_cmdline_get_next_opt(cons |
|
| Line 55 static int cfg_cmdline_get_next_opt(cons |
|
| && ! strcmp(con->cur_arg, con->argv[con->cur_idx - 1])) |
&& ! strcmp(con->cur_arg, con->argv[con->cur_idx - 1])) |
| leftover_init = 1; |
leftover_init = 1; |
| |
|
| free_currents(con); |
__cfg_free_currents(con); |
| |
|
| if (! strdyn_compare(con->line_stop_str, con->argv[con->cur_idx])) |
if (! strdyn_compare(con->line_stop_str, con->argv[con->cur_idx])) |
| return CFG_ERROR_STOP_STR_FOUND; |
return CFG_ERROR_STOP_STR_FOUND; |
| Line 80 static int cfg_cmdline_get_next_opt(cons |
|
| Line 69 static int cfg_cmdline_get_next_opt(cons |
|
| return CFG_ERROR_NOMEM; |
return CFG_ERROR_NOMEM; |
| } |
} |
| else { |
else { |
| if (cmdline_set_currents(con) == 0) |
if (__cfg_cmdline_set_currents(con) == 0) |
| return CFG_ERROR_NOMEM; |
return CFG_ERROR_NOMEM; |
| } |
} |
| } |
} |
| |
|
| ret = process_currents(con, &ret_val, &arg_used); |
ret = __cfg_process_currents(con, &ret_val, &arg_used); |
| |
|
| if (ret != CFG_OK) |
if (ret != CFG_OK) |
| return ret; |
return ret; |
| Line 94 static int cfg_cmdline_get_next_opt(cons |
|
| Line 83 static int cfg_cmdline_get_next_opt(cons |
|
| if (! (con->cur_opt_type & CFG_LONG_SEPINIT) |
if (! (con->cur_opt_type & CFG_LONG_SEPINIT) |
| && !(con->cur_opt_type & CFG_SHORT_OPTIONS) |
&& !(con->cur_opt_type & CFG_SHORT_OPTIONS) |
| && !(con->cur_opt_type == CFG_NONE_OPTION)) |
&& !(con->cur_opt_type == CFG_NONE_OPTION)) |
| { |
|
| /* puts("[1] argument used, moving cur_idx"); */ |
|
| con->cur_idx_tmp++; |
con->cur_idx_tmp++; |
| } |
|
| |
|
| if (con->cur_opt_type & CFG_SHORT_OPTIONS) |
if (con->cur_opt_type & CFG_SHORT_OPTIONS) |
| con->cur_opt_type -= CFG_SHORT_OPTIONS; |
con->cur_opt_type -= CFG_SHORT_OPTIONS; |
| } |
} |
| |
|
| if (! (con->cur_opt_type & CFG_SHORT_OPTIONS)) { |
if (! (con->cur_opt_type & CFG_SHORT_OPTIONS)) |
| /* puts("[2] moving cur_idx"); */ |
|
| con->cur_idx_tmp++; |
con->cur_idx_tmp++; |
| } |
|
| |
|
| if (ret_val > 0) |
if (ret_val > 0) |
| return ret_val; |
return ret_val; |
| Line 114 static int cfg_cmdline_get_next_opt(cons |
|
| Line 98 static int cfg_cmdline_get_next_opt(cons |
|
| } |
} |
| |
|
| return CFG_OK; |
return CFG_OK; |
| } |
|
| |
|
| static int process_currents(const CFG_CONTEXT con, int *ret_val, int *arg_used) |
|
| { |
|
| register int opt_idx; |
|
| register int opt_data_type, opt_f_multi, opt_f_multi_sep; |
|
| |
|
| *ret_val = 0; |
|
| if (arg_used != NULL) |
|
| *arg_used = 0; |
|
| |
|
| opt_idx = search_cur_opt_idx(con); |
|
| |
|
| #if defined(DEBUG) && DEBUG |
|
| fprintf(stderr, "%s|%d|%s|%s|%s|%d|flags=%x[", |
|
| con->type == CFG_LINE ? "cmdline" : "cfgfile", |
|
| con->type == CFG_LINE ? con->cur_idx : 0, |
|
| con->type == CFG_LINE ? con->argv[con->cur_idx] : "N/A", |
|
| con->cur_opt == NULL ? "[NULL]" : con->cur_opt, |
|
| con->cur_arg == NULL ? "[NULL]" : con->cur_arg, |
|
| opt_idx, con->cur_opt_type); |
|
| |
|
| if (con->cur_opt_type & CFG_LONG_OPTION) |
|
| fputs("-LONG-", stderr); |
|
| if (con->cur_opt_type & CFG_SHORT_OPTION) |
|
| fputs("-SHORT-", stderr); |
|
| if (con->cur_opt_type & CFG_SHORT_OPTIONS) |
|
| fputs("-SHORTS-", stderr); |
|
| if (con->cur_opt_type & CFG_LONG_SEPINIT) |
|
| fputs("-SEPINIT-", stderr); |
|
| |
|
| fputs("]\n", stderr); |
|
| #endif |
|
| |
|
| if (opt_idx < 0) |
|
| return CFG_ERROR_UNKNOWN; |
|
| |
|
| if ( ! (con->flags & CFG_IGNORE_MULTI) |
|
| && ! (con->options[opt_idx].type & CFG_MULTI)) { |
|
| int ret = 0; |
|
| |
|
| ret = add_to_used_opt_idx(con, opt_idx); |
|
| |
|
| if (ret < 0) |
|
| return CFG_ERROR_NOMEM; |
|
| else if (ret > 0) |
|
| return CFG_ERROR_MULTI; |
|
| } |
|
| |
|
| /* Setting others opt_XXX constants according to *opt_idx. */ |
|
| /* opt_data_type - option data type, opt_f_XXX - option flags */ |
|
| opt_data_type = con->options[opt_idx].type & CFG_DATA_TYPE_MASK; |
|
| opt_f_multi = con->options[opt_idx].type & CFG_MULTI; |
|
| opt_f_multi_sep = con->options[opt_idx].type & |
|
| (CFG_MULTI_SEPARATED & ~CFG_MULTI); |
|
| |
|
| switch (opt_data_type) { |
|
| default: |
|
| return CFG_ERROR_INTERNAL; |
|
| break; |
|
| |
|
| /* Boolean data type. */ |
|
| |
|
| case CFG_BOOLEAN: |
|
| if (con->cur_opt_type & CFG_LONG_SEPINIT |
|
| && con->cur_arg != NULL) |
|
| return CFG_ERROR_NOTALLOWEDARG; |
|
| |
|
| if (con->options[opt_idx].value != NULL) |
|
| (*((int *) con->options[opt_idx].value))++; |
|
| break; |
|
| |
|
| /* Numeric (int, long, float and double) data types. */ |
|
| |
|
| case CFG_INT: |
|
| case CFG_UINT: |
|
| case CFG_LONG: |
|
| case CFG_ULONG: |
|
| case CFG_FLOAT: |
|
| case CFG_DOUBLE: |
|
| |
|
| if (con->cur_arg == NULL) |
|
| return CFG_ERR_NOARG; |
|
| |
|
| { |
|
| register int ret; |
|
| |
|
| if (opt_f_multi) { |
|
| char **add; |
|
| char *static_add[2] = {NULL, NULL}; |
|
| |
|
| if (opt_f_multi_sep) { |
|
| add = strdyn_explode_ar(con->cur_arg, |
|
| con->multi_vals_separator); |
|
| if (add == NULL) |
|
| return CFG_ERROR_NOMEM; |
|
| } |
|
| else { |
|
| add = static_add; |
|
| add[0] = con->cur_arg; |
|
| } |
|
| |
|
| ret = store_multi_arg(opt_data_type, |
|
| (const char **) add, |
|
| con->options[opt_idx].value); |
|
| |
|
| if (add != static_add) |
|
| strdyn_free((char **) add); |
|
| } |
|
| else |
|
| ret = store_single_arg(opt_data_type, con->cur_arg, |
|
| con->options[opt_idx].value); |
|
| |
|
| if (ret != CFG_OK) |
|
| return ret; |
|
| } |
|
| |
|
| if (arg_used != NULL) |
|
| *arg_used = 1; |
|
| break; |
|
| |
|
| /* String data type. */ |
|
| |
|
| case CFG_STRING: |
|
| |
|
| if (con->cur_arg == NULL) |
|
| return CFG_ERR_NOARG; |
|
| |
|
| if (con->options[opt_idx].value != NULL) { |
|
| if (opt_f_multi) { |
|
| register char ***p; |
|
| p = (char ***) con->options[opt_idx].value; |
|
| |
|
| if (opt_f_multi_sep) { |
|
| register char **ar; |
|
| |
|
| ar = strdyn_explode_ar(con->cur_arg, |
|
| con->multi_vals_separator); |
|
| if (ar == NULL) |
|
| return CFG_ERROR_NOMEM; |
|
| |
|
| if ((*p = strdyn_add_ar(*p, ar)) == NULL) |
|
| return CFG_ERROR_NOMEM; |
|
| |
|
| strdyn_free(ar); |
|
| } |
|
| else { |
|
| if ((*p = strdyn_add(*p, con->cur_arg)) == NULL) |
|
| return CFG_ERROR_NOMEM; |
|
| } |
|
| } |
|
| else |
|
| *((char **) con->options[opt_idx].value) = |
|
| strdup(con->cur_arg); |
|
| } |
|
| |
|
| if (arg_used != NULL) |
|
| *arg_used = 1; |
|
| break; |
|
| } |
|
| |
|
| /* if (con->options[opt_idx].val != 0) */ |
|
| *ret_val = con->options[opt_idx].val; |
|
| |
|
| return CFG_OK; |
|
| } |
|
| |
|
| /* |
|
| * free_currents() |
|
| * |
|
| * Frees allocated memory for cur_opt, cur_arg. |
|
| * Sets cur_opt_type to CFG_NONE_OPTION. |
|
| */ |
|
| |
|
| static void free_currents(const CFG_CONTEXT con) |
|
| { |
|
| if (con->cur_opt != NULL) |
|
| free(con->cur_opt); |
|
| if (con->cur_arg != NULL) |
|
| free(con->cur_arg); |
|
| |
|
| con->cur_opt_type = CFG_NONE_OPTION; |
|
| |
|
| con->cur_opt = con->cur_arg = NULL; |
|
| } |
|
| |
|
| |
|
| /* |
|
| * cmdline_set_curents() |
|
| * |
|
| * Function allocate and initialize variables con->cur_opt and con->cur_arg |
|
| * according to con->argv[con->cur_idx]. |
|
| * Returns 1 on success, 0 on error (not enough memory). |
|
| */ |
|
| |
|
| static int cmdline_set_currents(const CFG_CONTEXT con) |
|
| { |
|
| register int i, size; |
|
| register char *s, *s_sep, *s_tmp; |
|
| |
|
| size = 0; |
|
| s = con->argv[con->cur_idx]; |
|
| |
|
| for (i = 0; con->short_option_prefix[i] != NULL; i++) |
|
| if (strlen(con->short_option_prefix[i]) > size |
|
| && strstr(s, con->short_option_prefix[i]) == s) |
|
| size = strlen(con->short_option_prefix[i]); |
|
| |
|
| size = -size; |
|
| |
|
| for (i = 0; con->long_option_prefix[i] != NULL; i++) |
|
| if (strlen(con->long_option_prefix[i]) > (size < 0 ? -size : size) |
|
| && strstr(s, con->long_option_prefix[i]) == s) |
|
| size = strlen(con->long_option_prefix[i]); |
|
| |
|
| s_sep = NULL; |
|
| |
|
| if (size == 0) { |
|
| con->cur_opt_type = CFG_NONE_OPTION; |
|
| } |
|
| else if (size < 0) { |
|
| s += -size; |
|
| s_sep = s + 1; |
|
| |
|
| if (strlen(s_sep) > 0) { |
|
| con->cur_opt_type = CFG_SHORT_OPTION + CFG_SHORT_OPTIONS; |
|
| |
|
| if ((con->cur_arg = strdup(s_sep)) == NULL) |
|
| return 0; |
|
| } |
|
| else { |
|
| con->cur_opt_type = CFG_SHORT_OPTION; |
|
| |
|
| if (con->argv[con->cur_idx + 1] != NULL) { |
|
| con->cur_arg = strdup(con->argv[con->cur_idx + 1]); |
|
| if (con->cur_arg == NULL) |
|
| return 0; |
|
| } |
|
| else |
|
| con->cur_arg = NULL; |
|
| } |
|
| } |
|
| else { |
|
| con->cur_opt_type = CFG_LONG_OPTION; |
|
| |
|
| s += size; |
|
| size = 0; |
|
| |
|
| for (i = 0; con->line_option_arg_separator[i] != NULL; i++) |
|
| if ((s_tmp = strstr(s, con->line_option_arg_separator[i])) != NULL) |
|
| if (s_sep == NULL || s_tmp < s_sep |
|
| || (s_tmp == s_sep && |
|
| strlen(con->line_option_arg_separator[i]) > size)) { |
|
| s_sep = s_tmp; |
|
| size = strlen(con->line_option_arg_separator[i]); |
|
| } |
|
| |
|
| if (s_sep == NULL) { |
|
| if (con->argv[con->cur_idx + 1] != NULL) { |
|
| con->cur_arg = strdup(con->argv[con->cur_idx + 1]); |
|
| if (con->cur_arg == NULL) |
|
| return 0; |
|
| } |
|
| else |
|
| con->cur_arg = NULL; |
|
| } |
|
| else { |
|
| con->cur_opt_type += CFG_LONG_SEPINIT; |
|
| if ((con->cur_arg = strdup(s_sep + size)) == NULL) |
|
| return 0; |
|
| } |
|
| } |
|
| |
|
| if (s_sep == NULL) |
|
| s_sep = s + strlen(s); |
|
| |
|
| con->cur_opt = (char *) malloc((s_sep - s + 1) * sizeof(char)); |
|
| if (con->cur_opt == NULL) |
|
| return 0; |
|
| |
|
| strncpy(con->cur_opt, s, s_sep - s); |
|
| con->cur_opt[s_sep - s] = '\0'; |
|
| |
|
| if (con->cur_opt_type == CFG_NONE_OPTION) { |
|
| register char *tmp_str; |
|
| |
|
| tmp_str =con->cur_opt; |
|
| con->cur_opt = con->cur_arg; |
|
| con->cur_arg = tmp_str; |
|
| } |
|
| |
|
| return 1; |
|
| } |
|
| |
|
| /* |
|
| * search_cur_opt_idx() |
|
| * |
|
| * Function searches con->options for con->cur_opt. |
|
| * Returns index on success or -1 if not found. |
|
| */ |
|
| |
|
| static int search_cur_opt_idx(const CFG_CONTEXT con) |
|
| { |
|
| register int i; |
|
| |
|
| for (i = 0; con->options[i].cmdline_long_name != NULL |
|
| || con->options[i].cmdline_short_name != '\0' |
|
| || con->options[i].cfgfile_name != NULL |
|
| || con->options[i].type != CFG_END |
|
| || con->options[i].value != NULL |
|
| || con->options[i].val != 0; |
|
| i++) |
|
| { |
|
| |
|
| if (con->type == CFG_CMDLINE) { |
|
| if ((con->cur_opt_type & CFG_LONG_OPTION && con->cur_opt != NULL |
|
| && con->options[i].cmdline_long_name != NULL |
|
| && ! strcmp(con->cur_opt, |
|
| con->options[i].cmdline_long_name)) |
|
| || (con->cur_opt_type & CFG_SHORT_OPTION && |
|
| con->cur_opt[0] == con->options[i].cmdline_short_name) |
|
| || (con->cur_opt_type == CFG_NONE_OPTION && |
|
| con->options[i].type & CFG_LEFTOVER_ARGS)) |
|
| |
|
| return i; |
|
| } |
|
| else { /* con->type == CFG_CFGFILE */ |
|
| if (con->cur_opt != NULL |
|
| && con->options[i].cfgfile_name != NULL |
|
| && ! strcmp(con->cur_opt, con->options[i].cfgfile_name)) |
|
| |
|
| return i; |
|
| } |
|
| } |
|
| |
|
| return -1; |
|
| } |
|
| |
|
| /* |
|
| * Size of realloc() step for used_opt member of cfg_context structure. |
|
| * Value must be grater than 0. |
|
| */ |
|
| |
|
| #ifdef CFG_USED_OPT_IDX_STEP |
|
| # undef CFG_USED_OPT_IDX_STEP |
|
| #endif |
|
| |
|
| #if defined(DEBUG) && DEBUG |
|
| # define CFG_USED_OPT_IDX_STEP (1) |
|
| #else |
|
| # define CFG_USED_OPT_IDX_STEP (10) |
|
| #endif |
|
| |
|
| /* |
|
| * add_to_used_opt_idx() |
|
| * |
|
| * Function adds opt_idx to dynamic array con->used_opt_idx. If array is full, |
|
| * it is realloc()-ed according to CFG_USED_OPT_IDX_STEP constant. This |
|
| * function is used for detecting multiple options on command line. |
|
| * |
|
| * Note, that in array -1 means empty cell, which can be overwritten by option |
|
| * index value and -255 means end of array. If there is no -1 left in array, |
|
| * array must be resized to add new option index value. |
|
| * |
|
| * Retuns -1 on not enough memory error, 1 if opt_idx founded in array and 0 if |
|
| * opt_idx was sucessfully added to array. |
|
| */ |
|
| |
|
| static int add_to_used_opt_idx(const CFG_CONTEXT con, int opt_idx) |
|
| { |
|
| int *p_i = NULL; |
|
| |
|
| if (opt_idx < 0) |
|
| return 1; |
|
| |
|
| if (con->used_opt_idx != NULL) |
|
| for (p_i = con->used_opt_idx; *p_i >= 0; p_i++) |
|
| if (*p_i == opt_idx) |
|
| return 1; |
|
| |
|
| if (p_i == NULL || *p_i == -255) { |
|
| register int *p_j; |
|
| register int new_size; |
|
| |
|
| new_size = (p_i == NULL ? 0 : p_i - con->used_opt_idx) |
|
| + 1 + CFG_USED_OPT_IDX_STEP; |
|
| |
|
| con->used_opt_idx = (int *) realloc(con->used_opt_idx, |
|
| new_size * sizeof(int)); |
|
| |
|
| #if defined(DEBUG) && DEBUG |
|
| printf("add_to_used_opt_idx(con, %d): realloc(%d) = %p\n", |
|
| opt_idx, new_size, con->used_opt_idx); |
|
| #endif |
|
| |
|
| if (con->used_opt_idx == NULL) |
|
| return -1; |
|
| |
|
| if (p_i == NULL) |
|
| p_i = con->used_opt_idx; |
|
| else /* Searching for new p_i after realloc(). */ |
|
| for (p_i = con->used_opt_idx; *p_i >= 0; p_i++) ; |
|
| |
|
| for (p_j = p_i; p_j - p_i < CFG_USED_OPT_IDX_STEP; p_j++) |
|
| *p_j = -1; |
|
| |
|
| *p_j = -255; |
|
| } |
|
| |
|
| *p_i = opt_idx; |
|
| |
|
| return 0; |
|
| } |
|
| |
|
| /* |
|
| * store_multi_arg() |
|
| * |
|
| * According to option date type (type) parses and stores multiple arguments |
|
| * (multi_arg) by adding to *ar dynamic array. Array resizing is done as first |
|
| * and than is store_single_arg() function called with appropriate parameters. |
|
| */ |
|
| |
|
| static int store_multi_arg(const int type, const char **multi_arg, void ***ar) |
|
| { |
|
| register int ptr_len, item_len; |
|
| register int size_plus, size; |
|
| register int k, ret; |
|
| |
|
| switch (type) { |
|
| default: |
|
| return CFG_ERROR_INTERNAL; |
|
| break; |
|
| |
|
| case CFG_INT: |
|
| ptr_len = sizeof(int *); |
|
| item_len = sizeof(int); |
|
| break; |
|
| |
|
| case CFG_UINT: |
|
| ptr_len = sizeof(unsigned int *); |
|
| item_len = sizeof(unsigned int); |
|
| break; |
|
| |
|
| case CFG_LONG: |
|
| ptr_len = sizeof(long *); |
|
| item_len = sizeof(long); |
|
| break; |
|
| |
|
| case CFG_ULONG: |
|
| ptr_len = sizeof(unsigned long *); |
|
| item_len = sizeof(unsigned long); |
|
| break; |
|
| |
|
| case CFG_FLOAT: |
|
| ptr_len = sizeof(float *); |
|
| item_len = sizeof(float); |
|
| break; |
|
| |
|
| case CFG_DOUBLE: |
|
| ptr_len = sizeof(double *); |
|
| item_len = sizeof(double); |
|
| break; |
|
| } |
|
| |
|
| for (size_plus = 0; multi_arg[size_plus] != NULL; size_plus++) ; |
|
| for (size = 0; *ar != NULL && (*ar)[size] != NULL; size++) ; |
|
| |
|
| *ar = realloc(*ar, (size + 1 + size_plus) * ptr_len); |
|
| |
|
| if (*ar == NULL) |
|
| return CFG_ERROR_NOMEM; |
|
| |
|
| /* Array terminated NULL pointer (end of array). */ |
|
| (*ar)[size + size_plus] = NULL; |
|
| |
|
| for (k = 0; k < size_plus; k++) { |
|
| (*ar)[size + k] = malloc(item_len); |
|
| if ((*ar)[size + k] == NULL) |
|
| return CFG_ERROR_NOMEM; |
|
| |
|
| ret = store_single_arg(type, multi_arg[k], (*ar)[size + k]); |
|
| |
|
| if (ret != CFG_OK) { |
|
| /* To prevent having random value at size + k position in *ar. */ |
|
| (*ar)[size + k] = NULL; |
|
| return ret; |
|
| } |
|
| } |
|
| |
|
| return CFG_OK; |
|
| } |
|
| |
|
| /* |
|
| * store_single_arg() |
|
| * |
|
| * According to option date type (type) parses and stores single argument (arg) |
|
| * to specified place pointed by where. |
|
| */ |
|
| |
|
| static int store_single_arg(const int type, const char *arg, const void *where) |
|
| { |
|
| register long long_val = 0; |
|
| register unsigned long ulong_val = 0; |
|
| register double double_val = 0.0; |
|
| char *end; |
|
| |
|
| if (where == NULL) |
|
| return CFG_OK; |
|
| |
|
| /* Conveting to numeric value. */ |
|
| switch (type) { |
|
| default: |
|
| return CFG_ERROR_INTERNAL; |
|
| break; |
|
| |
|
| case CFG_INT: |
|
| case CFG_UINT: |
|
| case CFG_LONG: |
|
| long_val = strtol(arg, &end, 0); |
|
| break; |
|
| |
|
| case CFG_ULONG: |
|
| ulong_val = strtoul(arg, &end, 0); |
|
| break; |
|
| |
|
| case CFG_FLOAT: |
|
| case CFG_DOUBLE: |
|
| double_val = strtod(arg, &end); |
|
| if (*end) |
|
| return CFG_ERROR_BADNUMBER; |
|
| |
|
| if (double_val == +HUGE_VAL || double_val == -HUGE_VAL) |
|
| return CFG_ERROR_OVERFLOW; |
|
| if (double_val == 0.0 && errno == ERANGE) |
|
| return CFG_ERROR_OVERFLOW; |
|
| break; |
|
| } |
|
| |
|
| /* Validating coversion results. */ |
|
| if (!(end && *end == '\0')) |
|
| return CFG_ERROR_BADNUMBER; |
|
| |
|
| /* Range checking and value storing. */ |
|
| switch (type) { |
|
| default: |
|
| return CFG_ERROR_INTERNAL; |
|
| break; |
|
| |
|
| case CFG_INT: |
|
| if (long_val >= INT_MAX || long_val <= INT_MIN) |
|
| return CFG_ERROR_OVERFLOW; |
|
| |
|
| *((int *) where) = (int) long_val; |
|
| break; |
|
| |
|
| case CFG_UINT: |
|
| if (long_val > UINT_MAX || long_val < 0) |
|
| return CFG_ERROR_OVERFLOW; |
|
| |
|
| *((unsigned int *) where) = (unsigned int) long_val; |
|
| break; |
|
| |
|
| case CFG_LONG: |
|
| if (long_val == LONG_MIN || long_val == LONG_MAX) |
|
| return CFG_ERROR_OVERFLOW; |
|
| |
|
| *((long *) where) = long_val; |
|
| break; |
|
| |
|
| case CFG_ULONG: |
|
| /* Fix strange strtoul() behaviour. */ |
|
| for (end = (char *) arg; isspace(*end); end++) ; |
|
| |
|
| /* Testing errno after strtoul() is not needed here. */ |
|
| if (*end == '-' || ulong_val == ULONG_MAX /* || ulong_val == 0 */) |
|
| return CFG_ERROR_OVERFLOW; |
|
| |
|
| *((unsigned long *) where) = (unsigned long) ulong_val; |
|
| break; |
|
| |
|
| case CFG_FLOAT: |
|
| #ifdef ABS /* Borrowed from popt library. */ |
|
| # undef ABS |
|
| #endif |
|
| #define ABS(a) (((a) < 0) ? -(a) : (a)) |
|
| |
|
| if (double_val != 0.0) |
|
| if (ABS(double_val) > FLT_MAX || ABS(double_val) < FLT_MIN) |
|
| return CFG_ERROR_OVERFLOW; |
|
| |
|
| *((float *) where) = (float) double_val; |
|
| break; |
|
| |
|
| case CFG_DOUBLE: |
|
| *((double *) where) = (double) double_val; |
|
| break; |
|
| } |
|
| |
|
| return CFG_OK; |
|
| } |
} |
| |
|