Index: ossp-pkg/petidomo/libargv/argv.c RCS File: /v/ossp/cvs/ossp-pkg/petidomo/libargv/argv.c,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/petidomo/libargv/argv.c,v' 2>/dev/null --- argv.c 2000/12/13 13:19:10 1.1 +++ argv.c 2000/12/13 15:37:35 1.2 @@ -1,9 +1,10 @@ /* - * Generic argv processor... + * $Source$ + * $Revision$ + * $Date$ * - * Copyright 1995 by Gray Watson - * - * This file is part of the argv library. + * Copyright (c) 1999 by Gray Watson . + * All rights reserved. * * Permission to use, copy, modify, and distribute this software for * any purpose and without fee is hereby granted, provided that the @@ -13,94 +14,150 @@ * without specific, written prior permission. * * Gray Watson makes no representations about the suitability of the - * software described herein for any purpose. It is provided "as is" + * software described herein for any purpose. It is provided "as is" * without express or implied warranty. - * - * The author may be contacted at gray.watson@letters.com - * - * - Parse command line parameters conveniently. - * */ #include #include #include #include -#include -#include "_argv.h" +#include "argv.h" +#include "argv_loc.h" /* internal routines */ -LOCAL void do_list(argv_t *grid, const int argc, char **argv, - char *okay_p); +static void do_list(argv_t *grid, const int arg_c, char **argv, + argv_t **queue_list, int *queue_head_p, + int *queue_tail_p, int *okay_bp); /* * exported variables */ /* This is a processed version of argv[0], pre-path removed: /bin/ls -> ls */ -EXPORT char argv_program[PROGRAM_NAME + 1] = "Unknown"; +char argv_program[PROGRAM_NAME + 1] = "Unknown"; /* A global value of argv from main after argv_process has been called */ -EXPORT char **argv_argv = NULL; +char **argv_argv = NULL; /* A global value of argc from main after argv_process has been called */ -EXPORT int argv_argc = 0; +int argv_argc = 0; /* This should be set externally to provide general program help to user */ -EXPORT char *argv_help_string = NULL; +char *argv_help_string = NULL; /* This should be set externally to provide version information to the user */ -EXPORT char *argv_version_string = NULL; +char *argv_version_string = NULL; /* * Are we running interactively? This will exit on errors. Set to * false to return error codes instead. */ -EXPORT char argv_interactive = ARGV_TRUE; +int argv_interactive = ARGV_TRUE; /* * The FILE stream that argv out_puts all its errors. Set to NULL to * not dump any error messages. Default is stderr. */ -EXPORT FILE *argv_error_stream = ERROR_STREAM_INIT; +FILE *argv_error_stream = ERROR_STREAM_INIT; /* local variables */ -LOCAL_QUEUE_DECLARE(argv_t *); /* args waiting for values */ -LOCAL argv_t empty[] = {{ ARGV_LAST }}; /* empty argument array */ -LOCAL char enabled = ARGV_FALSE; /* are the lights on? */ +static argv_t empty[] = {{ ARGV_LAST }}; /* empty argument array */ +static int enabled_b = ARGV_FALSE; /* are the lights on? */ /* global settings */ -LOCAL int global_close = GLOBAL_CLOSE_ENABLE; /* close processing */ -LOCAL int global_env = GLOBAL_ENV_BEFORE; /* env processing */ -LOCAL int global_error = GLOBAL_ERROR_SEE; /* error processing */ -LOCAL int global_multi = GLOBAL_MULTI_ACCEPT; /* multi processing */ -LOCAL int global_usage = GLOBAL_USAGE_LONG; /* usage processing */ +static int global_close = GLOBAL_CLOSE_ENABLE; /* close processing */ +static int global_env = GLOBAL_ENV_BEFORE; /* env processing */ +static int global_error = GLOBAL_ERROR_SEE; /* error processing */ +static int global_multi = GLOBAL_MULTI_ACCEPT; /* multi processing */ +static int global_usage = GLOBAL_USAGE_LONG; /* usage processing */ +static int global_lasttog = GLOBAL_LASTTOG_DISABLE; /*last-arg toggling*/ /****************************** startup routine ******************************/ /* + * static void argv_startup + * + * DESCRIPTION: + * * Turn on the lights. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * None. */ -LOCAL void argv_startup(void) +static void argv_startup(void) { - if (enabled) + if (enabled_b) { return; - enabled = ARGV_TRUE; + } + enabled_b = ARGV_TRUE; /* ANSI says we cannot predefine this above */ - if (argv_error_stream == ERROR_STREAM_INIT) + if (argv_error_stream == ERROR_STREAM_INIT) { argv_error_stream = stderr; + } } /***************************** general utilities *****************************/ + +/*** ET: BSD's strsep funktion. See their man-page... ***/ + +char * +my_strsep(char **stringp, const char *delim) +{ + register char *s; + register const char *spanp; + register int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return NULL; + for (tok = s;;) + { + c = *s++; + spanp = delim; + do + { + if ((sc = *spanp++) == c) + { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return tok; + } + } while (sc != 0); + } + /* NOTREACHED */ +} + /* - * Binary STR to integer translation + * static int btoi + * + * DESCRIPTION: + * + * Binary string to integer translation. + * + * RETURNS: + * + * Integer converted from the string. + * + * ARGUMENTS: + * + * str - String of binary 0s and 1s that we are converting. */ -LOCAL int btoi(const char *str) +static int btoi(const char *str) { int ret = 0; /* strip off spaces */ - for (; isspace((int)*str); str++); + for (; isspace((int)*str); str++) { + } for (; *str == '0' || *str == '1'; str++) { ret *= 2; @@ -111,14 +168,27 @@ } /* - * Octal STR to integer translation + * static int otoi + * + * DESCRIPTION: + * + * Octal string to integer translation. + * + * RETURNS: + * + * Integer converted from the string. + * + * ARGUMENTS: + * + * str - String of octal digits that we are converting. */ -LOCAL int otoi(const char *str) +static int otoi(const char *str) { int ret = 0; /* strip off spaces */ - for (; isspace((int)*str); str++); + for (; isspace((int)*str); str++) { + } for (; *str >= '0' && *str <= '7'; str++) { ret *= 8; @@ -129,174 +199,301 @@ } /* - * Hexadecimal STR to integer translation + * static int htoi + * + * DESCRIPTION: + * + * Hexadecimal string to integer translation. + * + * RETURNS: + * + * Integer converted from the string. + * + * ARGUMENTS: + * + * str - String of hexadecimal characters and digits that we are + * converting. */ -LOCAL int htoi(const char *str) +static int htoi(const char *str) { int ret = 0; /* strip off spaces */ - for (; isspace((int)*str); str++); + for (; isspace((int)*str); str++) { + } /* skip a leading 0[xX] */ - if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) + if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) { str += 2; + } for (; isdigit((int)*str) || (*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F'); str++) { ret *= 16; - if (*str >= 'a' && *str <= 'f') + if (*str >= 'a' && *str <= 'f') { ret += *str - 'a' + 10; - else if (*str >= 'A' && *str <= 'F') + } + else if (*str >= 'A' && *str <= 'F') { ret += *str - 'A' + 10; - else + } + else { ret += *str - '0'; + } } return ret; } /* - * Basically a strdup for compatibility sake + * static char *string_copy + * + * DESCRIPTION: + * + * Basically a strdup for compatibility sake. + * + * RETURNS: + * + * Character pointer that must be freed later. + * + * ARGUMENTS: + * + * str - String we are copying. */ -LOCAL char *string_copy(const char *ptr) +static char *string_copy(const char *str) { - const char *ptr_p; - char *ret, *ret_p; + const char *str_p; + char *copy, *copy_p; int len; - len = strlen(ptr); - ret = (char *)malloc(len + 1); - if (ret == NULL) { - if (argv_error_stream != NULL) + len = strlen(str); + copy = (char *)malloc(len + 1); + if (copy == NULL) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return NULL; } - for (ptr_p = ptr, ret_p = ret; *ptr_p != NULLC;) - *ret_p++ = *ptr_p++; - *ret_p = NULLC; + for (str_p = str, copy_p = copy; *str_p != '\0';) { + *copy_p++ = *str_p++; + } + *copy_p = '\0'; - return ret; + return copy; } /* - * Break STR and return an array of char * whose values are tokenized - * by TOK. it passes back the number of tokens in TOKN. + * static char **vectorize * - * NOTE: the return value should be freed later and the STR should stay - * around until that time. + * DESCRIPTION: + * + * Break a string up into its arguments separated by one of the + * characters in a token string and return an array of char pointers. + * + * NOTE: the string argument should stay around until that time. + * + * RETURNS: + * + * Success - Allocated list of character poiners into the string + * argument which must be freed later. + * + * Failure - NULL + * + * ARGUMENTS: + * + * str - String we are tokenizing. + * + * tok - List of token characters to look for in the string. + * + * num_tok_p - Pointer to an integer which will be set to the number + * of tokens found in the string. */ -LOCAL char **vectorize(char *str, const char *tok, int *tokn) +static char **vectorize(char *str, const char *tok, int *num_tok_p) { char **vect_p; - char *tmp, *tok_p; - int tok_c; + char *tmp, *str_p, *tok_p; + int tok_c, tok_n; /* count the tokens */ tmp = string_copy(str); - if (tmp == NULL) + if (tmp == NULL) { return NULL; + } - tok_p = strtok(tmp, tok); - for (tok_c = 0; tok_p != NULL; tok_c++) - tok_p = strtok(NULL, tok); + str_p = tmp; + tok_c = 0; + while (1) { + tok_p = my_strsep(&str_p, tok); + if (tok_p == NULL) { + break; + } + if (*tok_p != '\0') { + tok_c++; + } + } + tok_n = tok_c; free(tmp); - *tokn = tok_c; + *num_tok_p = tok_n; - if (tok_c == 0) + if (tok_c == 0) { return NULL; + } /* allocate the pointer grid */ vect_p = (char **)malloc(sizeof(char *) * tok_c); if (vect_p == NULL) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return NULL; } /* load the tokens into the list */ - vect_p[0] = strtok(str, tok); - - for (tok_c = 1; tok_c < *tokn; tok_c++) - vect_p[tok_c] = strtok(NULL, tok); + str_p = str; + for (tok_c = 0; tok_c < tok_n;) { + tok_p = my_strsep(&str_p, tok); + if (tok_p == NULL) { + break; + } + if (*tok_p != '\0') { + vect_p[0] = tok_p; + tok_c++; + } + } return vect_p; } /* - * Display printable chars from BUF of SIZE, non-printables as \%03o + * static int expand_buf + * + * DESCRIPTION: + * + * Translates a buffer of bytes into its printable version. + * + * NOTE: it does _not_ add a \0 at the end of OUT. + * + * RETURNS: + * + * Number of characters written in to the output buffer. + * + * ARGUMENTS: + * + * buf - Input buffer of bytes. + * + * buf_size - Size of the input buffer. If < 0 then the routing will + * translate up to the first \0. + * + * out - Output buffer for the translated characters. + * + * out_size - Maximum size of the output buffer. */ -LOCAL char *expand_buf(const void *buf, const int size) +static int expand_buf(const void *buf, const int buf_size, + char *out, const int out_size) { - static char out[DUMP_SPACE_BUF]; - int size_c; - void *buf_p; - char *out_p; + int buf_c; + const unsigned char *buf_p, *spec_p; + char *max_p, *out_p = out; - for (size_c = 0, out_p = out, buf_p = (void *)buf; size_c < size; - size_c++, buf_p = (char *)buf_p + 1) { - char *spec_p; + /* setup our max pointer */ + max_p = out + out_size; - /* handle special chars */ - if (out_p + 2 >= out + sizeof(out)) - break; + /* run through the input buffer, counting the characters as we go */ + for (buf_c = 0, buf_p = (const unsigned char *)buf;; buf_c++, buf_p++) { + + /* did we reach the end of the buffer? */ + if (buf_size < 0) { + if (*buf_p == '\0') { + break; + } + } + else { + if (buf_c >= buf_size) { + break; + } + } /* search for special characters */ - for (spec_p = SPECIAL_CHARS + 1; *(spec_p - 1) != NULLC; spec_p += 2) - if (*spec_p == *(char *)buf_p) + for (spec_p = (unsigned char *)SPECIAL_CHARS + 1; + *(spec_p - 1) != '\0'; + spec_p += 2) { + if (*spec_p == *buf_p) { break; + } + } /* did we find one? */ - if (*(spec_p - 1) != NULLC) { - if (out_p + 2 >= out + sizeof(out)) + if (*(spec_p - 1) != '\0') { + if (out_p + 2 >= max_p) { break; + } (void)sprintf(out_p, "\\%c", *(spec_p - 1)); out_p += 2; continue; } - if (*(unsigned char *)buf_p < 128 && isprint((int)(*(char *)buf_p))) { - if (out_p + 1 >= out + sizeof(out)) + /* print out any 7-bit printable characters */ + if (*buf_p < 128 && isprint(*buf_p)) { + if (out_p + 1 >= max_p) { break; + } *out_p = *(char *)buf_p; out_p += 1; } else { - if (out_p + 4 >= out + sizeof(out)) + if (out_p + 4 >= max_p) { break; - (void)sprintf(out_p, "\\%03o", *(unsigned char *)buf_p); + } + (void)sprintf(out_p, "\\%03o", *buf_p); out_p += 4; } } - *out_p = NULLC; - return out; + return out_p - out; } + /****************************** usage routines *******************************/ /* + * static void usage_short + * + * DESCRIPTION: + * * Print a short-format usage message. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * args - Array of argv_t structions whose usage messages you print. + * + * flags - User flags. */ -LOCAL void usage_short(const argv_t *args, const int flag) +static void usage_short(const argv_t *args, const int flag) { const argv_t *arg_p; int len, col_c = 0; - char mark = ARGV_FALSE, *prefix; + int mark_b = ARGV_FALSE; + char *prefix; - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return; + } /* print the usage message header */ (void)fprintf(argv_error_stream, "%s%s", USAGE_LABEL, argv_program); @@ -310,18 +507,21 @@ /* skip or-specifiers */ if (arg_p->ar_short_arg == ARGV_OR - || arg_p->ar_short_arg == ARGV_XOR) + || arg_p->ar_short_arg == ARGV_XOR) { continue; + } /* skip non booleans */ - if (HAS_ARG(arg_p->ar_type)) + if (HAS_ARG(arg_p->ar_type)) { continue; + } /* skip args with no short component */ - if (arg_p->ar_short_arg == NULLC) + if (arg_p->ar_short_arg == '\0') { continue; + } - if (! mark) { + if (! mark_b) { len = 2 + SHORT_PREFIX_LENGTH; prefix = " ["; @@ -340,7 +540,7 @@ (void)fprintf(argv_error_stream, "%s%s", prefix, SHORT_PREFIX); col_c += len; - mark = ARGV_TRUE; + mark_b = ARGV_TRUE; } len = 1; @@ -359,7 +559,7 @@ col_c++; } - if (mark) { + if (mark_b) { (void)fprintf(argv_error_stream, "]"); col_c++; } @@ -371,15 +571,18 @@ /* skip or-specifiers */ if (arg_p->ar_short_arg == ARGV_OR - || arg_p->ar_short_arg == ARGV_XOR) + || arg_p->ar_short_arg == ARGV_XOR) { continue; + } /* skip booleans types */ - if (! HAS_ARG(arg_p->ar_type)) + if (! HAS_ARG(arg_p->ar_type)) { continue; + } if (arg_p->ar_var_label == NULL) { - if (ARGV_TYPE(arg_p->ar_type) == ARGV_BOOL_ARG) { + if (ARGV_TYPE(arg_p->ar_type) == ARGV_BOOL_ARG + || ARGV_TYPE(arg_p->ar_type) == ARGV_BOOL_INT_ARG) { var_str = BOOL_ARG_LABEL; var_len = BOOL_ARG_LENGTH; } @@ -451,102 +654,162 @@ (void)fprintf(argv_error_stream, "\n"); - if (flag == GLOBAL_USAGE_SHORTREM) + if (flag == GLOBAL_USAGE_SHORTREM) { (void)fprintf(argv_error_stream, "%*.*sUse the '%s%s' argument for more assistance.\n", (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", LONG_PREFIX, USAGE_ARG); + } } /* - * Display an argument type while keeping track of COL_C. + * static void display_arg + * + * DESCRIPTION: + * + * Display an argument type while keeping track of the column we are + * in. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * stream - Output stream we are writing to. + * + * arg_p - Argument that we are displaying. + * + * max - Maximum column position to write to. + * + * col_cp - Pointer to an integer to record the column position. */ -LOCAL void display_arg(FILE *stream, const argv_t *arg_p, const int max, - int *col_c) +static void display_arg(FILE *stream, const argv_t *arg_p, const int max, + int *col_cp) { int var_len, len; - if (arg_p->ar_var_label == NULL) + if (arg_p->ar_var_label == NULL) { var_len = 0; - else + } + else { var_len = strlen(arg_p->ar_var_label); + } switch (ARGV_TYPE(arg_p->ar_type)) { case ARGV_BOOL: case ARGV_BOOL_NEG: case ARGV_INCR: + case ARGV_BOOL_INT: + case ARGV_BOOL_INT_NEG: break; case ARGV_BOOL_ARG: + case ARGV_BOOL_INT_ARG: (void)fprintf(stream, "%s", BOOL_ARG_LABEL); - (*col_c) += BOOL_ARG_LENGTH; + (*col_cp) += BOOL_ARG_LENGTH; break; case ARGV_CHAR: - case ARGV_CHARP: - case ARGV_FLOAT: + case ARGV_CHAR_P: case ARGV_SHORT: + case ARGV_U_SHORT: case ARGV_INT: case ARGV_U_INT: case ARGV_LONG: case ARGV_U_LONG: + case ARGV_FLOAT: + case ARGV_DOUBLE: case ARGV_BIN: case ARGV_OCT: case ARGV_HEX: + case ARGV_SIZE: + case ARGV_U_SIZE: if (arg_p->ar_var_label == NULL) { - len = max - *col_c; + len = max - *col_cp; (void)fprintf(stream, "%-.*s", len, UNKNOWN_ARG); - *col_c += MIN(len, UNKNOWN_ARG_LENGTH); + *col_cp += MIN(len, (int)UNKNOWN_ARG_LENGTH); } else { - len = max - *col_c; + len = max - *col_cp; (void)fprintf(stream, "%-.*s", len, arg_p->ar_var_label); - *col_c += MIN(len, var_len); + *col_cp += MIN(len, var_len); } break; } } /* - * Display an option entry ARG_P to STREAM while counting COL_C. + * static void display_option + * + * DESCRIPTION: + * + * Display an option entry while while keeping track of the column we + * are in. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * stream - Output stream we are writing to. + * + * arg_p - Argument that we are displaying. + * + * max - Maximum column position to write to. + * + * col_cp - Pointer to an integer to record the column position. */ -LOCAL void display_option(FILE *stream, const argv_t *arg_p, int *col_c) +static void display_option(FILE *stream, const argv_t *arg_p, int *col_cp) { - if (stream == NULL) + if (stream == NULL) { return; + } (void)fputc('[', stream); - (*col_c)++; + (*col_cp)++; /* arg maybe does not have a -? preface */ if (arg_p->ar_short_arg != ARGV_MAYBE) { (void)fprintf(stream, "%s%c", SHORT_PREFIX, arg_p->ar_short_arg); - *col_c += SHORT_PREFIX_LENGTH + 1; + *col_cp += SHORT_PREFIX_LENGTH + 1; if (HAS_ARG(arg_p->ar_type)) { /* display optional argument */ (void)fputc(' ', stream); - (*col_c)++; + (*col_cp)++; } } - display_arg(stream, arg_p, LONG_COLUMN - 1, col_c); + display_arg(stream, arg_p, LONG_COLUMN - 1, col_cp); (void)fputc(']', stream); - (*col_c)++; + (*col_cp)++; } /* + * static void usage_long + * + * DESCRIPTION: + * * Print a long-format usage message. + * + * RETURNS: + * + * None. + * + * ars - Array of argv_t structures whose usage we are printing. */ -LOCAL void usage_long(const argv_t *args) +static void usage_long(const argv_t *args) { const argv_t *arg_p; int col_c, len; - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return; + } /* print the usage message header */ (void)fprintf(argv_error_stream, "%s%s\n", USAGE_LABEL, argv_program); @@ -555,8 +818,9 @@ for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { /* skip or specifiers */ - if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) + if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) { continue; + } /* indent to the short-option col_c */ (void)fprintf(argv_error_stream, "%*.*s", SHORT_COLUMN, SHORT_COLUMN, ""); @@ -565,15 +829,21 @@ col_c = SHORT_COLUMN; /* print the short-arg stuff if there */ - if (arg_p->ar_short_arg == NULLC) { + if (arg_p->ar_short_arg == '\0') { (void)fputc('[', argv_error_stream); col_c++; } else { - if (arg_p->ar_short_arg == ARGV_MAND) + if (arg_p->ar_short_arg == '\0') { + ; + } + else if (arg_p->ar_short_arg == ARGV_MAND) { display_arg(argv_error_stream, arg_p, COMMENT_COLUMN, &col_c); - else + } + else { + /* ARGV_MAYBE handled here */ display_option(argv_error_stream, arg_p, &col_c); + } /* put the long-option message on the correct column */ if (col_c < LONG_COLUMN) { @@ -586,18 +856,18 @@ /* print the long-option message */ if (arg_p->ar_long_arg != NULL) { len = COMMENT_COLUMN - col_c - (LONG_PREFIX_LENGTH + 1); - if (arg_p->ar_short_arg != NULLC) { + if (arg_p->ar_short_arg != '\0') { (void)fprintf(argv_error_stream, "%s", LONG_LABEL); col_c += LONG_LABEL_LENGTH; len -= LONG_LABEL_LENGTH; } (void)fprintf(argv_error_stream, "%s%-.*s", LONG_PREFIX, len, arg_p->ar_long_arg); - col_c += LONG_PREFIX_LENGTH + MIN(len, strlen(arg_p->ar_long_arg)); + col_c += LONG_PREFIX_LENGTH + MIN(len, (int)strlen(arg_p->ar_long_arg)); } /* add the optional argument if no short-arg */ - if (arg_p->ar_short_arg == NULLC) { + if (arg_p->ar_short_arg == '\0') { if (HAS_ARG(arg_p->ar_type)) { (void)fputc(' ', argv_error_stream); col_c++; @@ -629,22 +899,41 @@ } /* - * Do the usage depending on FLAG. + * static void do_usage + * + * DESCRIPTION: + * + * Print the usage messages. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * args - Array of argv_t structures. + * + * flag - Users flags which will tell us whether to display short or + * long usage messages. */ -LOCAL void do_usage(const argv_t *args, const int flag) +static void do_usage(const argv_t *args, const int flag) { - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return; + } - if (flag == GLOBAL_USAGE_SEE) + if (flag == GLOBAL_USAGE_SEE) { (void)fprintf(argv_error_stream, "%*.*sUse the '%s%s' argument for assistance.\n", (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", LONG_PREFIX, USAGE_ARG); - else if (flag == GLOBAL_USAGE_SHORT || flag == GLOBAL_USAGE_SHORTREM) + } + else if (flag == GLOBAL_USAGE_SHORT || flag == GLOBAL_USAGE_SHORTREM) { usage_short(args, flag); - else if (flag == GLOBAL_USAGE_LONG || flag == GLOBAL_USAGE_ALL) + } + else if (flag == GLOBAL_USAGE_LONG || flag == GLOBAL_USAGE_ALL) { usage_long(args); + } if (flag == GLOBAL_USAGE_ALL) { (void)fprintf(argv_error_stream, "\n"); @@ -682,122 +971,128 @@ /******************************* preprocessing *******************************/ /* - * Preprocess argument array ARGS of NUM_ARGS entries and set the MAND - * and MAYBE boolean arrays. Returns [NO]ERROR. + * static int preprocess_array + * + * DESCRIPTION: + * + * Preprocess argument array entries and set the mandatory and maybe + * flags. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures. + * + * arg_n - Number of entries in the argv_t array. We need this for a + * couple of reasons. */ -LOCAL int preprocess_array(argv_t *args, const int num_args) +static int preprocess_array(argv_t *args, const int arg_n) { argv_t *arg_p; - char mand_array = ARGV_FALSE, maybe_field = ARGV_FALSE; + int mand_array_b = ARGV_FALSE, maybe_field_b = ARGV_FALSE; /* count the args and find the first mandatory */ - for (arg_p = args; arg_p < args + num_args; arg_p++) { + for (arg_p = args; arg_p < args + arg_n; arg_p++) { /* clear internal flags */ arg_p->ar_type &= ~ARGV_FLAG_USED; /* do we have a mandatory-array? */ if (arg_p->ar_short_arg == ARGV_MAND) { - if (mand_array) { - if (argv_error_stream != NULL) + if (mand_array_b) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, no ARGV_MAND's can follow a MAND or MAYBE array\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } - if (maybe_field) { - if (argv_error_stream != NULL) + if (maybe_field_b) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, no ARGV_MAND's can follow a ARGV_MAYBE\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } -#if 0 - if (arg_p->ar_long_arg != NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: %s, ARGV_MAND's should not have long-options\n", - argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { + mand_array_b = ARGV_TRUE; } -#endif - - if (arg_p->ar_type & ARGV_ARRAY) - mand_array = ARGV_TRUE; } /* do we have a maybe field? */ if (arg_p->ar_short_arg == ARGV_MAYBE) { - if (mand_array) { - if (argv_error_stream != NULL) + if (mand_array_b) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, no ARGV_MAYBE's can follow a MAND or MAYBE array\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } - maybe_field = ARGV_TRUE; - if (arg_p->ar_type & ARGV_ARRAY) - mand_array = ARGV_TRUE; + maybe_field_b = ARGV_TRUE; + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { + mand_array_b = ARGV_TRUE; + } } /* handle initializing the argument array */ - if (arg_p->ar_type & ARGV_ARRAY) { + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { argv_array_t *arrp = (argv_array_t *)arg_p->ar_variable; if (! HAS_ARG(arg_p->ar_type)) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, cannot have an array of boolean values\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } if (ARGV_TYPE(arg_p->ar_type) == ARGV_INCR) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, cannot have an array of incremental values\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } - arrp->aa_entryn = 0; - } - -#if 0 - /* must have a valid ar_short_arg */ - if (arg_p->ar_short_arg == NULLC) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: %s, short-option character is '\\0'\n", - argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; + arrp->aa_entry_n = 0; } -#endif /* verify variable pointer */ if (arg_p->ar_variable == NULL && arg_p->ar_short_arg != ARGV_OR && arg_p->ar_short_arg != ARGV_XOR) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, NULL variable specified in arg array\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } @@ -806,25 +1101,29 @@ || arg_p->ar_short_arg == ARGV_XOR) { /* that they are not at the start or end of list */ - if (arg_p == args || arg_p >= (args + num_args - 1)) { - if (argv_error_stream != NULL) + if (arg_p == args || arg_p >= (args + arg_n - 1)) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, ARGV_[X]OR entries cannot be at start or end of array\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } /* that two aren't next to each other */ if ((arg_p - 1)->ar_short_arg == ARGV_OR || (arg_p - 1)->ar_short_arg == ARGV_XOR) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, two ARGV_[X]OR entries cannot be next to each other\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } } @@ -834,52 +1133,76 @@ } /* - * Translate string argument ARG into VAR depending on its TYPE. - * Returns [NO]ERROR. + * static int string_to_value + * + * DESCRIPTION: + * + * Translate string value argument into a variable value depending on + * its type. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * arg - Argument string. + * + * var - Pointer to our variable. + * + * type - Type of the variable. */ -LOCAL int translate_value(const char *arg, ARGV_PNT var, - const short type) +static int string_to_value(const char *arg, ARGV_PNT var, + const unsigned int type) { argv_array_t *arr_p; argv_type_t *type_p; - int val_type = ARGV_TYPE(type), size = 0; + unsigned int val_type = ARGV_TYPE(type), size = 0; /* find the type and the size for array */ - for (type_p = argv_types; type_p->at_value != 0; type_p++) + for (type_p = argv_types; type_p->at_value != 0; type_p++) { if (type_p->at_value == val_type) { size = type_p->at_size; break; } + } if (type_p->at_value == 0) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal variable type %d\n", __FILE__, val_type); + } return ERROR; } - if (type & ARGV_ARRAY) { + if (type & ARGV_FLAG_ARRAY) { arr_p = (argv_array_t *)var; - if (arr_p->aa_entryn == 0) + if (arr_p->aa_entry_n == 0) { arr_p->aa_entries = (char *)malloc(ARRAY_INCR *size); - else if (arr_p->aa_entryn % ARRAY_INCR == 0) + } + else if (arr_p->aa_entry_n % ARRAY_INCR == 0) { arr_p->aa_entries = - (char *)realloc(arr_p->aa_entries, (arr_p->aa_entryn + ARRAY_INCR) * + (char *)realloc(arr_p->aa_entries, (arr_p->aa_entry_n + ARRAY_INCR) * size); + } if (arr_p->aa_entries == NULL) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } - var = (char *)(arr_p->aa_entries) + arr_p->aa_entryn * size; - arr_p->aa_entryn++; + var = (char *)(arr_p->aa_entries) + arr_p->aa_entry_n * size; + arr_p->aa_entry_n++; } /* translate depending on type */ @@ -887,34 +1210,64 @@ case ARGV_BOOL: /* if no close argument, set to true */ - if (arg == NULL) + if (arg == NULL) { *(char *)var = ARGV_TRUE; + } + else if (*(char *)arg == 't' || *(char *)arg == 'T' + || *(char *)arg == 'y' || *(char *)arg == 'Y' + || *(char *)arg == '1') { + *(char *)var = ARGV_TRUE; + } + else { + *(char *)var = ARGV_FALSE; + } + break; + + case ARGV_BOOL_NEG: + /* if no close argument, set to false */ + if (arg == NULL) { + *(char *)var = ARGV_FALSE; + } else if (*(char *)arg == 't' || *(char *)arg == 'T' || *(char *)arg == 'y' || *(char *)arg == 'Y' - || *(char *)arg == '1') + || *(char *)arg == '1') { *(char *)var = ARGV_TRUE; - else + } + else { + *(char *)var = ARGV_FALSE; + } + break; + + case ARGV_BOOL_ARG: + if (*(char *)arg == 't' || *(char *)arg == 'T' + || *(char *)arg == 'y' || *(char *)arg == 'Y' + || *(char *)arg == '1') { + *(char *)var = ARGV_TRUE; + } + else { *(char *)var = ARGV_FALSE; + } break; case ARGV_CHAR: *(char *)var = *(char *)arg; break; - case ARGV_CHARP: + case ARGV_CHAR_P: *(char **)var = string_copy((char *)arg); - if (*(char **)var == NULL) + if (*(char **)var == NULL) { return ERROR; - break; - - case ARGV_FLOAT: - *(float *)var = (float)atof(arg); + } break; case ARGV_SHORT: *(short *)var = (short)atoi(arg); break; + case ARGV_U_SHORT: + *(unsigned short *)var = (unsigned short)atoi(arg); + break; + case ARGV_INT: *(int *)var = atoi(arg); break; @@ -931,6 +1284,14 @@ *(unsigned long *)var = atol(arg); break; + case ARGV_FLOAT: + (void)sscanf(arg, "%f", (float *)var); + break; + + case ARGV_DOUBLE: + (void)sscanf(arg, "%lf", (double *)var); + break; + case ARGV_BIN: *(int *)var = btoi(arg); break; @@ -943,158 +1304,423 @@ *(int *)var = htoi(arg); break; - case ARGV_BOOL_NEG: - /* if no close argument, set to false */ - if (arg == NULL) - *(char *)var = ARGV_FALSE; - else if (*(char *)arg == 't' || *(char *)arg == 'T' - || *(char *)arg == 'y' || *(char *)arg == 'Y' - || *(char *)arg == '1') - *(char *)var = ARGV_TRUE; - else - *(char *)var = ARGV_FALSE; - break; - case ARGV_INCR: /* if no close argument then increment else set the value */ - if (arg == NULL) + if (arg == NULL) { (*(int *)var)++; - else + } + else { *(int *)var = atoi(arg); + } break; - case ARGV_BOOL_ARG: + case ARGV_SIZE: + { + const char *arg_p; + long val; + + /* take initial integer point */ + val = atol(arg); + for (arg_p = arg; + *arg_p == ' ' || *arg_p == '-' || *arg_p == '+' + || (*arg_p >= '0' && *arg_p <= '9'); + arg_p++) { + } + if (*arg_p == 'b' || *arg_p == 'B') { + val *= 1; + } + else if (*arg_p == 'k' || *arg_p == 'B') { + val *= 1024; + } + else if (*arg_p == 'm' || *arg_p == 'M') { + val *= 1024 * 1024; + } + else if (*arg_p == 'g' || *arg_p == 'G') { + val *= 1024 * 1024 * 1024; + } + *(long *)var = val; + } + break; + + case ARGV_U_SIZE: + { + const char *arg_p; + unsigned long val; + + /* take initial integer point */ + val = (unsigned long)atol(arg); + for (arg_p = arg; + *arg_p == ' ' || *arg_p == '-' || *arg_p == '+' + || (*arg_p >= '0' && *arg_p <= '9'); + arg_p++) { + } + if (*arg_p == 'b' || *arg_p == 'B') { + val *= 1; + } + else if (*arg_p == 'k' || *arg_p == 'B') { + val *= 1024; + } + else if (*arg_p == 'm' || *arg_p == 'M') { + val *= 1024 * 1024; + } + else if (*arg_p == 'g' || *arg_p == 'G') { + val *= 1024 * 1024 * 1024; + } + *(unsigned long *)var = val; + } + break; + + case ARGV_BOOL_INT: + /* if no close argument, set to true */ + if (arg == NULL) { + *(int *)var = ARGV_TRUE; + } + else if (*(char *)arg == 't' || *(char *)arg == 'T' + || *(char *)arg == 'y' || *(char *)arg == 'Y' + || *(char *)arg == '1') { + *(int *)var = ARGV_TRUE; + } + else { + *(int *)var = ARGV_FALSE; + } + break; + + case ARGV_BOOL_INT_NEG: + /* if no close argument, set to false */ + if (arg == NULL) { + *(int *)var = ARGV_FALSE; + } + else if (*(char *)arg == 't' || *(char *)arg == 'T' + || *(char *)arg == 'y' || *(char *)arg == 'Y' + || *(char *)arg == '1') { + *(int *)var = ARGV_TRUE; + } + else { + *(int *)var = ARGV_FALSE; + } + break; + + case ARGV_BOOL_INT_ARG: if (*(char *)arg == 't' || *(char *)arg == 'T' || *(char *)arg == 'y' || *(char *)arg == 'Y' - || *(char *)arg == '1') - *(char *)var = ARGV_TRUE; - else - *(char *)var = ARGV_FALSE; + || *(char *)arg == '1') { + *(int *)var = ARGV_TRUE; + } + else { + *(int *)var = ARGV_FALSE; + } break; + } return NOERROR; } /* - * Translate value from VAR into string STR depending on its TYPE. + * static int value_to_string + * + * DESCRIPTION: + * + * Translate value from variable depending on its type intoits string + * represetnation in buffer. + * + * RETURNS: + * + * Number of characters added to the buffer. + * + * ARGUMENTS: + * + * var - Variable pointer. + * + * type - Type of variable. + * + * buf - User buffer to convert into. + * + * buf_size - Size of the user buffer. */ -LOCAL void display_value(const ARGV_PNT var, const short type) +static int value_to_string(const ARGV_PNT var, const unsigned int type, + char *buf, const int buf_size) { - int val_type = ARGV_TYPE(type); + int len = 0; + + /* + * NOTE: without a snprintf, we have to hope that buf_size > integer + * and the string repesentations of the numbers. + */ /* translate depending on type */ - switch (val_type) { + switch (ARGV_TYPE(type)) { case ARGV_BOOL: case ARGV_BOOL_NEG: case ARGV_BOOL_ARG: - if (*(char *)var) - (void)fprintf(argv_error_stream, "ARGV_TRUE"); - else - (void)fprintf(argv_error_stream, "ARGV_FALSE"); + if (*(char *)var) { + strncpy(buf, "true (! 0)", buf_size); + } + else { + strncpy(buf, "false (0)", buf_size); + } + buf[buf_size - 1] = '\0'; + len = strlen(buf); break; case ARGV_CHAR: - (void)fprintf(argv_error_stream, "'%s'", expand_buf((char *)var, 1)); + len = expand_buf((char *)var, 1, buf, buf_size); break; - case ARGV_CHARP: - { - int len; - if (*(char **)var == NULL) - (void)fprintf(argv_error_stream, "(null)"); - else { - len = strlen(*(char **)var); - (void)fprintf(argv_error_stream, "\"%s\"", - expand_buf(*(char **)var, len)); - } + case ARGV_CHAR_P: + if (*(char **)var == NULL) { + strncpy(buf, "(null)", buf_size); + buf[buf_size - 1] = '\0'; + len = strlen(buf); + } + else { + len = expand_buf(*(char **)var, -1, buf, buf_size); } break; - case ARGV_FLOAT: - (void)fprintf(argv_error_stream, "%f", *(float *)var); + case ARGV_SHORT: + (void)sprintf(buf, "%d", *(short *)var); + len = strlen(buf); break; - case ARGV_SHORT: - (void)fprintf(argv_error_stream, "%d", *(short *)var); + case ARGV_U_SHORT: + (void)sprintf(buf, "%d", *(unsigned short *)var); + len = strlen(buf); break; case ARGV_INT: - case ARGV_INCR: - (void)fprintf(argv_error_stream, "%d", *(int *)var); + (void)sprintf(buf, "%d", *(int *)var); + len = strlen(buf); break; case ARGV_U_INT: - (void)fprintf(argv_error_stream, "%u", *(unsigned int *)var); + (void)sprintf(buf, "%u", *(unsigned int *)var); + len = strlen(buf); break; case ARGV_LONG: - (void)fprintf(argv_error_stream, "%ld", *(long *)var); + (void)sprintf(buf, "%ld", *(long *)var); + len = strlen(buf); break; case ARGV_U_LONG: - (void)fprintf(argv_error_stream, "%lu", *(unsigned long *)var); + (void)sprintf(buf, "%lu", *(unsigned long *)var); + len = strlen(buf); + break; + + case ARGV_FLOAT: + (void)sprintf(buf, "%f", *(float *)var); + len = strlen(buf); + break; + + case ARGV_DOUBLE: + (void)sprintf(buf, "%f", *(double *)var); + len = strlen(buf); break; /* this should be a routine */ case ARGV_BIN: { - int bit_c; - char first = ARGV_FALSE; + int bit_c, bit, first_b = ARGV_FALSE; + char binary[2 + 128 + 1], *bin_p = binary; - (void)fputc('0', argv_error_stream); + if (*(int *)var == 0) { + strncpy(buf, "0", buf_size); + } + else { - if (*(int *)var != 0) { - (void)fputc('b', argv_error_stream); + /* initially write binary number into tmp buffer, then copy into out */ + *bin_p++ = '0'; + *bin_p++ = 'b'; for (bit_c = sizeof(int) * BITS_IN_BYTE - 1; bit_c >= 0; bit_c--) { - int bit = *(int *)var & (1 << bit_c); + bit = *(int *)var & (1 << bit_c); if (bit == 0) { - if (first) - (void)fputc('0', argv_error_stream); + if (first_b) { + *bin_p++ = '0'; + } } else { - (void)fputc('1', argv_error_stream); - first = ARGV_TRUE; + *bin_p++ = '1'; + first_b = ARGV_TRUE; } } + + /* add on the decimal equivalent */ + (void)sprintf(bin_p, " (%d)", *(int *)var); + /* find the \0 at end */ + for (; *bin_p != '\0'; bin_p++) { + } + + /* now we copy from the binary buffer to the output */ + strncpy(buf, binary, buf_size); } + + buf[buf_size - 1] = '\0'; + len = strlen(buf); } break; case ARGV_OCT: - (void)fprintf(argv_error_stream, "%#o", *(int *)var); + if (*(int *)var == 0) { + (void)strncpy(buf, "0", buf_size); + buf[buf_size - 1] = '\0'; + } + else { + (void)sprintf(buf, "%#o (%d)", *(int *)var, *(int *)var); + } + len = strlen(buf); break; case ARGV_HEX: - (void)fprintf(argv_error_stream, "%#x", *(int *)var); + if (*(int *)var == 0) { + (void)strcpy(buf, "0"); + } + else { + (void)sprintf(buf, "%#x (%d)", *(int *)var, *(int *)var); + } + len = strlen(buf); + break; + + case ARGV_INCR: + (void)sprintf(buf, "%d", *(int *)var); + len = strlen(buf); + break; + + case ARGV_SIZE: + { + long morf, val = *(long *)var; + + if (val == 0) { + (void)strcpy(buf, "0"); + } + else if (val % (1024 * 1024 * 1024) == 0) { + morf = val / (1024 * 1024 * 1024); + (void)sprintf(buf, "%ldg (%ld)", morf, val); + } + else if (val % (1024 * 1024) == 0) { + morf = val / (1024 * 1024); + (void)sprintf(buf, "%ldm (%ld)", morf, val); + } + else if (val % 1024 == 0) { + morf = val / 1024; + (void)sprintf(buf, "%ldk (%ld)", morf, val); + } + else { + (void)sprintf(buf, "%ld", val); + } + + len = strlen(buf); + } + break; + + case ARGV_U_SIZE: + { + unsigned long morf, val = *(unsigned long *)var; + + if (val == 0) { + (void)strcpy(buf, "0"); + } + else if (val % (1024 * 1024 * 1024) == 0) { + morf = val / (1024 * 1024 * 1024); + (void)sprintf(buf, "%ldg (%ld)", morf, val); + } + else if (val % (1024 * 1024) == 0) { + morf = val / (1024 * 1024); + (void)sprintf(buf, "%ldm (%ld)", morf, val); + } + else if (val % 1024 == 0) { + morf = val / 1024; + (void)sprintf(buf, "%ldk (%ld)", morf, val); + } + else { + (void)sprintf(buf, "%ld", val); + } + + len = strlen(buf); + } + break; + + case ARGV_BOOL_INT: + case ARGV_BOOL_INT_NEG: + case ARGV_BOOL_INT_ARG: + if (*(int *)var) { + strncpy(buf, "true (! 0)", buf_size); + } + else { + strncpy(buf, "false (0)", buf_size); + } + buf[buf_size - 1] = '\0'; + len = strlen(buf); + break; + + default: + strncpy(buf, "(unknown)", buf_size); + buf[buf_size - 1] = '\0'; + len = strlen(buf); break; } + + return len; } /* - * Translate value from VAR into string STR depending on its TYPE. + * static void display_variables + * + * DESCRIPTION: + * + * Display all of the variable values from our array. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * args - Array of argv_t structures whose variables we are + * displaying. */ -LOCAL void display_variables(const argv_t *args) +static void display_variables(const argv_t *args) { const argv_t *arg_p; argv_type_t *type_p; + char buf[256]; + int len, col_c, val_type; /* run through the argument structure */ for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { - int col_c, val_type = ARGV_TYPE(arg_p->ar_type); + + val_type = ARGV_TYPE(arg_p->ar_type); /* skip or specifiers */ - if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) + if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) { continue; + } col_c = 0; - if (arg_p->ar_short_arg == ARGV_MAND) + if (arg_p->ar_short_arg == '\0') { + if (arg_p->ar_long_arg != NULL) { + len = COMMENT_COLUMN - col_c - (LONG_PREFIX_LENGTH + 1); + if (arg_p->ar_short_arg != '\0') { + (void)fprintf(argv_error_stream, "%s", LONG_LABEL); + col_c += LONG_LABEL_LENGTH; + len -= LONG_LABEL_LENGTH; + } + (void)fprintf(argv_error_stream, "%s%-.*s", + LONG_PREFIX, len, arg_p->ar_long_arg); + col_c += LONG_PREFIX_LENGTH + MIN(len, + (int)strlen(arg_p->ar_long_arg)); + } + } + else if (arg_p->ar_short_arg == ARGV_MAND) { display_arg(argv_error_stream, arg_p, COMMENT_COLUMN, &col_c); - else + } + else { + /* ARGV_MAYBE handled here */ display_option(argv_error_stream, arg_p, &col_c); + } /* put the type in the correct column */ if (col_c < LONG_COLUMN) { @@ -1107,13 +1733,13 @@ type_p = NULL; for (type_p = argv_types; type_p->at_value != 0; type_p++) { if (type_p->at_value == ARGV_TYPE(arg_p->ar_type)) { - int len, tlen; + int tlen; len = COMMENT_COLUMN - col_c - 1; tlen = strlen(type_p->at_name); (void)fprintf(argv_error_stream, " %-.*s", len, type_p->at_name); col_c += MIN(len, tlen); - if (arg_p->ar_type & ARGV_ARRAY) { + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { (void)fprintf(argv_error_stream, "%s", ARRAY_LABEL); col_c += sizeof(ARRAY_LABEL) - 1; } @@ -1127,7 +1753,7 @@ col_c = COMMENT_COLUMN; } - if (arg_p->ar_type & ARGV_ARRAY) { + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { argv_array_t *arr_p; int entry_c, size = 0; @@ -1140,20 +1766,25 @@ size = type_p->at_size; arr_p = (argv_array_t *)arg_p->ar_variable; - if (arr_p->aa_entryn == 0) + if (arr_p->aa_entry_n == 0) { (void)fprintf(argv_error_stream, "no entries"); + } else { - for (entry_c = 0; entry_c < arr_p->aa_entryn; entry_c++) { + for (entry_c = 0; entry_c < arr_p->aa_entry_n; entry_c++) { ARGV_PNT var; - if (entry_c > 0) + if (entry_c > 0) { (void)fputc(',', argv_error_stream); + } var = (char *)(arr_p->aa_entries) + entry_c * size; - display_value(var, val_type); + len = value_to_string(var, val_type, buf, sizeof(buf)); + (void)fwrite(buf, sizeof(char), len, argv_error_stream); } } } - else - display_value(arg_p->ar_variable, val_type); + else { + len = value_to_string(arg_p->ar_variable, val_type, buf, sizeof(buf)); + (void)fwrite(buf, sizeof(char), len, argv_error_stream); + } (void)fputc('\n', argv_error_stream); } } @@ -1161,18 +1792,36 @@ /************************** checking used arguments **************************/ /* - * Check out if WHICH argument from ARGS has an *or* specified - * attached to it. Returns [NO]ERROR + * static int check_or + * + * DESCRIPTION: + * + * Check out if an argument has an ARGV_OR attached to it and both + * variables have not been set. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures that we are checking. + * + * which_p - Pointer to the specific argument that we are checking for + * the ARGV_OR. */ -LOCAL int check_or(const argv_t *args, const argv_t *which) +static int check_or(const argv_t *args, const argv_t *which_p) { const argv_t *arg_p, *match_p = NULL; /* check ORs below */ - for (arg_p = which - 2; arg_p >= args; arg_p -= 2) { + for (arg_p = which_p - 2; arg_p >= args; arg_p -= 2) { if ((arg_p + 1)->ar_short_arg != ARGV_OR - && (arg_p + 1)->ar_short_arg != ARGV_XOR) + && (arg_p + 1)->ar_short_arg != ARGV_XOR) { break; + } if (arg_p->ar_type & ARGV_FLAG_USED) { match_p = arg_p; break; @@ -1181,14 +1830,15 @@ /* check ORs above */ if (match_p == NULL) { - /* NOTE: we assume that which is not pointing now to ARGV_LAST */ - for (arg_p = which + 2; + /* NOTE: we assume that which_p is not pointing now to ARGV_LAST */ + for (arg_p = which_p + 2; arg_p->ar_short_arg != ARGV_LAST && (arg_p - 1)->ar_short_arg != ARGV_LAST; arg_p += 2) { if ((arg_p - 1)->ar_short_arg != ARGV_OR - && (arg_p - 1)->ar_short_arg != ARGV_XOR) + && (arg_p - 1)->ar_short_arg != ARGV_XOR) { break; + } if (arg_p->ar_type & ARGV_FLAG_USED) { match_p = arg_p; break; @@ -1197,11 +1847,13 @@ } /* did we not find a problem? */ - if (match_p == NULL) + if (match_p == NULL) { return NOERROR; + } - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return ERROR; + } (void)fprintf(argv_error_stream, "%s: %s, specify only one of the following:\n", @@ -1209,27 +1861,49 @@ /* little hack to print the one that matched and the one we were checking */ for (;;) { - if (match_p->ar_long_arg == NULL) - (void)fprintf(argv_error_stream, " %s%c\n", + if (match_p->ar_long_arg == NULL) { + (void)fprintf(argv_error_stream, "%*.*s%s%c\n", + (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", SHORT_PREFIX, match_p->ar_short_arg); - else - (void)fprintf(argv_error_stream, " %s%c (%s%s)\n", + } + else { + (void)fprintf(argv_error_stream, "%*.*s%s%c (%s%s)\n", + (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", SHORT_PREFIX, match_p->ar_short_arg, LONG_PREFIX, match_p->ar_long_arg); + } - if (match_p == which) + if (match_p == which_p) { break; - match_p = which; + } + match_p = which_p; } return ERROR; } /* - * Find all the XOR arguments and make sure each group has at least - * one specified in it. Returns [NO]ERROR. + * static int check_xor + * + * DESCRIPTION: + * + * Check out if an argument has an ARGV_XOR attached to it and that at + * least one but not both variables have been set. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures that we are checking. + * + * which_p - Pointer to the specific argument that we are checking for + * the ARGV_XOR. */ -LOCAL int check_xor(const argv_t *args) +static int check_xor(const argv_t *args) { const argv_t *start_p = NULL, *arg_p; @@ -1237,8 +1911,9 @@ for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { /* only check the XORs */ - if (arg_p->ar_short_arg != ARGV_XOR) + if (arg_p->ar_short_arg != ARGV_XOR) { continue; + } start_p = arg_p; @@ -1246,31 +1921,37 @@ * NOTE: we are guaranteed that we are on a XOR so there is * something below and above... */ - if ((arg_p - 1)->ar_type & ARGV_FLAG_USED) + if ((arg_p - 1)->ar_type & ARGV_FLAG_USED) { start_p = NULL; + } /* run through all XORs */ for (;;) { arg_p++; - if (arg_p->ar_type & ARGV_FLAG_USED) + if (arg_p->ar_type & ARGV_FLAG_USED) { start_p = NULL; - if ((arg_p + 1)->ar_short_arg != ARGV_XOR) + } + if ((arg_p + 1)->ar_short_arg != ARGV_XOR) { break; + } arg_p++; } /* were none of the xor's filled? */ - if (start_p != NULL) + if (start_p != NULL) { break; + } } /* did we not find a problem? */ - if (start_p == NULL) + if (start_p == NULL) { return NOERROR; + } /* arg_p points to the first XOR which failed */ - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return ERROR; + } (void)fprintf(argv_error_stream, "%s: %s, must specify one of:\n", argv_program, USAGE_ERROR_NAME); @@ -1280,61 +1961,119 @@ * NOTE: we are guaranteed that we are on a XOR so there is * something below and above... */ - (void)fprintf(argv_error_stream, " %s%c", + (void)fprintf(argv_error_stream, "%*.*s%s%c", + (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", SHORT_PREFIX, (arg_p - 1)->ar_short_arg); - if ((arg_p - 1)->ar_long_arg != NULL) + if ((arg_p - 1)->ar_long_arg != NULL) { (void)fprintf(argv_error_stream, " (%s%s)", LONG_PREFIX, (arg_p - 1)->ar_long_arg); + } (void)fprintf(argv_error_stream, "\n"); - if (arg_p->ar_short_arg != ARGV_XOR) + if (arg_p->ar_short_arg != ARGV_XOR) { break; + } } return ERROR; } /* - * Check to see if any mandatory arguments left. Returns [NO]ERROR. + * static int check_mand + * + * DESCRIPTION: + * + * Verify that all of the mandatory arguments in our array have been + * specified. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures that we are checking. */ -LOCAL int check_mand(const argv_t *args) +static int check_mand(const argv_t *args) { const argv_t *arg_p; - int slot_c = 0; + int mand_c = 0, flag_c = 0; /* see if there are any mandatory args left */ - for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) + for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { if (arg_p->ar_short_arg == ARGV_MAND - && (! (arg_p->ar_type & ARGV_FLAG_USED)) - && ! (arg_p->ar_type & ARGV_ARRAY)) - slot_c++; + && (! (arg_p->ar_type & ARGV_FLAG_USED))) { + mand_c++; + } + if (arg_p->ar_type & ARGV_FLAG_MAND + && (! (arg_p->ar_type & ARGV_FLAG_USED))) { + flag_c++; + if (argv_error_stream != NULL) { + if (flag_c == 1) { + (void)fprintf(argv_error_stream, + "%s: %s, these mandatory flags must be specified:\n", + argv_program, USAGE_ERROR_NAME); + } + (void)fprintf(argv_error_stream, "%*.*s%s%c", + (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", + SHORT_PREFIX, arg_p->ar_short_arg); + if (arg_p->ar_long_arg != NULL) { + (void)fprintf(argv_error_stream, " (%s%s)", + LONG_PREFIX, arg_p->ar_long_arg); + } + (void)fprintf(argv_error_stream, "\n"); + } + } + } - if (slot_c > 0) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: %s, %d more mandatory argument%s must be specified\n", - argv_program, USAGE_ERROR_NAME, - slot_c, (slot_c == 1 ? "" : "s")); - return ERROR; + if (mand_c > 0 && argv_error_stream != NULL) { + (void)fprintf(argv_error_stream, + "%s: %s, %d more mandatory argument%s must be specified\n", + argv_program, USAGE_ERROR_NAME, + mand_c, (mand_c == 1 ? "" : "s")); } - return NOERROR; + if (mand_c > 0 || flag_c > 0) { + return ERROR; + } + else { + return NOERROR; + } } /* - * Check for any missing argument options. Returns [NO]ERROR + * static int check_opt + * + * DESCRIPTION: + * + * Check for any missing argument options. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * queue_head - Head of the option queue. + * + * queue_tail - Tail of the option queue. */ -LOCAL int check_opt(void) +static int check_opt(const int queue_head, const int queue_tail) { int queue_c; - queue_c = QUEUE_COUNT(); + queue_c = queue_head - queue_tail; if (queue_c > 0) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, %d more option-argument%s must be specified\n", argv_program, USAGE_ERROR_NAME, queue_c, (queue_c == 1 ? "" : "s")); + } return ERROR; } @@ -1344,42 +2083,75 @@ /**************************** argument processing ****************************/ /* - * Read in arguments from PATH and run them from the GRID. OKAY_P is - * a pointer to the boolean error marker. Returns [NO]ERROR. + * static void file_args + * + * DESCRIPTION: + * + * Read in arguments from a file and process them like they were + * specified on the command line. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * path -> File of the arguments we are reading in. + * + * grid -> Array of argv_t structures we are using. + * + * queue_list <-> Our option queue for storing options to arguments. + * + * queue_head_p <-> Pointer to integer which will be updated with the + * head position in our option queue. + * + * queue_tail_p <-> Pointer to integer which will be updated with the + * tail position in our option queue. + * + * okay_bp <- Pointer to an integer which is set with 0 if the + * arguments specified in the env variable are somehow invalid. */ -LOCAL void file_args(const char *path, argv_t *grid, char *okay_p) +static void file_args(const char *path, argv_t *grid, + argv_t **queue_list, int *queue_head_p, + int *queue_tail_p, int *okay_bp) { char **argv, **argv_p; - int argc, max; + int arg_c, max; FILE *infile; char line[FILE_LINE_SIZE + 1], *line_p; /* open the input file */ infile = fopen(path, "r"); if (infile == NULL) { - *okay_p = ARGV_FALSE; - if (argv_error_stream != NULL) + *okay_bp = ARGV_FALSE; + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: could not load command-line arguments from: %s\n", argv_program, path); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return; } /* get an array of char * */ - argc = 0; + arg_c = 0; max = ARRAY_INCR; argv = malloc(sizeof(char *) * max); if (argv == NULL) { - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; (void)fclose(infile); - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return; } argv_p = argv; @@ -1387,52 +2159,82 @@ /* read in the file lines */ while (fgets(line, FILE_LINE_SIZE, infile) != NULL) { /* punch the \n at end of line */ - for (line_p = line; *line_p != '\n' && *line_p != '\0'; line_p++); + for (line_p = line; *line_p != '\n' && *line_p != '\0'; line_p++) { + } *line_p = '\0'; *argv_p = string_copy(line); if (*argv_p == NULL) { - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; return; } argv_p++; - argc++; - if (argc == max) { + arg_c++; + if (arg_c == max) { max += ARRAY_INCR; argv = realloc(argv, sizeof(char *) * max); if (argv == NULL) { - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; (void)fclose(infile); - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return; } - argv_p = argv + argc; + argv_p = argv + arg_c; } } /* now do the list */ - do_list(grid, argc, argv, okay_p); + do_list(grid, arg_c, argv, queue_list, queue_head_p, queue_tail_p, okay_bp); /* now free up the list */ - for (argv_p = argv; argv_p < argv + argc; argv_p++) + for (argv_p = argv; argv_p < argv + arg_c; argv_p++) { free(*argv_p); + } free(argv); (void)fclose(infile); } /* - * Process an argument in MATCH_P which looking at GRID. sets okay_p to - * FALSE if the argument was not okay. + * static void do_arg + * + * DESCRIPTION: + * + * Process an argument in MATCH_P which looking at GRID. sets okay_p + * to FALSE if the argument was not okay. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * grid -> Our array of argv_t structures. + * + * match_p -> Entry in our argv_t structure array that matches the + * specified argument. + * + * close_p -> Pointer to the value closely associated (with an '=') + * with this option or NULL if none. + * + * queue_list <-> Our option queue for storing options to arguments. + * + * queue_head_p <-> Pointer to integer which will be updated with the + * head position in our option queue. + * + * okay_bp <- Pointer to an integer which is set with 0 if the + * arguments specified in the env variable are somehow invalid. */ -LOCAL void do_arg(argv_t *grid, argv_t *match_p, const char *close_p, - char *okay_p) +static void do_arg(argv_t *grid, argv_t *match_p, const char *close_p, + argv_t **queue_list, int *queue_head_p, int *okay_bp) { if (global_multi == GLOBAL_MULTI_REJECT) { /* @@ -1440,14 +2242,15 @@ * NOTE: should this be a warning or a non-error altogether? */ if (match_p->ar_type & ARGV_FLAG_USED - && (! (match_p->ar_type & ARGV_ARRAY)) + && (! (match_p->ar_type & ARGV_FLAG_ARRAY)) && ARGV_TYPE(match_p->ar_type) != ARGV_INCR) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, you've already specified the '%c' argument\n", argv_program, USAGE_ERROR_NAME, match_p->ar_short_arg); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; } } @@ -1460,7 +2263,7 @@ * don't return here else we might generate an XOR error * because the argument wasn't specified */ - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; } /* @@ -1469,69 +2272,157 @@ * else queue it for needing a value argument. */ if (global_close == GLOBAL_CLOSE_ENABLE && close_p != NULL) { - if (translate_value(close_p, match_p->ar_variable, - match_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; + if (string_to_value(close_p, match_p->ar_variable, + match_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } } else if (! HAS_ARG(match_p->ar_type)) { - if (translate_value(NULL, match_p->ar_variable, - match_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; + if (string_to_value(NULL, match_p->ar_variable, + match_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } } else if (global_close == GLOBAL_CLOSE_ENABLE && close_p != NULL) { - if (translate_value(close_p, match_p->ar_variable, - match_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; + if (string_to_value(close_p, match_p->ar_variable, + match_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } + } + else { + queue_list[*queue_head_p] = match_p; + (*queue_head_p)++; + } +} + +/* + * static int is_number + * + * DESCRIPTION: + * + * Examine an argument string to see if it really is a negative number + * being passed into a previously specified argument. + * + * Thanks much to Nick Kisseberth for + * pointing out this oversight. + * + * RETURNS: + * + * 1 if a number otherwise 0. + * + * ARGUMENTS: + * + * str - String which may be a number. + */ +static int is_number(const char *str) +{ + const char *str_p; + + /* empty strings are not numbers */ + if (str[0] == '\0') { + return 0; } - else - QUEUE_ENQUEUE(match_p); + + /* + * All chars in the string should be number chars for it to be a + * number. Yes this will return yes if the argument is "00-" but + * we'll chalk this up to user error. + */ + for (str_p = str; *str_p != '\0'; str_p++) { + if (strchr(NUMBER_ARG_CHARS, *str_p) == NULL) { + return 0; + } + } + + return 1; } /* - * Process a list of arguments ARGV and ARGV as it applies to ARGS. - * on NUM_ARGS members. OKAY_P is a pointer to the boolean error - * marker. + * static void do_list + * + * DESCRIPTION: + * + * Process a list of arguments with our array of argv_t structures + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * grid - Our array of argv_t structures. + * + * arg_c - Number of arguments in argv. + * + * argv - User argument array of character pointers. + * + * queue_list <-> Our option queue for storing options to arguments. + * + * queue_head_p <-> Pointer to integer which will be updated with the + * head position in our option queue. + * + * queue_tail_p <-> Pointer to integer which will be updated with the + * tail position in our option queue. + * + * okay_bp - Pointer to an integer which is set with 0 if the + * arguments specified in the env variable are somehow invalid. */ -LOCAL void do_list(argv_t *grid, const int argc, char **argv, - char *okay_p) +static void do_list(argv_t *grid, const int arg_c, char **argv, + argv_t **queue_list, int *queue_head_p, + int *queue_tail_p, int *okay_bp) { argv_t *grid_p, *match_p; int len, char_c, unwant_c = 0; - char last_arg = ARGV_FALSE; + int last_arg_b = ARGV_FALSE; char *close_p = NULL, **arg_p; /* run throught rest of arguments */ - for (arg_p = argv; arg_p < argv + argc; arg_p++) { + for (arg_p = argv; arg_p < argv + arg_c; arg_p++) { /* have we reached the LAST_ARG marker? */ - if (! last_arg && strcmp(LAST_ARG, *arg_p) == 0) { - last_arg = ARGV_TRUE; - continue; - } - - /* check for close equals marker */ - if (! last_arg && global_close == GLOBAL_CLOSE_ENABLE) { - close_p = strchr(*arg_p, ARG_EQUALS); - /* if we find the special char then punch the null and set pointer */ - if (close_p != NULL) { - *close_p = NULLC; - close_p++; + if (strcmp(LAST_ARG, *arg_p) == 0) { + if (last_arg_b) { + if (global_lasttog == GLOBAL_LASTTOG_ENABLE) { + last_arg_b = ARGV_FALSE; + continue; + } + } + else { + last_arg_b = ARGV_TRUE; + continue; } } /* are we processing a long option? */ - if (! last_arg && strncmp(LONG_PREFIX, *arg_p, LONG_PREFIX_LENGTH) == 0) { + if ((! last_arg_b) + && strncmp(LONG_PREFIX, *arg_p, LONG_PREFIX_LENGTH) == 0) { + + /* + * check for close equals marker + * + * NOTE: duplicated in the short prefix section below. In here otherwise + * we process normal args with x=5 instead of just -x=5. + */ + if (global_close == GLOBAL_CLOSE_ENABLE) { + close_p = strchr(*arg_p, ARG_EQUALS); + /* if we found the special char then punch the null and set pointer */ + if (close_p != NULL) { + *close_p = '\0'; + close_p++; + } + } /* get length of rest of argument */ len = strlen(*arg_p) - LONG_PREFIX_LENGTH; /* we need more than the prefix */ if (len <= 0) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, empty long-option prefix '%s'\n", argv_program, USAGE_ERROR_NAME, *arg_p); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; continue; } @@ -1539,18 +2430,20 @@ /* run though long options looking for a match */ for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) { - if (grid_p->ar_long_arg == NULL) + if (grid_p->ar_long_arg == NULL) { continue; + } if (strncmp(*arg_p + LONG_PREFIX_LENGTH, grid_p->ar_long_arg, len) == 0) { if (match_p != NULL) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, '%s' might be '%s' or '%s'\n", argv_program, USAGE_ERROR_NAME, *arg_p, grid_p->ar_long_arg, match_p->ar_long_arg); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; break; } @@ -1562,11 +2455,13 @@ } /* if we found a match but quit then we must have found two matches */ - if (match_p != NULL && grid_p->ar_short_arg != ARGV_LAST) + if (match_p != NULL && grid_p->ar_short_arg != ARGV_LAST) { continue; + } if (match_p != NULL) { - (void)do_arg(grid, match_p, close_p, okay_p); + (void)do_arg(grid, match_p, close_p, queue_list, queue_head_p, + okay_bp); continue; } @@ -1576,17 +2471,20 @@ if (strncmp(FILE_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (global_close == GLOBAL_CLOSE_ENABLE && close_p != NULL) { /* open the file and read in the args */ - file_args(close_p, grid, okay_p); + file_args(close_p, grid, queue_list, queue_head_p, queue_tail_p, + okay_bp); } else { /* HACK: we enqueue null for the file argument */ - QUEUE_ENQUEUE(NULL); + queue_list[*queue_head_p] = NULL; + (*queue_head_p)++; } continue; } /* check for special usage value */ - if (strncmp(USAGE_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { + if (strncmp(USAGE_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0 + || strncmp(HELP_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { do_usage(grid, global_usage); (void)exit(0); @@ -1625,12 +2523,15 @@ if (strncmp(HELP_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { if (argv_error_stream != NULL) { - if (argv_help_string == NULL) + if (argv_help_string == NULL) { (void)fprintf(argv_error_stream, "%s: I'm sorry, no help is available.\n", argv_program); - else - (void)fprintf(argv_error_stream, "%s\n", argv_help_string); + } + else { + (void)fprintf(argv_error_stream, "%s: %s\n", + argv_program, argv_help_string); + } } (void)exit(0); } @@ -1641,12 +2542,14 @@ if (strncmp(VERSION_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { if (argv_error_stream != NULL) { - if (argv_version_string == NULL) + if (argv_version_string == NULL) { (void)fprintf(argv_error_stream, "%s: no version information is available.\n", argv_program); - else + } + else { (void)fprintf(argv_error_stream, "%s\n", argv_version_string); + } } (void)exit(0); } @@ -1656,35 +2559,53 @@ /* check for display arguments value */ if (strncmp(DISPLAY_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { display_variables(grid); + } (void)exit(0); } continue; } - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, unknown long option '%s'.\n", argv_program, USAGE_ERROR_NAME, *arg_p); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; continue; } /* are we processing a short option? */ - if (! last_arg + if ((! last_arg_b) && strncmp(SHORT_PREFIX, *arg_p, SHORT_PREFIX_LENGTH) == 0) { + /* + * check for close equals marker + * + * NOTE: duplicated in the long prefix section above. In here otherwise + * we process normal args with x=5 instead of just -x=5. + */ + if (global_close == GLOBAL_CLOSE_ENABLE) { + close_p = strchr(*arg_p, ARG_EQUALS); + /* if we found the special char then punch the null and set pointer */ + if (close_p != NULL) { + *close_p = '\0'; + close_p++; + } + } + /* get length of rest of argument */ len = strlen(*arg_p) - SHORT_PREFIX_LENGTH; /* we need more than the prefix */ if (len <= 0) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, empty short-option prefix '%s'\n", argv_program, USAGE_ERROR_NAME, *arg_p); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; continue; } @@ -1692,9 +2613,12 @@ for (char_c = 0; char_c < len; char_c++) { /* run through the arg list looking for a match */ - for (match_p = grid; match_p->ar_short_arg != ARGV_LAST; match_p++) - if (match_p->ar_short_arg == (*arg_p)[SHORT_PREFIX_LENGTH + char_c]) + for (match_p = grid; match_p->ar_short_arg != ARGV_LAST; match_p++) { + if (match_p->ar_short_arg == + (*arg_p)[SHORT_PREFIX_LENGTH + char_c]) { break; + } + } /* did we not find argument? */ if (match_p->ar_short_arg == ARGV_LAST) { @@ -1708,83 +2632,157 @@ continue; } + /* + * allow values with negative signs if we are at the start + * of an argument list, and if the argument is a number, and + * we already have a variable looking for a value. Thanks + * to Nick Kisseberth for + * pointing out this oversight. + */ + if (char_c == 0 && is_number(*arg_p) + && *queue_head_p > *queue_tail_p) { + + match_p = queue_list[*queue_tail_p]; + /* + * NOTE: we don't advance the queue tail here unless we + * find out that we can use it below + */ + + switch (ARGV_TYPE(match_p->ar_type)) { + + case ARGV_SHORT: + case ARGV_INT: + case ARGV_LONG: + case ARGV_FLOAT: + case ARGV_DOUBLE: + string_to_value(*arg_p, match_p->ar_variable, match_p->ar_type); + char_c = len; + /* we actually used it so we advance the queue tail position */ + (*queue_tail_p)++; + continue; + break; + } + } + /* create an error string */ - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, unknown short option '%s%c'.\n", argv_program, USAGE_ERROR_NAME, SHORT_PREFIX, (*arg_p)[SHORT_PREFIX_LENGTH + char_c]); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; continue; } - do_arg(grid, match_p, close_p, okay_p); + do_arg(grid, match_p, close_p, queue_list, queue_head_p, okay_bp); } continue; } /* could this be a value? */ - if (grid->ar_short_arg != ARGV_LAST && QUEUE_COUNT() > 0) { - QUEUE_DEQUEUE(match_p); + if (grid->ar_short_arg != ARGV_LAST && *queue_head_p > *queue_tail_p) { + + /* pull the variable waiting for a value from the queue */ + match_p = queue_list[*queue_tail_p]; + (*queue_tail_p)++; + /* HACK: is this the file argument */ - if (match_p == NULL) - file_args(close_p, grid, okay_p); - else - if (translate_value(*arg_p, match_p->ar_variable, - match_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; + if (match_p == NULL) { + file_args(*arg_p, grid, queue_list, queue_head_p, queue_tail_p, + okay_bp); + } + else { + if (string_to_value(*arg_p, match_p->ar_variable, + match_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } + } continue; } /* process mandatory args if some left to process */ - for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) + for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) { if (grid_p->ar_short_arg == ARGV_MAND - && (! (grid_p->ar_type & ARGV_FLAG_USED))) + && ((! (grid_p->ar_type & ARGV_FLAG_USED)) + || grid_p->ar_type & ARGV_FLAG_ARRAY)) { break; + } + } if (grid_p->ar_short_arg != ARGV_LAST) { /* absorb another mand. arg */ - if (translate_value(*arg_p, grid_p->ar_variable, - grid_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; - if (! (grid_p->ar_type & ARGV_ARRAY)) - grid_p->ar_type |= ARGV_FLAG_USED; + if (string_to_value(*arg_p, grid_p->ar_variable, + grid_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } + grid_p->ar_type |= ARGV_FLAG_USED; continue; } /* process maybe args if some left to process */ - for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) + for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) { if (grid_p->ar_short_arg == ARGV_MAYBE - && (! (grid_p->ar_type & ARGV_FLAG_USED))) + && ((! (grid_p->ar_type & ARGV_FLAG_USED)) + || grid_p->ar_type & ARGV_FLAG_ARRAY)) { break; + } + } if (grid_p->ar_short_arg != ARGV_LAST) { /* absorb another maybe arg */ - if (translate_value(*arg_p, grid_p->ar_variable, - grid_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; - if (! (grid_p->ar_type & ARGV_ARRAY)) - grid_p->ar_type |= ARGV_FLAG_USED; + if (string_to_value(*arg_p, grid_p->ar_variable, + grid_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } + grid_p->ar_type |= ARGV_FLAG_USED; continue; } /* default is an error */ unwant_c++; - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; } - if (unwant_c > 0 && argv_error_stream != NULL) + if (unwant_c > 0 && argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, %d unwanted additional argument%s\n", argv_program, USAGE_ERROR_NAME, unwant_c, (unwant_c == 1 ? "" : "s")); + } } /****************************** env processing *******************************/ /* - * Handle the args from the ENV variable. Returns [NO]ERROR. + * static int do_env_args + * + * DESCRIPTION: + * + * Handle the args from the environmentatl variable. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures we are using. + * + * queue_list <-> Our option queue for storing options to arguments. + * + * queue_head_p <-> Pointer to integer which will be updated with the + * head position in our option queue. + * + * queue_tail_p <-> Pointer to integer which will be updated with the + * tail position in our option queue. + * + * okay_bp - Pointer to an integer which is set with 0 if the + * arguments specified in the env variable are somehow invalid. */ -LOCAL int do_env_args(argv_t *args, char *okay_p) +static int do_env_args(argv_t *args, argv_t **queue_list, + int *queue_head_p, int *queue_tail_p, int *okay_bp) { int env_c, env_n; char **vect_p, env_name[256], *environ_p; @@ -1793,26 +2791,32 @@ (void)sprintf(env_name, ENVIRON_FORMAT, argv_program); /* NOTE: by default the env name is all uppercase */ - for (environ_p = env_name; *environ_p != NULLC; environ_p++) - if (islower((int)*environ_p)) + for (environ_p = env_name; *environ_p != '\0'; environ_p++) { + if (islower((int)*environ_p)) { *environ_p = toupper((int)*environ_p); + } + } environ_p = getenv(env_name); - if (environ_p == NULL) + if (environ_p == NULL) { return NOERROR; + } /* break the list into tokens and do the list */ environ_p = string_copy(environ_p); - if (environ_p == NULL) + if (environ_p == NULL) { return ERROR; + } vect_p = vectorize(environ_p, " \t", &env_n); if (vect_p != NULL) { - do_list(args, env_n, vect_p, okay_p); + do_list(args, env_n, vect_p, queue_list, queue_head_p, queue_tail_p, + okay_bp); /* free token list */ - for (env_c = 0; env_c < env_n; env_c++) + for (env_c = 0; env_c < env_n; env_c++) { free(vect_p[env_c]); + } free(vect_p); } free(environ_p); @@ -1821,610 +2825,594 @@ } /* - * Process the global env variable. Returns [NO]ERROR. + * static int process_env + * + * DESCRIPTION: + * + * Process the global env variables. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * None. */ -LOCAL int process_env(void) +static int process_env(void) { - static char done = ARGV_FALSE; - char *environ_p, *env_p, *arg; + static int done_b = ARGV_FALSE; + char *environ, *tok_p, *env_p; int len; /* make sure we only do this once */ - if (done) + if (done_b) { return NOERROR; + } - done = ARGV_TRUE; + done_b = ARGV_TRUE; /* get the argv information */ - environ_p = getenv(GLOBAL_NAME); - if (environ_p == NULL) + environ = getenv(GLOBAL_NAME); + if (environ == NULL) { return NOERROR; + } /* save a copy of it */ - environ_p = string_copy(environ_p); - if (environ_p == NULL) + environ = string_copy(environ); + if (environ == NULL) { return ERROR; + } - arg = environ_p; + env_p = environ; for (;;) { - env_p = strtok(arg, " \t,:"); - if (env_p == NULL) + tok_p = my_strsep(&env_p, " \t,:"); + if (tok_p == NULL) { break; - arg = NULL; + } + /* skip any empty tokens */ + if (*tok_p == '\0') { + continue; + } len = strlen(GLOBAL_CLOSE); - if (strncmp(GLOBAL_CLOSE, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "disable") == 0) + if (strncmp(GLOBAL_CLOSE, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "disable") == 0 + || strcmp(tok_p, "off") == 0 + || strcmp(tok_p, "no") == 0 + || strcmp(tok_p, "0") == 0) { global_close = GLOBAL_CLOSE_DISABLE; - else if (strcmp(env_p, "enable") == 0) + } + else if (strcmp(tok_p, "enable") == 0 + || strcmp(tok_p, "on") == 0 + || strcmp(tok_p, "yes") == 0 + || strcmp(tok_p, "1") == 0) { global_close = GLOBAL_CLOSE_ENABLE; + } + else { + if (argv_error_stream != NULL) { + (void)fprintf(argv_error_stream, + "%s: illegal env variable '%s' '%s' argument '%s'\n", + __FILE__, GLOBAL_NAME, GLOBAL_CLOSE, tok_p); + } + } + continue; + } + + len = strlen(GLOBAL_LASTTOG); + if (strncmp(GLOBAL_LASTTOG, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "disable") == 0 + || strcmp(tok_p, "off") == 0 + || strcmp(tok_p, "no") == 0 + || strcmp(tok_p, "0") == 0) { + global_lasttog = GLOBAL_LASTTOG_DISABLE; + } + else if (strcmp(tok_p, "enable") == 0 + || strcmp(tok_p, "on") == 0 + || strcmp(tok_p, "yes") == 0 + || strcmp(tok_p, "1") == 0) { + global_lasttog = GLOBAL_LASTTOG_ENABLE; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_CLOSE, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_LASTTOG, tok_p); + } } continue; } len = strlen(GLOBAL_ENV); - if (strncmp(GLOBAL_ENV, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "none") == 0) + if (strncmp(GLOBAL_ENV, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "none") == 0) { global_env = GLOBAL_ENV_NONE; - else if (strcmp(env_p, "before") == 0) + } + else if (strcmp(tok_p, "before") == 0) { global_env = GLOBAL_ENV_BEFORE; - else if (strcmp(env_p, "after") == 0) + } + else if (strcmp(tok_p, "after") == 0) { global_env = GLOBAL_ENV_AFTER; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_ENV, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_ENV, tok_p); + } } continue; } len = strlen(GLOBAL_ERROR); - if (strncmp(GLOBAL_ERROR, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "none") == 0) + if (strncmp(GLOBAL_ERROR, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "none") == 0) { global_error = GLOBAL_ERROR_NONE; - else if (strcmp(env_p, "see") == 0) + } + else if (strcmp(tok_p, "see") == 0) { global_error = GLOBAL_ERROR_SEE; - else if (strcmp(env_p, "short") == 0) + } + else if (strcmp(tok_p, "short") == 0) { global_error = GLOBAL_ERROR_SHORT; - else if (strcmp(env_p, "shortrem") == 0) + } + else if (strcmp(tok_p, "shortrem") == 0) { global_error = GLOBAL_ERROR_SHORTREM; - else if (strcmp(env_p, "long") == 0) + } + else if (strcmp(tok_p, "long") == 0) { global_error = GLOBAL_ERROR_LONG; - else if (strcmp(env_p, "all") == 0) + } + else if (strcmp(tok_p, "all") == 0) { global_error = GLOBAL_ERROR_ALL; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_ERROR, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_ERROR, tok_p); + } } continue; } len = strlen(GLOBAL_MULTI); - if (strncmp(GLOBAL_MULTI, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "reject") == 0) + if (strncmp(GLOBAL_MULTI, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "reject") == 0) { global_multi = GLOBAL_MULTI_REJECT; - else if (strcmp(env_p, "accept") == 0) + } + else if (strcmp(tok_p, "accept") == 0) { global_multi = GLOBAL_MULTI_ACCEPT; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_MULTI, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_MULTI, tok_p); + } } continue; } len = strlen(GLOBAL_USAGE); - if (strncmp(GLOBAL_USAGE, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "short") == 0) + if (strncmp(GLOBAL_USAGE, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "short") == 0) { global_usage = GLOBAL_USAGE_SHORT; - else if (strcmp(env_p, "shortrem") == 0) + } + else if (strcmp(tok_p, "shortrem") == 0) { global_usage = GLOBAL_USAGE_SHORTREM; - else if (strcmp(env_p, "long") == 0) + } + else if (strcmp(tok_p, "long") == 0) { global_usage = GLOBAL_USAGE_LONG; - else if (strcmp(env_p, "all") == 0) + } + else if (strcmp(tok_p, "all") == 0) { global_usage = GLOBAL_USAGE_ALL; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_USAGE, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_USAGE, tok_p); + } } continue; } - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' setting '%s'\n", - __FILE__, GLOBAL_NAME, env_p); + __FILE__, GLOBAL_NAME, tok_p); + } } - free(environ_p); + free(environ); return NOERROR; } +/***************************** exported routines *****************************/ + /* - * Processes ARGS from ARGC and ARGV. Returns 0 if no error else -1. + * int argv_process_no_env + * + * DESCRIPTION: + * + * Process the user arguments with an argv_t structure array. Like + * argv_process_args but without the processing of the argv + * environmental variables. + * + * RETURNS: + * + * Success - 0 + * + * Failure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures. + * + * arg_c - Number of arguments in the argv array. + * + * argv - Array of character pointers terminated by 0L. */ -LOCAL int process_args(argv_t *args, const int argc, char **argv) +int argv_process_no_env(argv_t *args, const int arg_c, char **argv) { - int num_args; + int arg_n; const char *prog_p; - char okay = ARGV_TRUE; + int okay_b = ARGV_TRUE; argv_t *arg_p; + argv_t **queue_list=NULL; + int queue_head = 0, queue_tail = 0; - if (process_env() != NOERROR) - return ERROR; - - if (args == NULL) + if (args == NULL) { args = empty; + } - if (argc < 0) { - if (argv_error_stream != NULL) + if (arg_c < 0) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, argc argument to argv_process is %d\n", - __FILE__, INTERNAL_ERROR_NAME, argc); - if (argv_interactive) + __FILE__, INTERNAL_ERROR_NAME, arg_c); + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } if (argv == NULL) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, argv argument to argv_process is NULL\n", __FILE__, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } /* set global variables */ argv_argv = argv; - argv_argc = argc; + argv_argc = arg_c; /* build the program name from the argv[0] path */ { const char *tmp_p; prog_p = *argv; - for (tmp_p = *argv; *tmp_p != NULLC; tmp_p++) - if (*tmp_p == '/') + for (tmp_p = *argv; *tmp_p != '\0'; tmp_p++) { + if (*tmp_p == '/') { prog_p = tmp_p + 1; + } + } } /* so we can step on the environmental space */ (void)strncpy(argv_program, prog_p, PROGRAM_NAME); /* count the args */ - num_args = 0; - for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) - num_args++; + arg_n = 0; + for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { + arg_n++; + } /* verify the argument array */ - if (preprocess_array(args, num_args) != NOERROR) + if (preprocess_array(args, arg_n) != NOERROR) { return ERROR; + } /* allocate our value queue */ - if (num_args > 0) - QUEUE_ALLOC(argv_t *, num_args); + if (arg_n > 0) { + /* allocate our argument queue */ + queue_list = (argv_t **)malloc(sizeof(argv_t *) * arg_n); + if (queue_list == NULL) { + return ERROR; + } + queue_head = 0; + queue_tail = 0; + } /* do the env args before? */ if (global_env == GLOBAL_ENV_BEFORE) { - if (do_env_args(args, &okay) != NOERROR) + if (do_env_args(args, queue_list, &queue_head, &queue_tail, + &okay_b) != NOERROR) { return ERROR; + } } /* do the external args */ - do_list(args, argc - 1, argv + 1, &okay); + do_list(args, arg_c - 1, argv + 1, queue_list, &queue_head, &queue_tail, + &okay_b); - /* do the env args after? */ + /* DO the env args after? */ if (global_env == GLOBAL_ENV_AFTER) { - do_env_args(args, &okay); - if (do_env_args(args, &okay) != NOERROR) + if (do_env_args(args, queue_list, &queue_head, &queue_tail, + &okay_b) != NOERROR) { return ERROR; + } } /* make sure the XOR and MAND args and argument-options are okay */ - if (check_mand(args) != NOERROR) - okay = ARGV_FALSE; - if (check_opt() != NOERROR) - okay = ARGV_FALSE; - if (check_xor(args) != NOERROR) - okay = ARGV_FALSE; + if (check_mand(args) != NOERROR) { + okay_b = ARGV_FALSE; + } + if (check_opt(queue_head, queue_tail) != NOERROR) { + okay_b = ARGV_FALSE; + } + if (check_xor(args) != NOERROR) { + okay_b = ARGV_FALSE; + } /* if we allocated the space then free it */ - if (num_args > 0) - QUEUE_FREE(); + if (arg_n > 0) { + free(queue_list); + } /* was there an error? */ - if (! okay) { - if (argv_error_stream != NULL) + if (! okay_b) { + if (argv_error_stream != NULL) { do_usage(args, global_error); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } return NOERROR; } -/***************************** exported routines *****************************/ - /* - * Processes ARGC number of arguments from ARGV depending on argument - * info array ARGS (if null then an empty array is used). This - * routine will not modify the argv array in any way. + * int argv_process + * + * DESCRIPTION: + * + * Processes a number of arguments depending on the argument array. + * This routine will not modify the argv array in any way. * * NOTE: it will modify the args array by setting various flags in the * type field. returns 0 if no error else -1. + * + * ARGUMENTS: + * + * args - Array of argv_t structures that we are using to process the + * user argument array. If null then an empty array is used. + * + * argc - Number of arguments in the argv argument array. + * + * argv - Array of character pointer arguments terminated by a 0L. */ -EXPORT int argv_process(argv_t *args, const int argc, char **argv) +int argv_process(argv_t *args, const int argc, char **argv) { - if (! enabled) + if (! enabled_b) { argv_startup(); + } + + /* we only process env variables here */ + if (process_env() != NOERROR) { + return ERROR; + } - if (process_args(args, argc, argv) == NOERROR) + if (argv_process_no_env(args, argc, argv) == NOERROR) { return NOERROR; - else + } + else { return ERROR; + } } /* - * Processes arguments sent in via the STRING that a web-server might - * send to program in ARG0. Use DELIM to set up the delimiters of the - * arguments in the string. query_string processing should have "&" - * and path_info should have "/". You may want to add "=" if you use - * arg=value. The '=' delimiter is treated as special so //x=// will - * strip the extra /'s in a row but will create a null argument for x. - * - * WARNING: you cannot use argv_copy_args after this is called because a - * temporary grid is created. returns 0 on noerror else -1. - */ -EXPORT int argv_web_process_string(argv_t *args, const char *arg0, - const char *string, - const char *delim) -{ - const char *str_p, *delim_p, *delim_str; - char *copy, *copy_p, **argv; - int argc, ret, alloced; - - if (! enabled) + * int argv_usage + * + * DESCRIPTION: + * + * Print the standard usage messages for our argument array. You can + * specify whether you want to see a short or long usage messages. + * + * NOTE: if this is called before argv_process then the program name + * may be invalid. + * + * RETURNS: + * + * Success - 0 + * + * Failure - -1 + * + * ARGUMENTS: + * + * args - Our argument array to print the usage messages about. If + * null then an empty array is used. + * + * which - Either ARGV_USAGE_SHORT (for short usage messages), + * ARGV_USAGE_LONG (for long usage messages), or ARGV_USAGE_DEFAULT + * (the user's default either long or short). + */ +int argv_usage(const argv_t *args, const int which) +{ + if (! enabled_b) { argv_startup(); - - if (delim == NULL) - delim_str = ""; - else - delim_str = delim; - - /* copy incoming string so we can punch nulls */ - copy = malloc(strlen(string) + 1); - if (copy == NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; } - /* create argv array */ - alloced = ARG_MALLOC_INCR; - argv = (char **)malloc(sizeof(char *) * alloced); - if (argv == NULL) { - free(copy); - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); + if (process_env() != NOERROR) { return ERROR; } - argc = 0; - argv[argc++] = (char *)arg0; - str_p = string; - /* skip starting multiple arg delimiters */ - for (; *str_p != NULLC; str_p++) { - for (delim_p = delim_str; *delim_p != NULLC; delim_p++) - if (*str_p == *delim_p) - break; - if (*delim_p == NULLC) - break; + if (args == NULL) { + args = empty; } - /* start of the string is argv[1] */ - if (*str_p != NULLC) { - if (argc >= alloced) { - alloced += ARG_MALLOC_INCR; - argv = (char **)realloc(argv, sizeof(char *) * alloced); - if (argv == NULL) { - free(copy); - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; - } - } - argv[argc++] = copy; + if (which == ARGV_USAGE_SHORT) { + usage_short(args, 0); } - - for (copy_p = copy;; str_p++) { - int val; - - /* are we done? */ - if (*str_p == NULLC) { - *copy_p = NULLC; - break; - } - - /* is this a argument seperator? */ - for (delim_p = delim_str; *delim_p != NULLC; delim_p++) - if (*str_p == *delim_p) - break; - if (*delim_p != NULLC) { - *copy_p++ = NULLC; - - /* - * look ahead and skip multiple arg delimiters. we have a - * special case if the delimiter is '='. This means that we - * need to generate a null string argument. - */ - if (*str_p != '=') { - for (;; str_p++) { - for (delim_p = delim_str; *delim_p != NULLC; delim_p++) - if (*(str_p + 1) == *delim_p) - break; - if (*delim_p == NULLC) - break; - } - } - - /* if we are not at the end of the string, create a new arg */ - if (*str_p == '=' || *(str_p + 1) != NULLC) { - if (argc >= alloced) { - alloced += ARG_MALLOC_INCR; - argv = (char **)realloc(argv, sizeof(char *) * alloced); - if (argv == NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; - } - } - argv[argc++] = copy_p; - } - continue; - } - - /* a space */ - if (*str_p == '+') { - *copy_p++ = ' '; - continue; - } - - /* no binary character, than it is normal */ - if (*str_p != '%') { - *copy_p++ = *str_p; - continue; - } - - str_p++; - - if (*str_p >= 'a' && *str_p <= 'f') - val = 10 + *str_p - 'a'; - else if (*str_p >= 'A' && *str_p <= 'F') - val = 10 + *str_p - 'A'; - else if (*str_p >= '0' && *str_p <= '9') - val = *str_p - '0'; - else - continue; - - str_p++; - - if (*str_p >= 'a' && *str_p <= 'f') - val = val * 16 + (10 + *str_p - 'a'); - else if (*str_p >= 'A' && *str_p <= 'F') - val = val * 16 + (10 + *str_p - 'A'); - else if (*str_p >= '0' && *str_p <= '9') - val = val * 16 + (*str_p - '0'); - else - str_p--; - - *copy_p++ = (char)val; + else if (which == ARGV_USAGE_LONG) { + usage_long(args); + } + else { + /* default/env settings */ + do_usage(args, global_usage); } - ret = process_args(args, argc, argv); - - free(copy); - free(argv); - - if (ret == NOERROR) - return NOERROR; - else - return ERROR; + return NOERROR; } /* - * Processes arguments sent in via the QUERY_STRING environmental - * variable that a web-server might send to program in ARG0. Returns - * 0 on noerror else -1. + * int argv_was_used + * + * DESCRIPTION: + * + * See if an argument was used in a previous call to argv_process. + * + * RETURNS: + * + * 1 if yes it was used, else 0 if not. + * + * ARGUMENTS: + * + * args - Argument list to search. + * + * short_arg - Short argument to see if it was used. */ -EXPORT int argv_web_process(argv_t *args, const char *arg0) +int argv_was_used(const argv_t *args, const char short_arg) { - char *env, *work = NULL; - int ret, len; + const argv_t *arg_p; - if (! enabled) + if (! enabled_b) { argv_startup(); - - env = getenv("REQUEST_METHOD"); - if (env != NULL && strcmp(env, "POST") == 0) { - env = getenv("CONTENT_LENGTH"); - if (env != NULL) { - len = atoi(env); - if (len > 0) { - work = (char *)malloc(len + 1); - if (work == NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; - } - (void)read(STDIN, work, len); - work[len] = NULLC; - } - } } - if (work == NULL) { - env = getenv("QUERY_STRING"); - - /* if it is not set or empty, then nothing to do */ - if (env == NULL || *env == NULLC) { - work = (char *)malloc(1); - if (work == NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; + for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { + if (arg_p->ar_short_arg == short_arg) { + if (arg_p->ar_type & ARGV_FLAG_USED) { + return 1; + } + else { + return 0; } - work[0] = NULLC; - } - else { - work = string_copy(env); - if (work == NULL) - return ERROR; } } - ret = argv_web_process_string(args, arg0, work, "&="); - free(work); - - if (ret == NOERROR) - return NOERROR; - else - return ERROR; + return 0; } /* - * Print the standard usage messages for argument array ARGS (if null - * then an empty array is used). WHICH chooses between long or short - * messages (see argv.h). + * int argv_long_was_used * - * NOTE: if this is called before argv_process then the program name may - * be messed up. - */ -EXPORT int argv_usage(const argv_t *args, const int which) -{ - if (! enabled) - argv_startup(); - - if (process_env() != NOERROR) - return ERROR; - - if (args == NULL) - args = empty; - - if (which == ARGV_USAGE_SHORT) - usage_short(args, 0); - else if (which == ARGV_USAGE_LONG) - usage_long(args); - else - /* default/env settings */ - do_usage(args, global_usage); - - return NOERROR; -} - -/* - * See if ARG argument was used in a previous call to argv_process on - * ARGS. Returns 1 if yes else 0. + * DESCRIPTION: + * + * See if a long argument was used in a previous call to argv_process. + * + * RETURNS: + * + * 1 if yes it was used, else 0 if not. + * + * ARGUMENTS: + * + * args - Argument list to search. + * + * long_arg - Long argument to see if it was used. */ -EXPORT int argv_was_used(const argv_t *args, const char arg) +int argv_long_was_used(const argv_t *args, const char *long_arg) { const argv_t *arg_p; - if (! enabled) + if (! enabled_b) { argv_startup(); + } - for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) - if (arg_p->ar_short_arg == arg) { - if (arg_p->ar_type & ARGV_FLAG_USED) + for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { + if (arg_p->ar_long_arg == long_arg) { + if (arg_p->ar_type & ARGV_FLAG_USED) { return 1; - else + } + else { return 0; + } } + } return 0; } /* - * Frees up any allocations in ARGS that may have been done by + * void argv_cleanup + * + * DESCRIPTION: + * + * Frees up any allocations associated with the argument array during * argv_process. This should be done at the end of the program or * after all the arguments have been referenced. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * args - Argument array we are cleaning up. */ -EXPORT void argv_cleanup(const argv_t *args) +void argv_cleanup(const argv_t *args) { const argv_t *arg_p; int entry_c; - if (! enabled) + if (! enabled_b) { argv_startup(); + } - if (args == NULL) + if (args == NULL) { return; + } /* run through the argument structure */ for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { /* handle any arrays */ - if (arg_p->ar_type & ARGV_ARRAY) { + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { argv_array_t *arr_p = (argv_array_t *)arg_p->ar_variable; /* free any entries */ - if (arr_p->aa_entryn > 0) { - if (ARGV_TYPE(arg_p->ar_type) == ARGV_CHARP) { - for (entry_c = 0; entry_c < arr_p->aa_entryn; entry_c++) + if (arr_p->aa_entry_n > 0) { + if (ARGV_TYPE(arg_p->ar_type) == ARGV_CHAR_P) { + for (entry_c = 0; entry_c < arr_p->aa_entry_n; entry_c++) { free(ARGV_ARRAY_ENTRY(*arr_p, char *, entry_c)); + } } free(arr_p->aa_entries); } arr_p->aa_entries = NULL; - arr_p->aa_entryn = 0; + arr_p->aa_entry_n = 0; continue; } /* handle individual charps */ if (arg_p->ar_type & ARGV_FLAG_USED - && ARGV_TYPE(arg_p->ar_type) == ARGV_CHARP) { + && ARGV_TYPE(arg_p->ar_type) == ARGV_CHAR_P) { free(*(char **)arg_p->ar_variable); continue; } @@ -2432,44 +3420,102 @@ } /* - * Copy all the args (after the 0th), one after the other, into BUF of - * MAX_SIZE. Returns 0 on no error else -1. + * int argv_copy_args + * + * DESCRIPTION: + * + * Copy all the arguements (not including the 0th) one after the other + * into the user specified buffer. + * + * NOTE: you can get the 0th argument from argv_argv[0] or + * argv_program. + * + * RETURNS: + * + * Success - 0 + * + * Failure - -1 * - * NOTE: you can get the 0th argument from argv_argv[0]. + * ARGUMENTS: + * + * buf - Buffer to copy all of the user arguments into. + * + * buf_size - Size of the buffer. */ -EXPORT int argv_copy_args(char *buf, const int max_size) +int argv_copy_args(char *buf, const int buf_size) { char **argv_p, *buf_p = buf, *arg_p; - int argc, size_c = max_size; + int arg_c, size_c = buf_size; - if (! enabled) + if (! enabled_b) { argv_startup(); + } - if (process_env() != NOERROR) - return ERROR; - - if (max_size == 0) + if (buf_size <= 0) { return NOERROR; + } + + *buf_p = '\0'; - *buf_p = NULLC; + if (process_env() != NOERROR) { + return ERROR; + } - if (argv_argv == NULL || max_size == 1) + if (argv_argv == NULL || buf_size == 1) { return NOERROR; + } - for (argv_p = argv_argv + 1, argc = 1; argc < argv_argc; argv_p++, argc++) { + for (argv_p = argv_argv + 1, arg_c = 1; + arg_c < argv_argc; + argv_p++, arg_c++) { - if (size_c < 2) + /* we compare against 2 for the ' ' and the \0 */ + if (size_c < 2) { break; + } if (argv_p > argv_argv + 1) { *buf_p++ = ' '; size_c--; } - for (arg_p = *argv_p; *arg_p != NULLC && size_c >= 2; size_c--) + /* we always compare against 2 to include the \0 */ + for (arg_p = *argv_p; *arg_p != '\0' && size_c >= 2; size_c--) { *buf_p++ = *arg_p++; + } } - *buf_p = NULLC; + *buf_p = '\0'; return NOERROR; } + +/* + * int argv_value_string + * + * DESCRIPTION: + * + * Convert the value of a RC entry to its string equivalent in the + * buffer provided. + * + * RETURNS: + * + * Length of bytes copied into the buffer. + * + * ARGUMENTS: + * + * argv_entry_p - Pointer to an entry in a argv_t list. + * + * buf - Buffer to convert the value into. + * + * buf_size - Size of the buffer. + */ +int argv_value_string(const argv_t *argv_entry_p, char *buf, + const int buf_size) +{ + if (! enabled_b) { + argv_startup(); + } + + return value_to_string(argv_entry_p->ar_variable, argv_entry_p->ar_type, + buf, buf_size); +}