@@ -36,40 +36,44 @@ #include #endif struct lc_varhandler_st *varhandlers = NULL; lc_err_t lc_errno = LC_ERR_NONE; +const char *lc_errfile = NULL; int lc_optind = 0; +int lc_errline = 0; extern char **environ; -static int lc_process_var_string(void *data, const char *value) { +static int lc_process_var_string(void *data, const char *value, const char **endptr) { char **dataval; dataval = data; *dataval = strdup(value); + *endptr = NULL; + return(0); } -static int lc_process_var_cidr(void *data, const char *value) { +static int lc_process_var_cidr(void *data, const char *value, const char **endptr) { + return(-1); +} + +static int lc_process_var_hostname6(void *data, const char *value, const char **endptr) { return(-1); } -static int lc_process_var_hostname6(void *data, const char *value) { +static int lc_process_var_hostname4(void *data, const char *value, const char **endptr) { return(-1); } -static int lc_process_var_hostname4(void *data, const char *value) { +static int lc_process_var_ip6(void *data, const char *value, const char **endptr) { return(-1); } -static int lc_process_var_ip6(void *data, const char *value) { - return(-1); -} - -static int lc_process_var_ip4(void *data, const char *value) { +static int lc_process_var_ip4(void *data, const char *value, const char **endptr) { uint32_t *dataval, retval = 0; const char *dotptr = NULL; int tmpval = -1; // int dotcount @@ -96,90 +100,134 @@ dotptr++; } *dataval = retval; + *endptr = (char *) dotptr; + return(0); } -static int lc_process_var_longlong(void *data, const char *value) { +static int lc_process_var_longlong(void *data, const char *value, const char **endptr) { long long *dataval; dataval = data; - *dataval = strtoll(value, NULL, 10); + *dataval = strtoll(value, (char **) endptr, 10); return(0); } -static int lc_process_var_long(void *data, const char *value) { +static int lc_process_var_long(void *data, const char *value, const char **endptr) { long *dataval; dataval = data; - *dataval = strtoll(value, NULL, 10); + *dataval = strtoll(value, (char **) endptr, 10); return(0); } -static int lc_process_var_int(void *data, const char *value) { +static int lc_process_var_int(void *data, const char *value, const char **endptr) { int *dataval; dataval = data; - *dataval = strtoll(value, NULL, 10); + *dataval = strtoll(value, (char **) endptr, 10); return(0); } -static int lc_process_var_short(void *data, const char *value) { +static int lc_process_var_short(void *data, const char *value, const char **endptr) { short *dataval; dataval = data; - *dataval = strtoll(value, NULL, 10); + *dataval = strtoll(value, (char **) endptr, 10); return(0); } -static int lc_process_var_bool_byexistance(void *data, const char *value) { +static int lc_process_var_bool_byexistance(void *data, const char *value, const char **endptr) { int *dataval; dataval = data; *dataval = 1; + *endptr = NULL; + return(0); } -static int lc_process_var_bool(void *data, const char *value) { +static int lc_process_var_bool(void *data, const char *value, const char **endptr) { + char *trueval[] = {"enable", "true", "yes", "on", "y", "1"}; + char *falseval[] = {"disable", "false", "no", "off", "n", "0"}; + size_t chkvallen, vallen; int *dataval; + int i; dataval = data; *dataval = -1; - if (strcasecmp(value, "enable") == 0 || - strcasecmp(value, "true") == 0 || - strcasecmp(value, "yes") == 0 || - strcasecmp(value, "on") == 0 || - strcasecmp(value, "y") == 0 || - strcasecmp(value, "1") == 0) { - *dataval = 1; - return(0); - } else if (strcasecmp(value, "disable") == 0 || - strcasecmp(value, "false") == 0 || - strcasecmp(value, "off") == 0 || - strcasecmp(value, "no") == 0 || - strcasecmp(value, "n") == 0 || - strcasecmp(value, "0") == 0) { - *dataval = 0; - return(0); + vallen = strlen(value); + + for (i = 0; i < (sizeof(trueval) / sizeof(*trueval)); i++) { + chkvallen = strlen(trueval[i]); + + /* + * Skip if there's no way we could find a match here. + */ + if (chkvallen > vallen) { + continue; + } + + /* + * Skip if there is no partial match. + */ + if (strncasecmp(value, trueval[i], chkvallen) != 0) { + continue; + } + + if (value[chkvallen] == '\0' || value[chkvallen] == ',' || \ + value[chkvallen] == ' ') { + /* Declare a winner and set the next token. */ + *endptr = value + chkvallen; + *dataval = 1; + return(0); + } + } + + for (i = 0; i < (sizeof(falseval) / sizeof(*falseval)); i++) { + chkvallen = strlen(falseval[i]); + + /* + * Skip if there's no way we could find a match here. + */ + if (chkvallen > vallen) { + continue; + } + + /* + * Skip if there is no partial match. + */ + if (strncasecmp(value, falseval[i], chkvallen) != 0) { + continue; + } + + if (value[chkvallen] == '\0' || value[chkvallen] == ',' || \ + value[chkvallen] == ' ') { + /* Declare a winner and set the next token. */ + *endptr = value + chkvallen; + *dataval = 0; + return(0); + } } lc_errno = LC_ERR_BADFORMAT; return(-1); } -static long long lc_process_size(const char *value) { - long long retval = -1; +static unsigned long long lc_process_size(const char *value, const char **endptr) { + unsigned long long retval = 0; char *mult = NULL; retval = strtoll(value, &mult, 10); if (mult != NULL) { switch (tolower(mult[0])) { @@ -204,109 +252,117 @@ } return(retval); } -static int lc_process_var_sizelonglong(void *data, const char *value) { - long long *dataval; - - dataval = data; - *dataval = lc_process_size(value); - - return(0); -} - -static int lc_process_var_sizelong(void *data, const char *value) { - long *dataval; - - dataval = data; - *dataval = lc_process_size(value); - - return(0); -} - -static int lc_process_var_sizeint(void *data, const char *value) { - int *dataval; - - dataval = data; - *dataval = lc_process_size(value); - - return(0); -} - -static int lc_process_var_sizeshort(void *data, const char *value) { - short *dataval; - - dataval = data; - *dataval = lc_process_size(value); - - return(0); -} - -static int lc_process_var_sizesizet(void *data, const char *value) { - size_t *dataval; - - dataval = data; - *dataval = lc_process_size(value); +static int lc_process_var_sizelonglong(void *data, const char *value, const char **endptr) { + long long *dataval; + + dataval = data; + *dataval = lc_process_size(value, endptr); + + return(0); +} + +static int lc_process_var_sizelong(void *data, const char *value, const char **endptr) { + long *dataval; + + dataval = data; + *dataval = lc_process_size(value, endptr); + + return(0); +} + +static int lc_process_var_sizeint(void *data, const char *value, const char **endptr) { + int *dataval; + + dataval = data; + *dataval = lc_process_size(value, endptr); + + return(0); +} + +static int lc_process_var_sizeshort(void *data, const char *value, const char **endptr) { + short *dataval; + + dataval = data; + *dataval = lc_process_size(value, endptr); + + return(0); +} + +static int lc_process_var_sizesizet(void *data, const char *value, const char **endptr) { + size_t *dataval; + + dataval = data; + *dataval = lc_process_size(value, endptr); return(0); } static int lc_handle_type(lc_var_type_t type, const char *value, void *data) { + const char *next; + int is_list; + + is_list = type & LC_VAR_LIST; + + if (is_list == LC_VAR_LIST) { + } + switch (type) { case LC_VAR_STRING: - return(lc_process_var_string(data, value)); + return(lc_process_var_string(data, value, &next)); break; case LC_VAR_LONG_LONG: - return(lc_process_var_longlong(data, value)); + return(lc_process_var_longlong(data, value, &next)); break; case LC_VAR_LONG: - return(lc_process_var_long(data, value)); + return(lc_process_var_long(data, value, &next)); break; case LC_VAR_INT: - return(lc_process_var_int(data, value)); + return(lc_process_var_int(data, value, &next)); break; case LC_VAR_SHORT: - return(lc_process_var_short(data, value)); + return(lc_process_var_short(data, value, &next)); break; case LC_VAR_BOOL: - return(lc_process_var_bool(data, value)); + return(lc_process_var_bool(data, value, &next)); break; case LC_VAR_SIZE_LONG_LONG: - return(lc_process_var_sizelonglong(data, value)); + return(lc_process_var_sizelonglong(data, value, &next)); break; case LC_VAR_SIZE_LONG: - return(lc_process_var_sizelong(data, value)); + return(lc_process_var_sizelong(data, value, &next)); break; case LC_VAR_SIZE_INT: - return(lc_process_var_sizeint(data, value)); + return(lc_process_var_sizeint(data, value, &next)); break; case LC_VAR_SIZE_SHORT: - return(lc_process_var_sizeshort(data, value)); + return(lc_process_var_sizeshort(data, value, &next)); break; case LC_VAR_BOOL_BY_EXISTANCE: - return(lc_process_var_bool_byexistance(data, value)); + return(lc_process_var_bool_byexistance(data, value, &next)); break; case LC_VAR_SIZE_SIZE_T: - return(lc_process_var_sizesizet(data, value)); + return(lc_process_var_sizesizet(data, value, &next)); break; case LC_VAR_IP: case LC_VAR_IP4: - return(lc_process_var_ip4(data, value)); + return(lc_process_var_ip4(data, value, &next)); break; case LC_VAR_IP6: - return(lc_process_var_ip6(data, value)); + return(lc_process_var_ip6(data, value, &next)); break; case LC_VAR_HOSTNAME4: - return(lc_process_var_hostname4(data, value)); + return(lc_process_var_hostname4(data, value, &next)); break; case LC_VAR_HOSTNAME6: - return(lc_process_var_hostname6(data, value)); + return(lc_process_var_hostname6(data, value, &next)); break; case LC_VAR_CIDR: - return(lc_process_var_cidr(data, value)); + return(lc_process_var_cidr(data, value, &next)); break; case LC_VAR_TIME: case LC_VAR_DATE: case LC_VAR_FILENAME: case LC_VAR_DIRECTORY: @@ -367,20 +423,27 @@ char **currvar; char *sep = NULL, *value = NULL, *cmd = NULL; char *ucase_appname = NULL, *ucase_appname_itr = NULL; char *lastcomponent_handler = NULL; int varnamelen = 0; + char *local_lc_errfile; + int local_lc_errline; /* Make sure we have an environment to screw with, if not, no arguments were found to be in error */ if (environ == NULL || appname == NULL) { return(0); } + + local_lc_errfile = ""; + local_lc_errline = 0; /* Allocate and create our uppercase appname. */ ucase_appname = strdup(appname); if (ucase_appname == NULL) { + lc_errfile = local_lc_errfile; + lc_errline = local_lc_errline; lc_errno = LC_ERR_ENOMEM; return(-1); } for (ucase_appname_itr = ucase_appname; *ucase_appname_itr != '\0'; ucase_appname_itr++) { *ucase_appname_itr = toupper(*ucase_appname_itr); @@ -488,23 +551,32 @@ char *usedargv = NULL; int cmdargidx = 0; int newargvidx = 0; int retval = 0, chkretval = 0; int ch = 0; + char *local_lc_errfile; + int local_lc_errline; + + local_lc_errfile = ""; + local_lc_errline = 0; /* Allocate "argc + 1" (+1 for the NULL terminator) elements. */ newargv = malloc((argc + 1) * sizeof(*newargv)); if (newargv == NULL) { + lc_errfile = local_lc_errfile; + lc_errline = local_lc_errline; lc_errno = LC_ERR_ENOMEM; return(-1); } newargv[newargvidx++] = argv[0]; newargv[argc] = NULL; /* Allocate space to indicate which arguments have been used. */ usedargv = malloc(argc * sizeof(*usedargv)); if (usedargv == NULL) { + lc_errfile = local_lc_errfile; + lc_errline = local_lc_errline; lc_errno = LC_ERR_ENOMEM; free(newargv); return(-1); } for (cmdargidx = 0; cmdargidx < argc; cmdargidx++) { @@ -517,11 +589,11 @@ /* Make sure we have an argument here. */ if (cmdarg == NULL) { break; } - /* If the argument isn't an option, abort. */ + /* If the argument isn't an option, skip. */ if (cmdarg[0] != '-') { continue; } /* Setup a pointer in the new array for the actual argument. */ @@ -583,10 +655,12 @@ cmdoptarg = NULL; } else { cmdargidx++; if (cmdargidx >= argc) { fprintf(stderr, "Argument required.\n"); + lc_errfile = local_lc_errfile; + lc_errline = local_lc_errline; lc_errno = LC_ERR_BADFORMAT; free(usedargv); free(newargv); return(-1); } @@ -603,10 +677,12 @@ break; } if (handler == NULL) { fprintf(stderr, "Unknown option: --%s\n", cmdarg); + lc_errfile = local_lc_errfile; + lc_errline = local_lc_errline; lc_errno = LC_ERR_INVCMD; free(usedargv); free(newargv); return(-1); } @@ -631,10 +707,12 @@ cmdoptarg = NULL; } else { cmdargidx++; if (cmdargidx >= argc) { fprintf(stderr, "Argument required.\n"); + lc_errfile = local_lc_errfile; + lc_errline = local_lc_errline; lc_errno = LC_ERR_BADFORMAT; free(usedargv); free(newargv); return(-1); } @@ -643,18 +721,22 @@ usedargv[cmdargidx] = 1; } chkretval = lc_handle(handler, handler->var, NULL, cmdoptarg, LC_FLAGS_CMDLINE); if (chkretval < 0) { + lc_errfile = local_lc_errfile; + lc_errline = local_lc_errline; retval = -1; } break; } if (handler == NULL) { fprintf(stderr, "Unknown option: -%c\n", ch); + lc_errfile = local_lc_errfile; + lc_errline = local_lc_errline; lc_errno = LC_ERR_INVCMD; free(usedargv); free(newargv); return(-1); } @@ -939,41 +1021,53 @@ return(retval); } char *lc_geterrstr(void) { - char *retval = NULL; - - switch (lc_errno) { - case LC_ERR_NONE: - retval = "Success"; - break; - case LC_ERR_INVCMD: - retval = "Invalid command"; - break; - case LC_ERR_INVSECTION: - retval = "Invalid section"; - break; - case LC_ERR_INVDATA: - retval = "Invalid application data (internal error)"; - break; - case LC_ERR_BADFORMAT: - retval = "Bad data specified or incorrect format."; - break; - case LC_ERR_CANTOPEN: - retval = "Can't open file."; - break; - case LC_ERR_CALLBACK: - retval = "Error return from application handler."; - break; - case LC_ERR_ENOMEM: - retval = "Insuffcient memory."; - break; - } - - lc_errno = LC_ERR_NONE; - - if (retval != NULL) { - return(retval); - } - return("Unknown error"); + static char retval[512]; + char *errmsg = NULL; + + switch (lc_errno) { + case LC_ERR_NONE: + errmsg = "Success"; + break; + case LC_ERR_INVCMD: + errmsg = "Invalid command or option"; + break; + case LC_ERR_INVSECTION: + errmsg = "Invalid section"; + break; + case LC_ERR_INVDATA: + errmsg = "Invalid application data (internal error)"; + break; + case LC_ERR_BADFORMAT: + errmsg = "Bad data specified or incorrect format."; + break; + case LC_ERR_CANTOPEN: + errmsg = "Can't open file."; + break; + case LC_ERR_CALLBACK: + errmsg = "Error return from application handler."; + break; + case LC_ERR_ENOMEM: + errmsg = "Insuffcient memory."; + break; + } + + /* + * This is not part of the switch statement so we will get warnings + * about unhandled enum values. + */ + if (errmsg == NULL) { + errmsg = "Unknown error"; + } + + if (lc_errfile == NULL) { + snprintf(retval, sizeof(retval), "%s:%i: %s", "", lc_errline, errmsg); + } else { + snprintf(retval, sizeof(retval), "%s:%i: %s", lc_errfile, lc_errline, errmsg); + } + + retval[sizeof(retval) - 1] = '\0'; + + return(retval); }