| version 1.7, 2001/11/28 20:46:51 |
version 1.8, 2001/11/30 02:10:27 |
|
|
| #include <math.h> |
#include <math.h> |
| #include <limits.h> |
#include <limits.h> |
| #include <float.h> |
#include <float.h> |
| #include <errno.h> |
|
| #include <ctype.h> |
#include <ctype.h> |
| |
#include <errno.h> |
| |
|
| #include "str/strplus.h" |
#include "str/strplus.h" |
| |
#include "str/strdyn.h" |
| |
|
| |
|
| static int cfg_cmdline_get_next_opt(const CFG_CONTEXT con); |
static int cfg_cmdline_get_next_opt(const CFG_CONTEXT con); |
| static void free_currents(const CFG_CONTEXT con); |
static void free_currents(const CFG_CONTEXT con); |
| static int set_currents(const CFG_CONTEXT con); |
static int set_currents(const CFG_CONTEXT con); |
| static int search_cur_opt(const CFG_CONTEXT con); |
static int search_cur_opt(const CFG_CONTEXT con); |
| |
static int add_to_used_opt_idx(const CFG_CONTEXT con, int opt_idx); |
| |
|
| |
|
| static int cfg_cmdline_get_next_opt(const CFG_CONTEXT con) { |
static int cfg_cmdline_get_next_opt(const CFG_CONTEXT con) { |
| |
|
| /* |
|
| while (con->argv[con->cur_idx] != NULL && con->argc > con->cur_idx) { |
|
| |
|
| if (set_currents(con) == 0) |
|
| return CFG_ERROR_NOMEM; |
|
| |
|
| printf("DEBUG|%d|%s|%s|%s|%s|\n", con->cur_idx, con->argv[con->cur_idx], |
|
| con->cur_opt_type ? con->cur_opt_type == 1 |
|
| ? "SHORT" : "LONG" |
|
| : "NONE", |
|
| con->cur_opt == NULL ? "[NULL]" : con->cur_opt, |
|
| con->cur_arg == NULL ? "[NULL]" : con->cur_arg); |
|
| |
|
| free_currents(con); |
|
| |
|
| con->cur_idx++; |
|
| } |
|
| |
|
| return 0; |
|
| */ |
|
| |
|
| register int opt_idx; |
register int opt_idx; |
| register int arg_used; |
register int arg_used; |
| |
|
| |
register int opt_data_type, opt_f_multi, opt_f_multi_sep, opt_f_leftover; |
| |
|
| while (1) { |
while (1) { |
| |
|
| arg_used = 0; |
arg_used = 0; |
| Line 69 static int cfg_cmdline_get_next_opt(cons |
|
| Line 52 static int cfg_cmdline_get_next_opt(cons |
|
| else { |
else { |
| free_currents(con); |
free_currents(con); |
| |
|
| |
if (! strdyn_compare(con->line_stop_str, con->argv[con->cur_idx])) |
| |
return CFG_ERROR_STOP_STR_FOUND; |
| |
|
| if (set_currents(con) == 0) |
if (set_currents(con) == 0) |
| return CFG_ERROR_NOMEM; |
return CFG_ERROR_NOMEM; |
| } |
} |
| Line 76 static int cfg_cmdline_get_next_opt(cons |
|
| Line 62 static int cfg_cmdline_get_next_opt(cons |
|
| opt_idx = search_cur_opt(con); |
opt_idx = search_cur_opt(con); |
| |
|
| #if defined(DEBUG) && DEBUG |
#if defined(DEBUG) && DEBUG |
| fprintf(stderr, "DEBUG|%d|%s|%s|%s|%d|flags=%x(", |
fprintf(stderr, "--\nDEBUG|%d|%s|%s|%s|%d|flags=%x(", |
| con->cur_idx, con->argv[con->cur_idx], |
con->cur_idx, con->argv[con->cur_idx], |
| con->cur_opt == NULL ? "[NULL]" : con->cur_opt, |
con->cur_opt == NULL ? "[NULL]" : con->cur_opt, |
| con->cur_arg == NULL ? "[NULL]" : con->cur_arg, |
con->cur_arg == NULL ? "[NULL]" : con->cur_arg, |
| Line 97 static int cfg_cmdline_get_next_opt(cons |
|
| Line 83 static int cfg_cmdline_get_next_opt(cons |
|
| if (opt_idx < 0) |
if (opt_idx < 0) |
| return CFG_ERROR_UNKNOWN; |
return CFG_ERROR_UNKNOWN; |
| |
|
| switch (con->options[opt_idx].type) { |
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); |
| |
opt_f_leftover = con->options[opt_idx].type & CFG_LEFTOVER_ARGS; |
| |
|
| |
switch (opt_data_type) { |
| default: |
default: |
| return CFG_ERROR_INTERNAL; |
return CFG_ERROR_INTERNAL; |
| break; |
break; |
| |
|
| |
/* |
| |
* Boolean data type. |
| |
*/ |
| |
|
| case CFG_BOOLEAN: |
case CFG_BOOLEAN: |
| if (con->cur_opt_type & CFG_LONG_SEPINIT |
if (con->cur_opt_type & CFG_LONG_SEPINIT |
| && con->cur_arg != NULL) |
&& con->cur_arg != NULL) |
| return CFG_ERROR_NOTALLOWEDARG; |
return CFG_ERROR_NOTALLOWEDARG; |
| |
|
| if (con->options[opt_idx].value != NULL) |
if (con->options[opt_idx].value != NULL) |
| *((int *)con->options[opt_idx].value) = 1; |
(*((int *)con->options[opt_idx].value))++; |
| break; |
break; |
| |
|
| |
/* |
| |
* Integer, unsigned integer and long data type. |
| |
*/ |
| |
|
| case CFG_INTEGER: |
case CFG_INTEGER: |
| case CFG_UNSIGNED_INT: |
case CFG_UNSIGNED_INT: |
| case CFG_LONG: |
case CFG_LONG: |
| Line 126 static int cfg_cmdline_get_next_opt(cons |
|
| Line 140 static int cfg_cmdline_get_next_opt(cons |
|
| if (!(end && *end == '\0')) |
if (!(end && *end == '\0')) |
| return CFG_ERROR_BADNUMBER; |
return CFG_ERROR_BADNUMBER; |
| |
|
| if (con->options[opt_idx].type == CFG_LONG) { |
if (opt_data_type == CFG_LONG) { |
| if (value == LONG_MIN || value == LONG_MAX) |
if (value == LONG_MIN || value == LONG_MAX) |
| return CFG_ERROR_OVERFLOW; |
return CFG_ERROR_OVERFLOW; |
| |
|
| if (con->options[opt_idx].value != NULL) |
if (con->options[opt_idx].value != NULL) |
| *((long *)con->options[opt_idx].value) = value; |
*((long *)con->options[opt_idx].value) = value; |
| } |
} |
| else if (con->options[opt_idx].type == CFG_UNSIGNED_INT) { |
else if (opt_data_type == CFG_UNSIGNED_INT) { |
| if (value > UINT_MAX || value < 0) |
if (value > UINT_MAX || value < 0) |
| return CFG_ERROR_OVERFLOW; |
return CFG_ERROR_OVERFLOW; |
| |
|
| Line 142 static int cfg_cmdline_get_next_opt(cons |
|
| Line 156 static int cfg_cmdline_get_next_opt(cons |
|
| (unsigned int) value; |
(unsigned int) value; |
| } |
} |
| else { |
else { |
| /* TODO: remove this |
|
| printf("testing: %ld < %d < (%ld) < %d < %ld\n", |
|
| LONG_MIN, |
|
| INT_MIN, |
|
| value, |
|
| INT_MAX, |
|
| LONG_MAX); |
|
| */ |
|
| |
|
| if (value >= INT_MAX || value <= INT_MIN) |
if (value >= INT_MAX || value <= INT_MIN) |
| return CFG_ERROR_OVERFLOW; |
return CFG_ERROR_OVERFLOW; |
| Line 163 static int cfg_cmdline_get_next_opt(cons |
|
| Line 169 static int cfg_cmdline_get_next_opt(cons |
|
| arg_used = 1; |
arg_used = 1; |
| break; |
break; |
| |
|
| |
/* |
| |
* Unsigned long data type |
| |
*/ |
| |
|
| case CFG_UNSIGNED_LONG: |
case CFG_UNSIGNED_LONG: |
| |
|
| if (con->cur_arg == NULL) |
if (con->cur_arg == NULL) |
| Line 190 static int cfg_cmdline_get_next_opt(cons |
|
| Line 200 static int cfg_cmdline_get_next_opt(cons |
|
| arg_used = 1; |
arg_used = 1; |
| break; |
break; |
| |
|
| |
/* |
| |
* Float and double data type. |
| |
*/ |
| |
|
| case CFG_FLOAT: |
case CFG_FLOAT: |
| case CFG_DOUBLE: |
case CFG_DOUBLE: |
| |
|
| Line 209 static int cfg_cmdline_get_next_opt(cons |
|
| Line 223 static int cfg_cmdline_get_next_opt(cons |
|
| if (value == 0.0 && errno == ERANGE) |
if (value == 0.0 && errno == ERANGE) |
| return CFG_ERROR_OVERFLOW; |
return CFG_ERROR_OVERFLOW; |
| |
|
| if (con->options[opt_idx].type == CFG_FLOAT) { |
if (opt_data_type == CFG_FLOAT) { |
| #ifdef ABS /* Borrowed from popt library. */ |
#ifdef ABS /* Borrowed from popt library. */ |
| #undef ABS |
# undef ABS |
| #endif |
#endif |
| #define ABS(a) (((a) < 0) ? -(a) : (a)) |
#define ABS(a) (((a) < 0) ? -(a) : (a)) |
| |
|
| Line 233 static int cfg_cmdline_get_next_opt(cons |
|
| Line 247 static int cfg_cmdline_get_next_opt(cons |
|
| arg_used = 1; |
arg_used = 1; |
| break; |
break; |
| |
|
| |
/* |
| |
* String data type. |
| |
*/ |
| |
|
| case CFG_STRING: |
case CFG_STRING: |
| |
|
| |
if (con->cur_arg == NULL) |
| |
return CFG_ERR_NOARG; |
| |
|
| |
if (con->options[opt_idx].value != NULL) { |
| |
if (opt_f_multi) { |
| |
char ***p = (char ***)con->options[opt_idx].value; |
| |
if (opt_f_multi_sep) { |
| |
/* TODO: split by all multi_separator[] |
| |
for (register int i = 0; |
| |
con->multi_separator[i] != NULL; i++) |
| |
*/ |
| |
char **ar; |
| |
|
| |
ar = strdyn_explode_str(con->cur_arg, |
| |
con->multi_separator[0]); |
| |
|
| |
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); |
| |
} |
| |
|
| |
arg_used = 1; |
| break; |
break; |
| } |
} |
| |
|
| Line 261 static int cfg_cmdline_get_next_opt(cons |
|
| Line 315 static int cfg_cmdline_get_next_opt(cons |
|
| return CFG_OK; |
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) { |
static void free_currents(const CFG_CONTEXT con) { |
| |
|
| if (con->cur_opt != NULL) |
if (con->cur_opt != NULL) |
| Line 373 static int set_currents(const CFG_CONTEX |
|
| Line 434 static int set_currents(const CFG_CONTEX |
|
| return 1; |
return 1; |
| } |
} |
| |
|
| |
/* |
| |
* search_cur_opt() |
| |
* |
| |
* Function searches con->options for con->cur_opt. |
| |
* Returns index on success or -1 if not found. |
| |
*/ |
| |
|
| static int search_cur_opt(const CFG_CONTEXT con) { |
static int search_cur_opt(const CFG_CONTEXT con) { |
| register int i; |
register int i; |
| |
|
| Line 405 static int search_cur_opt(const CFG_CONT |
|
| Line 473 static int search_cur_opt(const CFG_CONT |
|
| return -1; |
return -1; |
| } |
} |
| |
|
| |
#ifdef CFG_USED_OPT_IDX_STEP |
| |
# undef CFG_USED_OPT_IDX_STEP |
| |
#endif |
| |
|
| |
#if defined(DEBUG) && DEBUG |
| |
# define CFG_USED_OPT_IDX_STEP (1) /* Must be greater than 0. */ |
| |
#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; |
| |
} |
| |
|