head 1.3; access; symbols PETIDOMO_4_0b6:1.3 PETIDOMO_4_0b5:1.3 PETIDOMO_4_0b4:1.3 PETIDOMO_4_0b3:1.3 BEFORETHL:1.3 petidomo-2-2:1.1.1.1 petidomo:1.1.1; locks; strict; comment @ * @; 1.3 date 2001.01.19.14.56.34; author rse; state Exp; branches; next 1.2; 1.2 date 2000.12.13.15.37.35; author simons; state Exp; branches; next 1.1; 1.1 date 2000.12.13.13.19.10; author simons; state Exp; branches 1.1.1.1; next ; 1.1.1.1 date 2000.12.13.13.19.10; author simons; state Exp; branches; next ; desc @@ 1.3 log @Get rid of all complaints from GCC 2.97 (except for two things which I do not want to change on my own) @ text @/* * $Source: /e/ossp/cvs/ossp-pkg/petidomo/libargv/argv.c,v $ * $Revision: 1.2 $ * $Date: 2000/12/13 15:37:35 $ * * 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 * above copyright notice and this permission notice appear in all * copies, and that the name of Gray Watson not be used in advertising * or publicity pertaining to distribution of the document or software * 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" * without express or implied warranty. */ #include #include #include #include #include "argv.h" #include "argv_loc.h" /* internal routines */ 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 */ char argv_program[PROGRAM_NAME + 1] = "Unknown"; /* A global value of argv from main after argv_process has been called */ char **argv_argv = NULL; /* A global value of argc from main after argv_process has been called */ int argv_argc = 0; /* This should be set externally to provide general program help to user */ char *argv_help_string = NULL; /* This should be set externally to provide version information to the user */ char *argv_version_string = NULL; /* * Are we running interactively? This will exit on errors. Set to * false to return error codes instead. */ 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. */ FILE *argv_error_stream = ERROR_STREAM_INIT; /* local variables */ static argv_t empty[] = {{ ARGV_LAST }}; /* empty argument array */ static int enabled_b = ARGV_FALSE; /* are the lights on? */ /* global settings */ 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. */ static void argv_startup(void) { if (enabled_b) { return; } enabled_b = ARGV_TRUE; /* ANSI says we cannot predefine this above */ if (argv_error_stream == ERROR_STREAM_INIT) { argv_error_stream = stderr; } } /***************************** general utilities *****************************/ /*** ET: BSD's strsep funktion. See their man-page... ***/ static 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 */ } /* * 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. */ static int btoi(const char *str) { int ret = 0; /* strip off spaces */ for (; isspace((int)*str); str++) { } for (; *str == '0' || *str == '1'; str++) { ret *= 2; ret += *str - '0'; } return ret; } /* * 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. */ static int otoi(const char *str) { int ret = 0; /* strip off spaces */ for (; isspace((int)*str); str++) { } for (; *str >= '0' && *str <= '7'; str++) { ret *= 8; ret += *str - '0'; } return ret; } /* * 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. */ static int htoi(const char *str) { int ret = 0; /* strip off spaces */ for (; isspace((int)*str); str++) { } /* skip a leading 0[xX] */ 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') { ret += *str - 'a' + 10; } else if (*str >= 'A' && *str <= 'F') { ret += *str - 'A' + 10; } else { ret += *str - '0'; } } return ret; } /* * 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. */ static char *string_copy(const char *str) { const char *str_p; char *copy, *copy_p; int len; 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) { (void)exit(EXIT_CODE); } return NULL; } for (str_p = str, copy_p = copy; *str_p != '\0';) { *copy_p++ = *str_p++; } *copy_p = '\0'; return copy; } /* * static char **vectorize * * 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. */ static char **vectorize(char *str, const char *tok, int *num_tok_p) { char **vect_p; char *tmp, *str_p, *tok_p; int tok_c, tok_n; /* count the tokens */ tmp = string_copy(str); if (tmp == NULL) { return NULL; } 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); *num_tok_p = tok_n; 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) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); } if (argv_interactive) { (void)exit(EXIT_CODE); } return NULL; } /* load the tokens into the list */ 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; } /* * 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. */ static int expand_buf(const void *buf, const int buf_size, char *out, const int out_size) { int buf_c; const unsigned char *buf_p, *spec_p; char *max_p, *out_p = out; /* setup our max pointer */ max_p = out + out_size; /* 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 = (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) != '\0') { if (out_p + 2 >= max_p) { break; } (void)sprintf(out_p, "\\%c", *(spec_p - 1)); out_p += 2; continue; } /* 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 >= max_p) { break; } (void)sprintf(out_p, "\\%03o", *buf_p); out_p += 4; } } 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. */ static void usage_short(const argv_t *args, const int flag) { const argv_t *arg_p; int len, col_c = 0; int mark_b = ARGV_FALSE; char *prefix; if (argv_error_stream == NULL) { return; } /* print the usage message header */ (void)fprintf(argv_error_stream, "%s%s", USAGE_LABEL, argv_program); col_c += USAGE_LABEL_LENGTH + strlen(argv_program); /* * print all of the boolean arguments first. * NOTE: we assume they all fit on the line */ 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) { continue; } /* skip non booleans */ if (HAS_ARG(arg_p->ar_type)) { continue; } /* skip args with no short component */ if (arg_p->ar_short_arg == '\0') { continue; } if (! mark_b) { len = 2 + SHORT_PREFIX_LENGTH; prefix = " ["; /* we check for -2 here because we should have 1 arg and ] on line */ if (col_c + len > SCREEN_WIDTH - 2) { (void)fprintf(argv_error_stream, "\n%*.*s", (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, ""); col_c = USAGE_LABEL_LENGTH; /* if we are the start of a line, skip any starting spaces */ if (*prefix == ' ') { prefix++; len--; } } (void)fprintf(argv_error_stream, "%s%s", prefix, SHORT_PREFIX); col_c += len; mark_b = ARGV_TRUE; } len = 1; /* we check for -1 here because we should need ] */ if (col_c + len > SCREEN_WIDTH - 1) { (void)fprintf(argv_error_stream, "]\n%*.*s", (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, ""); col_c = USAGE_LABEL_LENGTH; /* restart the short option list */ (void)fprintf(argv_error_stream, "[%s", SHORT_PREFIX); col_c += 1 + SHORT_PREFIX_LENGTH; } (void)fprintf(argv_error_stream, "%c", arg_p->ar_short_arg); col_c++; } if (mark_b) { (void)fprintf(argv_error_stream, "]"); col_c++; } /* print remaining (non-boolean) arguments */ for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { int var_len; char *var_str, *postfix; /* skip or-specifiers */ if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) { continue; } /* skip booleans types */ 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 || ARGV_TYPE(arg_p->ar_type) == ARGV_BOOL_INT_ARG) { var_str = BOOL_ARG_LABEL; var_len = BOOL_ARG_LENGTH; } else { var_len = UNKNOWN_ARG_LENGTH; var_str = UNKNOWN_ARG; } } else { var_len = strlen(arg_p->ar_var_label); var_str = arg_p->ar_var_label; } if (arg_p->ar_short_arg == ARGV_MAND) { /* print the mandatory argument desc */ len = 1 + var_len; prefix = " "; postfix = ""; } else if (arg_p->ar_short_arg == ARGV_MAYBE) { /* print the maybe argument desc */ len = 2 + var_len + 1; prefix = " ["; postfix = "]"; } else { /* handle options with arguments */ /* " [" + short_prefix + char */ len = 2 + SHORT_PREFIX_LENGTH + 1; prefix = " ["; /* do we need to wrap */ if (col_c + len > SCREEN_WIDTH) { (void)fprintf(argv_error_stream, "\n%*.*s", (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, ""); col_c = USAGE_LABEL_LENGTH; /* if we are the start of a line, skip any starting spaces */ if (*prefix == ' ') { prefix++; len--; } } (void)fprintf(argv_error_stream, "%s%s%c", prefix, SHORT_PREFIX, arg_p->ar_short_arg); col_c += len; len = 1 + var_len + 1; prefix = " "; postfix = "]"; } if (col_c + len > SCREEN_WIDTH) { (void)fprintf(argv_error_stream, "\n%*.*s", (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, ""); col_c = USAGE_LABEL_LENGTH; /* if we are the start of a line, skip any starting spaces */ if (*prefix == ' ') { prefix++; len--; } } (void)fprintf(argv_error_stream, "%s%s%s", prefix, var_str, postfix); col_c += len; } (void)fprintf(argv_error_stream, "\n"); 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); } } /* * 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. */ 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) { var_len = 0; } 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_cp) += BOOL_ARG_LENGTH; break; case ARGV_CHAR: 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_cp; (void)fprintf(stream, "%-.*s", len, UNKNOWN_ARG); *col_cp += MIN(len, (int)UNKNOWN_ARG_LENGTH); } else { len = max - *col_cp; (void)fprintf(stream, "%-.*s", len, arg_p->ar_var_label); *col_cp += MIN(len, var_len); } break; } } /* * 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. */ static void display_option(FILE *stream, const argv_t *arg_p, int *col_cp) { if (stream == NULL) { return; } (void)fputc('[', stream); (*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_cp += SHORT_PREFIX_LENGTH + 1; if (HAS_ARG(arg_p->ar_type)) { /* display optional argument */ (void)fputc(' ', stream); (*col_cp)++; } } display_arg(stream, arg_p, LONG_COLUMN - 1, col_cp); (void)fputc(']', stream); (*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. */ static void usage_long(const argv_t *args) { const argv_t *arg_p; int col_c, len; if (argv_error_stream == NULL) { return; } /* print the usage message header */ (void)fprintf(argv_error_stream, "%s%s\n", USAGE_LABEL, argv_program); /* run through the argument structure */ 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) { continue; } /* indent to the short-option col_c */ (void)fprintf(argv_error_stream, "%*.*s", SHORT_COLUMN, SHORT_COLUMN, ""); /* start column counter */ col_c = SHORT_COLUMN; /* print the short-arg stuff if there */ if (arg_p->ar_short_arg == '\0') { (void)fputc('[', argv_error_stream); col_c++; } else { 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 { /* 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) { (void)fprintf(argv_error_stream, "%*.*s", LONG_COLUMN - col_c, LONG_COLUMN - col_c, ""); col_c = LONG_COLUMN; } } /* 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 != '\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)); } /* add the optional argument if no short-arg */ if (arg_p->ar_short_arg == '\0') { if (HAS_ARG(arg_p->ar_type)) { (void)fputc(' ', argv_error_stream); col_c++; } /* display any optional arguments */ display_arg(argv_error_stream, arg_p, COMMENT_COLUMN - 1, &col_c); (void)fputc(']', argv_error_stream); col_c++; } /* print the comment */ if (arg_p->ar_comment != NULL) { /* put the comment message on the correct column */ if (col_c < COMMENT_COLUMN) { (void)fprintf(argv_error_stream, "%*.*s", COMMENT_COLUMN - col_c, COMMENT_COLUMN - col_c, ""); col_c = COMMENT_COLUMN; } len = SCREEN_WIDTH - col_c - COMMENT_LABEL_LENGTH; (void)fprintf(argv_error_stream, "%s%-.*s", COMMENT_LABEL, len, arg_p->ar_comment); } (void)fprintf(argv_error_stream, "\n"); } } /* * 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. */ static void do_usage(const argv_t *args, const int flag) { if (argv_error_stream == NULL) { return; } 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) { usage_short(args, flag); } else if (flag == GLOBAL_USAGE_LONG || flag == GLOBAL_USAGE_ALL) { usage_long(args); } if (flag == GLOBAL_USAGE_ALL) { (void)fprintf(argv_error_stream, "\n"); (void)fprintf(argv_error_stream, "%*.*sUse '%s%s' for default usage information.\n", SHORT_COLUMN, SHORT_COLUMN, "", LONG_PREFIX, USAGE_ARG); (void)fprintf(argv_error_stream, "%*.*sUse '%s%s' for short usage information.\n", SHORT_COLUMN, SHORT_COLUMN, "", LONG_PREFIX, USAGE_SHORT_ARG); (void)fprintf(argv_error_stream, "%*.*sUse '%s%s' for long usage information.\n", SHORT_COLUMN, SHORT_COLUMN, "", LONG_PREFIX, USAGE_LONG_ARG); (void)fprintf(argv_error_stream, "%*.*sUse '%s%s' for all usage information.\n", SHORT_COLUMN, SHORT_COLUMN, "", LONG_PREFIX, USAGE_ALL_ARG); (void)fprintf(argv_error_stream, "%*.*sUse '%s%s' to display the help message.\n", SHORT_COLUMN, SHORT_COLUMN, "", LONG_PREFIX, HELP_ARG); (void)fprintf(argv_error_stream, "%*.*sUse '%s%s' to display the version message.\n", SHORT_COLUMN, SHORT_COLUMN, "", LONG_PREFIX, VERSION_ARG); (void)fprintf(argv_error_stream, "%*.*sUse '%s%s' to display the options and their values.\n", SHORT_COLUMN, SHORT_COLUMN, "", LONG_PREFIX, DISPLAY_ARG); } } /******************************* preprocessing *******************************/ /* * 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. */ static int preprocess_array(argv_t *args, const int arg_n) { argv_t *arg_p; 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 + 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_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) { (void)exit(EXIT_CODE); } return ERROR; } 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) { (void)exit(EXIT_CODE); } return ERROR; } if (arg_p->ar_type & ARGV_FLAG_ARRAY) { mand_array_b = ARGV_TRUE; } } /* do we have a maybe field? */ if (arg_p->ar_short_arg == ARGV_MAYBE) { 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) { (void)exit(EXIT_CODE); } return ERROR; } 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_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) { (void)fprintf(argv_error_stream, "%s: %s, cannot have an array of boolean values\n", argv_program, INTERNAL_ERROR_NAME); } if (argv_interactive) { (void)exit(EXIT_CODE); } return ERROR; } if (ARGV_TYPE(arg_p->ar_type) == ARGV_INCR) { 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) { (void)exit(EXIT_CODE); } return ERROR; } arrp->aa_entry_n = 0; } /* 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) { (void)fprintf(argv_error_stream, "%s: %s, NULL variable specified in arg array\n", argv_program, INTERNAL_ERROR_NAME); } if (argv_interactive) { (void)exit(EXIT_CODE); } return ERROR; } /* verify [X]OR's */ if (arg_p->ar_short_arg == ARGV_OR || 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 + 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) { (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) { (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) { (void)exit(EXIT_CODE); } return ERROR; } } } return NOERROR; } /* * 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. */ 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; 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++) { if (type_p->at_value == val_type) { size = type_p->at_size; break; } } if (type_p->at_value == 0) { if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal variable type %d\n", __FILE__, val_type); } return ERROR; } if (type & ARGV_FLAG_ARRAY) { arr_p = (argv_array_t *)var; if (arr_p->aa_entry_n == 0) { arr_p->aa_entries = (char *)malloc(ARRAY_INCR *size); } else if (arr_p->aa_entry_n % ARRAY_INCR == 0) { arr_p->aa_entries = (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) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); } if (argv_interactive) { (void)exit(EXIT_CODE); } return ERROR; } var = (char *)(arr_p->aa_entries) + arr_p->aa_entry_n * size; arr_p->aa_entry_n++; } /* translate depending on type */ switch (val_type) { case ARGV_BOOL: /* if no close argument, set to true */ 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 *)var = ARGV_TRUE; } 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_CHAR_P: *(char **)var = string_copy((char *)arg); if (*(char **)var == NULL) { return ERROR; } 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; case ARGV_U_INT: *(unsigned int *)var = atoi(arg); break; case ARGV_LONG: *(long *)var = atol(arg); break; case ARGV_U_LONG: *(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; case ARGV_OCT: *(int *)var = otoi(arg); break; case ARGV_HEX: *(int *)var = htoi(arg); break; case ARGV_INCR: /* if no close argument then increment else set the value */ if (arg == NULL) { (*(int *)var)++; } else { *(int *)var = atoi(arg); } break; 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') { *(int *)var = ARGV_TRUE; } else { *(int *)var = ARGV_FALSE; } break; } return NOERROR; } /* * 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. */ static int value_to_string(const ARGV_PNT var, const unsigned int type, char *buf, const int buf_size) { 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 (ARGV_TYPE(type)) { case ARGV_BOOL: case ARGV_BOOL_NEG: case ARGV_BOOL_ARG: 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: len = expand_buf((char *)var, 1, buf, buf_size); break; 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_SHORT: (void)sprintf(buf, "%d", *(short *)var); len = strlen(buf); break; case ARGV_U_SHORT: (void)sprintf(buf, "%d", *(unsigned short *)var); len = strlen(buf); break; case ARGV_INT: (void)sprintf(buf, "%d", *(int *)var); len = strlen(buf); break; case ARGV_U_INT: (void)sprintf(buf, "%u", *(unsigned int *)var); len = strlen(buf); break; case ARGV_LONG: (void)sprintf(buf, "%ld", *(long *)var); len = strlen(buf); break; case ARGV_U_LONG: (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, bit, first_b = ARGV_FALSE; char binary[2 + 128 + 1], *bin_p = binary; if (*(int *)var == 0) { strncpy(buf, "0", buf_size); } else { /* 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--) { bit = *(int *)var & (1 << bit_c); if (bit == 0) { if (first_b) { *bin_p++ = '0'; } } else { *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: 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: 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; } /* * 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. */ 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++) { 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) { continue; } col_c = 0; 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 { /* 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) { (void)fprintf(argv_error_stream, "%*.*s", LONG_COLUMN - col_c, LONG_COLUMN - col_c, ""); col_c = LONG_COLUMN; } /* find the type */ 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 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_FLAG_ARRAY) { (void)fprintf(argv_error_stream, "%s", ARRAY_LABEL); col_c += sizeof(ARRAY_LABEL) - 1; } break; } } if (col_c < COMMENT_COLUMN) { (void)fprintf(argv_error_stream, "%*.*s", COMMENT_COLUMN - col_c, COMMENT_COLUMN - col_c, ""); col_c = COMMENT_COLUMN; } if (arg_p->ar_type & ARGV_FLAG_ARRAY) { argv_array_t *arr_p; int entry_c, size = 0; /* find the type and the size for array */ if (type_p == NULL) { (void)fprintf(argv_error_stream, "%s: illegal variable type %d\n", __FILE__, val_type); continue; } size = type_p->at_size; arr_p = (argv_array_t *)arg_p->ar_variable; if (arr_p->aa_entry_n == 0) { (void)fprintf(argv_error_stream, "no entries"); } else { for (entry_c = 0; entry_c < arr_p->aa_entry_n; entry_c++) { ARGV_PNT var; if (entry_c > 0) { (void)fputc(',', argv_error_stream); } var = (char *)(arr_p->aa_entries) + entry_c * size; len = value_to_string(var, val_type, buf, sizeof(buf)); (void)fwrite(buf, sizeof(char), len, argv_error_stream); } } } 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); } } /************************** checking used arguments **************************/ /* * 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. */ 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_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) { break; } if (arg_p->ar_type & ARGV_FLAG_USED) { match_p = arg_p; break; } } /* check ORs above */ if (match_p == NULL) { /* 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) { break; } if (arg_p->ar_type & ARGV_FLAG_USED) { match_p = arg_p; break; } } } /* did we not find a problem? */ if (match_p == NULL) { return NOERROR; } if (argv_error_stream == NULL) { return ERROR; } (void)fprintf(argv_error_stream, "%s: %s, specify only one of the following:\n", argv_program, USAGE_ERROR_NAME); /* 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%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%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_p) { break; } match_p = which_p; } return 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. */ static int check_xor(const argv_t *args) { const argv_t *start_p = NULL, *arg_p; /* run through the list of arguments */ 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) { continue; } start_p = arg_p; /* * 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) { start_p = NULL; } /* run through all XORs */ for (;;) { arg_p++; if (arg_p->ar_type & ARGV_FLAG_USED) { start_p = NULL; } if ((arg_p + 1)->ar_short_arg != ARGV_XOR) { break; } arg_p++; } /* were none of the xor's filled? */ if (start_p != NULL) { break; } } /* did we not find a problem? */ if (start_p == NULL) { return NOERROR; } /* arg_p points to the first XOR which failed */ if (argv_error_stream == NULL) { return ERROR; } (void)fprintf(argv_error_stream, "%s: %s, must specify one of:\n", argv_program, USAGE_ERROR_NAME); for (arg_p = start_p;; arg_p += 2) { /* * NOTE: we are guaranteed that we are on a XOR so there is * something below and above... */ (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) { (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) { break; } } return 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. */ static int check_mand(const argv_t *args) { const argv_t *arg_p; 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++) { if (arg_p->ar_short_arg == ARGV_MAND && (! (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 (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")); } if (mand_c > 0 || flag_c > 0) { return ERROR; } else { return NOERROR; } } /* * 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. */ static int check_opt(const int queue_head, const int queue_tail) { int queue_c; queue_c = queue_head - queue_tail; if (queue_c > 0) { 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; } return NOERROR; } /**************************** argument processing ****************************/ /* * 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. */ 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 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_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) { (void)exit(EXIT_CODE); } return; } /* get an array of char * */ arg_c = 0; max = ARRAY_INCR; argv = malloc(sizeof(char *) * max); if (argv == NULL) { *okay_bp = ARGV_FALSE; (void)fclose(infile); 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; } argv_p = argv; /* 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++) { } *line_p = '\0'; *argv_p = string_copy(line); if (*argv_p == NULL) { *okay_bp = ARGV_FALSE; return; } argv_p++; arg_c++; if (arg_c == max) { max += ARRAY_INCR; argv = realloc(argv, sizeof(char *) * max); if (argv == NULL) { *okay_bp = ARGV_FALSE; (void)fclose(infile); 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; } argv_p = argv + arg_c; } } /* now do the list */ 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 + arg_c; argv_p++) { free(*argv_p); } free(argv); (void)fclose(infile); } /* * 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. */ 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) { /* * have we used this one before? * NOTE: should this be a warning or a non-error altogether? */ if (match_p->ar_type & ARGV_FLAG_USED && (! (match_p->ar_type & ARGV_FLAG_ARRAY)) && ARGV_TYPE(match_p->ar_type) != ARGV_INCR) { 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_bp = ARGV_FALSE; } } /* we used this argument */ match_p->ar_type |= ARGV_FLAG_USED; /* check arguments that must be OR'd */ if (check_or(grid, match_p) != NOERROR) { /* * don't return here else we might generate an XOR error * because the argument wasn't specified */ *okay_bp = ARGV_FALSE; } /* * If we have a close argument, pass to translate. If it is a * boolean or increment variable, then pass in a value of null * else queue it for needing a value argument. */ if (global_close == GLOBAL_CLOSE_ENABLE && close_p != NULL) { 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 (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 (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; } /* * 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; } /* * 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. */ 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; int last_arg_b = ARGV_FALSE; char *close_p = NULL, **arg_p; /* run throught rest of arguments */ for (arg_p = argv; arg_p < argv + arg_c; arg_p++) { /* have we reached the LAST_ARG marker? */ 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_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) { (void)fprintf(argv_error_stream, "%s: %s, empty long-option prefix '%s'\n", argv_program, USAGE_ERROR_NAME, *arg_p); } *okay_bp = ARGV_FALSE; continue; } match_p = NULL; /* 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) { continue; } if (strncmp(*arg_p + LONG_PREFIX_LENGTH, grid_p->ar_long_arg, len) == 0) { if (match_p != 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_bp = ARGV_FALSE; break; } /* record a possible match */ match_p = grid_p; /* don't break, need to see if another one matches */ } } /* 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) { continue; } if (match_p != NULL) { (void)do_arg(grid, match_p, close_p, queue_list, queue_head_p, okay_bp); continue; } /* we did not find long-option match */ /* check for special file value */ 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, queue_list, queue_head_p, queue_tail_p, okay_bp); } else { /* HACK: we enqueue null for the file argument */ 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 || strncmp(HELP_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { do_usage(grid, global_usage); (void)exit(0); } continue; } /* check for special short-usage value */ if (strncmp(USAGE_SHORT_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { do_usage(grid, GLOBAL_USAGE_SHORT); (void)exit(0); } continue; } /* check for special long-usage value */ if (strncmp(USAGE_LONG_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { do_usage(grid, GLOBAL_USAGE_LONG); (void)exit(0); } continue; } /* check for special long-usage value */ if (strncmp(USAGE_ALL_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { do_usage(grid, GLOBAL_USAGE_ALL); (void)exit(0); } continue; } /* check for special help value */ if (strncmp(HELP_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { if (argv_error_stream != 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: %s\n", argv_program, argv_help_string); } } (void)exit(0); } continue; } /* check for special version value */ if (strncmp(VERSION_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { if (argv_error_stream != NULL) { if (argv_version_string == NULL) { (void)fprintf(argv_error_stream, "%s: no version information is available.\n", argv_program); } else { (void)fprintf(argv_error_stream, "%s\n", argv_version_string); } } (void)exit(0); } continue; } /* check for display arguments value */ if (strncmp(DISPLAY_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { if (argv_error_stream != NULL) { display_variables(grid); } (void)exit(0); } continue; } 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_bp = ARGV_FALSE; continue; } /* are we processing a short option? */ 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) { (void)fprintf(argv_error_stream, "%s: %s, empty short-option prefix '%s'\n", argv_program, USAGE_ERROR_NAME, *arg_p); } *okay_bp = ARGV_FALSE; continue; } /* run through the chars in this option */ 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]) { break; } } /* did we not find argument? */ if (match_p->ar_short_arg == ARGV_LAST) { /* check for special usage value */ if ((*arg_p)[SHORT_PREFIX_LENGTH + char_c] == USAGE_CHAR_ARG) { if (argv_interactive) { do_usage(grid, global_usage); (void)exit(0); } 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) { (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_bp = ARGV_FALSE; continue; } 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_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(*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++) { if (grid_p->ar_short_arg == ARGV_MAND && ((! (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 (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++) { if (grid_p->ar_short_arg == ARGV_MAYBE && ((! (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 (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_bp = ARGV_FALSE; } 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 *******************************/ /* * 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. */ 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; /* create the env variable */ (void)sprintf(env_name, ENVIRON_FORMAT, argv_program); /* NOTE: by default the env name is all uppercase */ 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) { return NOERROR; } /* break the list into tokens and do the list */ environ_p = string_copy(environ_p); 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, queue_list, queue_head_p, queue_tail_p, okay_bp); /* free token list */ for (env_c = 0; env_c < env_n; env_c++) { free(vect_p[env_c]); } free(vect_p); } free(environ_p); return NOERROR; } /* * static int process_env * * DESCRIPTION: * * Process the global env variables. * * RETURNS: * * Success - 0 * * Faulure - -1 * * ARGUMENTS: * * None. */ static int process_env(void) { static int done_b = ARGV_FALSE; char *environ, *tok_p, *env_p; int len; /* make sure we only do this once */ if (done_b) { return NOERROR; } done_b = ARGV_TRUE; /* get the argv information */ environ = getenv(GLOBAL_NAME); if (environ == NULL) { return NOERROR; } /* save a copy of it */ environ = string_copy(environ); if (environ == NULL) { return ERROR; } env_p = environ; for (;;) { tok_p = my_strsep(&env_p, " \t,:"); if (tok_p == NULL) { break; } /* skip any empty tokens */ if (*tok_p == '\0') { continue; } len = strlen(GLOBAL_CLOSE); 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(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) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", __FILE__, GLOBAL_NAME, GLOBAL_LASTTOG, tok_p); } } continue; } len = strlen(GLOBAL_ENV); 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(tok_p, "before") == 0) { global_env = GLOBAL_ENV_BEFORE; } else if (strcmp(tok_p, "after") == 0) { global_env = GLOBAL_ENV_AFTER; } else { if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", __FILE__, GLOBAL_NAME, GLOBAL_ENV, tok_p); } } continue; } len = strlen(GLOBAL_ERROR); 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(tok_p, "see") == 0) { global_error = GLOBAL_ERROR_SEE; } else if (strcmp(tok_p, "short") == 0) { global_error = GLOBAL_ERROR_SHORT; } else if (strcmp(tok_p, "shortrem") == 0) { global_error = GLOBAL_ERROR_SHORTREM; } else if (strcmp(tok_p, "long") == 0) { global_error = GLOBAL_ERROR_LONG; } else if (strcmp(tok_p, "all") == 0) { global_error = GLOBAL_ERROR_ALL; } else { if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", __FILE__, GLOBAL_NAME, GLOBAL_ERROR, tok_p); } } continue; } len = strlen(GLOBAL_MULTI); 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(tok_p, "accept") == 0) { global_multi = GLOBAL_MULTI_ACCEPT; } else { if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", __FILE__, GLOBAL_NAME, GLOBAL_MULTI, tok_p); } } continue; } len = strlen(GLOBAL_USAGE); 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(tok_p, "shortrem") == 0) { global_usage = GLOBAL_USAGE_SHORTREM; } else if (strcmp(tok_p, "long") == 0) { global_usage = GLOBAL_USAGE_LONG; } else if (strcmp(tok_p, "all") == 0) { global_usage = GLOBAL_USAGE_ALL; } else { if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", __FILE__, GLOBAL_NAME, GLOBAL_USAGE, tok_p); } } continue; } if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' setting '%s'\n", __FILE__, GLOBAL_NAME, tok_p); } } free(environ); return NOERROR; } /***************************** exported routines *****************************/ /* * 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. */ int argv_process_no_env(argv_t *args, const int arg_c, char **argv) { int arg_n; const char *prog_p; int okay_b = ARGV_TRUE; argv_t *arg_p; argv_t **queue_list=NULL; int queue_head = 0, queue_tail = 0; if (args == NULL) { args = empty; } 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, arg_c); } if (argv_interactive) { (void)exit(EXIT_CODE); } return ERROR; } if (argv == 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) { (void)exit(EXIT_CODE); } return ERROR; } /* set global variables */ argv_argv = argv; 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 != '\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 */ 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, arg_n) != NOERROR) { return ERROR; } /* allocate our value queue */ 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, queue_list, &queue_head, &queue_tail, &okay_b) != NOERROR) { return ERROR; } } /* do the external args */ do_list(args, arg_c - 1, argv + 1, queue_list, &queue_head, &queue_tail, &okay_b); /* DO the env args after? */ if (global_env == GLOBAL_ENV_AFTER) { 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_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 (arg_n > 0) { free(queue_list); } /* was there an error? */ if (! okay_b) { if (argv_error_stream != NULL) { do_usage(args, global_error); } if (argv_interactive) { (void)exit(EXIT_CODE); } return ERROR; } return NOERROR; } /* * 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. */ int argv_process(argv_t *args, const int argc, char **argv) { if (! enabled_b) { argv_startup(); } /* we only process env variables here */ if (process_env() != NOERROR) { return ERROR; } if (argv_process_no_env(args, argc, argv) == NOERROR) { return NOERROR; } else { return ERROR; } } /* * 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 (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; } /* * 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. */ int argv_was_used(const argv_t *args, const char short_arg) { const argv_t *arg_p; if (! enabled_b) { argv_startup(); } 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; } } } return 0; } /* * int argv_long_was_used * * 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. */ int argv_long_was_used(const argv_t *args, const char *long_arg) { const argv_t *arg_p; if (! enabled_b) { argv_startup(); } 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 { return 0; } } } return 0; } /* * 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. */ void argv_cleanup(const argv_t *args) { const argv_t *arg_p; int entry_c; if (! enabled_b) { argv_startup(); } 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_FLAG_ARRAY) { argv_array_t *arr_p = (argv_array_t *)arg_p->ar_variable; /* free any entries */ 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_entry_n = 0; continue; } /* handle individual charps */ if (arg_p->ar_type & ARGV_FLAG_USED && ARGV_TYPE(arg_p->ar_type) == ARGV_CHAR_P) { free(*(char **)arg_p->ar_variable); continue; } } } /* * 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 * * ARGUMENTS: * * buf - Buffer to copy all of the user arguments into. * * buf_size - Size of the buffer. */ int argv_copy_args(char *buf, const int buf_size) { char **argv_p, *buf_p = buf, *arg_p; int arg_c, size_c = buf_size; if (! enabled_b) { argv_startup(); } if (buf_size <= 0) { return NOERROR; } *buf_p = '\0'; if (process_env() != NOERROR) { return ERROR; } if (argv_argv == NULL || buf_size == 1) { return NOERROR; } for (argv_p = argv_argv + 1, arg_c = 1; arg_c < argv_argc; argv_p++, arg_c++) { /* we compare against 2 for the ' ' and the \0 */ if (size_c < 2) { break; } if (argv_p > argv_argv + 1) { *buf_p++ = ' '; 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 = '\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); } @ 1.2 log @Imported libargv version 2.4.0. @ text @d2 3 a4 3 * $Source: /home/cvs/lib/libargv/argv.c,v $ * $Revision: 1.5 $ * $Date: 1999/12/14 14:06:32 $ d109 1 a109 1 char * @ 1.1 log @Initial revision @ text @d2 3 a4 1 * Generic argv processor... d6 2 a7 3 * Copyright 1995 by Gray Watson * * This file is part of the argv library. d17 1 a17 1 * software described herein for any purpose. It is provided "as is" a18 5 * * The author may be contacted at gray.watson@@letters.com * * - Parse command line parameters conveniently. * a24 1 #include d26 2 a27 1 #include "_argv.h" d30 3 a32 2 LOCAL void do_list(argv_t *grid, const int argc, char **argv, char *okay_p); d38 1 a38 1 EXPORT char argv_program[PROGRAM_NAME + 1] = "Unknown"; d41 1 a41 1 EXPORT char **argv_argv = NULL; d43 1 a43 1 EXPORT int argv_argc = 0; d46 1 a46 1 EXPORT char *argv_help_string = NULL; d48 1 a48 1 EXPORT char *argv_version_string = NULL; d54 1 a54 1 EXPORT char argv_interactive = ARGV_TRUE; d60 1 a60 1 EXPORT FILE *argv_error_stream = ERROR_STREAM_INIT; d63 2 a64 3 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? */ d67 6 a72 5 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 */ d77 4 d82 8 d91 1 a91 1 LOCAL void argv_startup(void) d93 1 a93 1 if (enabled) d95 2 a96 1 enabled = ARGV_TRUE; d99 1 a99 1 if (argv_error_stream == ERROR_STREAM_INIT) d101 1 d106 33 d140 13 a152 1 * Binary STR to integer translation d154 1 a154 1 LOCAL int btoi(const char *str) d159 2 a160 1 for (; isspace((int)*str); str++); d171 13 a183 1 * Octal STR to integer translation d185 1 a185 1 LOCAL int otoi(const char *str) d190 2 a191 1 for (; isspace((int)*str); str++); d202 14 a215 1 * Hexadecimal STR to integer translation d217 1 a217 1 LOCAL int htoi(const char *str) d222 2 a223 1 for (; isspace((int)*str); str++); d226 1 a226 1 if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) d228 1 d234 1 a234 1 if (*str >= 'a' && *str <= 'f') d236 2 a237 1 else if (*str >= 'A' && *str <= 'F') d239 2 a240 1 else d242 1 d249 13 a261 1 * Basically a strdup for compatibility sake d263 1 a263 1 LOCAL char *string_copy(const char *ptr) d265 2 a266 2 const char *ptr_p; char *ret, *ret_p; d269 4 a272 4 len = strlen(ptr); ret = (char *)malloc(len + 1); if (ret == NULL) { if (argv_error_stream != NULL) d276 2 a277 1 if (argv_interactive) d279 1 d283 4 a286 3 for (ptr_p = ptr, ret_p = ret; *ptr_p != NULLC;) *ret_p++ = *ptr_p++; *ret_p = NULLC; d288 1 a288 1 return ret; d292 19 a310 2 * Break STR and return an array of char * whose values are tokenized * by TOK. it passes back the number of tokens in TOKN. d312 4 a315 2 * NOTE: the return value should be freed later and the STR should stay * around until that time. d317 1 a317 1 LOCAL char **vectorize(char *str, const char *tok, int *tokn) d320 2 a321 2 char *tmp, *tok_p; int tok_c; d325 1 a325 1 if (tmp == NULL) d327 1 d329 12 a340 3 tok_p = strtok(tmp, tok); for (tok_c = 0; tok_p != NULL; tok_c++) tok_p = strtok(NULL, tok); d343 1 a343 1 *tokn = tok_c; d345 1 a345 1 if (tok_c == 0) d347 1 d352 1 a352 1 if (argv_error_stream != NULL) d356 2 a357 1 if (argv_interactive) d359 1 d364 11 a374 4 vect_p[0] = strtok(str, tok); for (tok_c = 1; tok_c < *tokn; tok_c++) vect_p[tok_c] = strtok(NULL, tok); d380 22 a401 1 * Display printable chars from BUF of SIZE, non-printables as \%03o d403 2 a404 1 LOCAL char *expand_buf(const void *buf, const int size) d406 3 a408 4 static char out[DUMP_SPACE_BUF]; int size_c; void *buf_p; char *out_p; d410 2 a411 3 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; d413 14 a426 3 /* handle special chars */ if (out_p + 2 >= out + sizeof(out)) break; d429 4 a432 2 for (spec_p = SPECIAL_CHARS + 1; *(spec_p - 1) != NULLC; spec_p += 2) if (*spec_p == *(char *)buf_p) d434 2 d438 2 a439 2 if (*(spec_p - 1) != NULLC) { if (out_p + 2 >= out + sizeof(out)) d441 1 d447 3 a449 2 if (*(unsigned char *)buf_p < 128 && isprint((int)(*(char *)buf_p))) { if (out_p + 1 >= out + sizeof(out)) d451 1 d456 1 a456 1 if (out_p + 4 >= out + sizeof(out)) d458 2 a459 1 (void)sprintf(out_p, "\\%03o", *(unsigned char *)buf_p); d464 1 a464 2 *out_p = NULLC; return out; d467 1 d471 4 d476 10 d487 1 a487 1 LOCAL void usage_short(const argv_t *args, const int flag) d491 2 a492 1 char mark = ARGV_FALSE, *prefix; d494 1 a494 1 if (argv_error_stream == NULL) d496 1 d510 1 a510 1 || arg_p->ar_short_arg == ARGV_XOR) d512 1 d515 1 a515 1 if (HAS_ARG(arg_p->ar_type)) d517 1 d520 1 a520 1 if (arg_p->ar_short_arg == NULLC) d522 1 d524 1 a524 1 if (! mark) { d543 1 a543 1 mark = ARGV_TRUE; d562 1 a562 1 if (mark) { d574 1 a574 1 || arg_p->ar_short_arg == ARGV_XOR) d576 1 d579 1 a579 1 if (! HAS_ARG(arg_p->ar_type)) d581 1 d584 2 a585 1 if (ARGV_TYPE(arg_p->ar_type) == ARGV_BOOL_ARG) { d657 1 a657 1 if (flag == GLOBAL_USAGE_SHORTREM) d662 1 d666 20 a685 1 * Display an argument type while keeping track of COL_C. d687 2 a688 2 LOCAL void display_arg(FILE *stream, const argv_t *arg_p, const int max, int *col_c) d692 1 a692 1 if (arg_p->ar_var_label == NULL) d694 2 a695 1 else d697 1 d704 2 d709 1 d711 1 a711 1 (*col_c) += BOOL_ARG_LENGTH; d715 1 a715 2 case ARGV_CHARP: case ARGV_FLOAT: d717 1 d722 2 d727 2 d730 1 a730 1 len = max - *col_c; d732 1 a732 1 *col_c += MIN(len, UNKNOWN_ARG_LENGTH); d735 1 a735 1 len = max - *col_c; d737 1 a737 1 *col_c += MIN(len, var_len); d744 20 a763 1 * Display an option entry ARG_P to STREAM while counting COL_C. d765 1 a765 1 LOCAL void display_option(FILE *stream, const argv_t *arg_p, int *col_c) d767 1 a767 1 if (stream == NULL) d769 1 d772 1 a772 1 (*col_c)++; d778 1 a778 1 *col_c += SHORT_PREFIX_LENGTH + 1; d783 1 a783 1 (*col_c)++; d787 1 a787 1 display_arg(stream, arg_p, LONG_COLUMN - 1, col_c); d789 1 a789 1 (*col_c)++; d793 4 d798 6 d805 1 a805 1 LOCAL void usage_long(const argv_t *args) d810 1 a810 1 if (argv_error_stream == NULL) d812 1 d821 1 a821 1 if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) d823 1 d832 1 a832 1 if (arg_p->ar_short_arg == NULLC) { d837 4 a840 1 if (arg_p->ar_short_arg == ARGV_MAND) d842 3 a844 1 else d846 1 d859 1 a859 1 if (arg_p->ar_short_arg != NULLC) { d866 1 a866 1 col_c += LONG_PREFIX_LENGTH + MIN(len, strlen(arg_p->ar_long_arg)); d870 1 a870 1 if (arg_p->ar_short_arg == NULLC) { d902 16 a917 1 * Do the usage depending on FLAG. d919 1 a919 1 LOCAL void do_usage(const argv_t *args, const int flag) d921 1 a921 1 if (argv_error_stream == NULL) d923 1 d925 1 a925 1 if (flag == GLOBAL_USAGE_SEE) d930 2 a931 1 else if (flag == GLOBAL_USAGE_SHORT || flag == GLOBAL_USAGE_SHORTREM) d933 2 a934 1 else if (flag == GLOBAL_USAGE_LONG || flag == GLOBAL_USAGE_ALL) d936 1 d974 19 a992 2 * Preprocess argument array ARGS of NUM_ARGS entries and set the MAND * and MAYBE boolean arrays. Returns [NO]ERROR. d994 1 a994 1 LOCAL int preprocess_array(argv_t *args, const int num_args) d997 1 a997 1 char mand_array = ARGV_FALSE, maybe_field = ARGV_FALSE; d1000 1 a1000 1 for (arg_p = args; arg_p < args + num_args; arg_p++) { d1007 2 a1008 2 if (mand_array) { if (argv_error_stream != NULL) d1012 2 a1013 1 if (argv_interactive) d1015 1 d1018 2 a1019 2 if (maybe_field) { if (argv_error_stream != NULL) d1023 2 a1024 1 if (argv_interactive) d1026 1 d1030 2 a1031 9 #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; a1032 4 #endif if (arg_p->ar_type & ARGV_ARRAY) mand_array = ARGV_TRUE; d1037 2 a1038 2 if (mand_array) { if (argv_error_stream != NULL) d1042 2 a1043 1 if (argv_interactive) d1045 1 d1049 4 a1052 3 maybe_field = ARGV_TRUE; if (arg_p->ar_type & ARGV_ARRAY) mand_array = ARGV_TRUE; d1056 1 a1056 1 if (arg_p->ar_type & ARGV_ARRAY) { d1060 1 a1060 1 if (argv_error_stream != NULL) d1064 2 a1065 1 if (argv_interactive) d1067 1 d1071 1 a1071 1 if (argv_error_stream != NULL) d1075 2 a1076 1 if (argv_interactive) d1078 1 d1081 1 a1081 13 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; a1082 1 #endif d1088 1 a1088 1 if (argv_error_stream != NULL) d1092 2 a1093 1 if (argv_interactive) d1095 1 d1104 2 a1105 2 if (arg_p == args || arg_p >= (args + num_args - 1)) { if (argv_error_stream != NULL) d1109 2 a1110 1 if (argv_interactive) d1112 1 d1119 1 a1119 1 if (argv_error_stream != NULL) d1123 2 a1124 1 if (argv_interactive) d1126 1 d1136 20 a1155 2 * Translate string argument ARG into VAR depending on its TYPE. * Returns [NO]ERROR. d1157 2 a1158 2 LOCAL int translate_value(const char *arg, ARGV_PNT var, const short type) d1162 1 a1162 1 int val_type = ARGV_TYPE(type), size = 0; d1165 1 a1165 1 for (type_p = argv_types; type_p->at_value != 0; type_p++) d1170 1 d1173 1 a1173 1 if (argv_error_stream != NULL) d1176 1 d1180 1 a1180 1 if (type & ARGV_ARRAY) { d1183 1 a1183 1 if (arr_p->aa_entryn == 0) d1185 2 a1186 1 else if (arr_p->aa_entryn % ARRAY_INCR == 0) d1188 1 a1188 1 (char *)realloc(arr_p->aa_entries, (arr_p->aa_entryn + ARRAY_INCR) * d1190 1 d1193 1 a1193 1 if (argv_error_stream != NULL) d1197 2 a1198 1 if (argv_interactive) d1200 1 d1204 2 a1205 2 var = (char *)(arr_p->aa_entries) + arr_p->aa_entryn * size; arr_p->aa_entryn++; d1213 1 a1213 1 if (arg == NULL) d1215 16 d1233 12 a1244 1 || *(char *)arg == '1') d1246 2 a1247 1 else d1249 1 d1256 1 a1256 1 case ARGV_CHARP: d1258 1 a1258 1 if (*(char **)var == NULL) d1260 1 a1260 4 break; case ARGV_FLOAT: *(float *)var = (float)atof(arg); d1267 4 d1287 8 d1307 71 a1377 4 case ARGV_BOOL_NEG: /* if no close argument, set to false */ if (arg == NULL) *(char *)var = ARGV_FALSE; d1380 6 a1385 4 || *(char *)arg == '1') *(char *)var = ARGV_TRUE; else *(char *)var = ARGV_FALSE; d1388 13 a1400 6 case ARGV_INCR: /* if no close argument then increment else set the value */ if (arg == NULL) (*(int *)var)++; else *(int *)var = atoi(arg); d1403 1 a1403 1 case ARGV_BOOL_ARG: d1406 6 a1411 4 || *(char *)arg == '1') *(char *)var = ARGV_TRUE; else *(char *)var = ARGV_FALSE; d1413 1 d1420 20 a1439 1 * Translate value from VAR into string STR depending on its TYPE. d1441 2 a1442 1 LOCAL void display_value(const ARGV_PNT var, const short type) d1444 6 a1449 1 int val_type = ARGV_TYPE(type); d1452 1 a1452 1 switch (val_type) { d1457 8 a1464 4 if (*(char *)var) (void)fprintf(argv_error_stream, "ARGV_TRUE"); else (void)fprintf(argv_error_stream, "ARGV_FALSE"); d1468 1 a1468 1 (void)fprintf(argv_error_stream, "'%s'", expand_buf((char *)var, 1)); d1471 8 a1478 10 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)); } d1482 3 a1484 2 case ARGV_FLOAT: (void)fprintf(argv_error_stream, "%f", *(float *)var); d1487 3 a1489 2 case ARGV_SHORT: (void)fprintf(argv_error_stream, "%d", *(short *)var); d1493 2 a1494 2 case ARGV_INCR: (void)fprintf(argv_error_stream, "%d", *(int *)var); d1498 2 a1499 1 (void)fprintf(argv_error_stream, "%u", *(unsigned int *)var); d1503 2 a1504 1 (void)fprintf(argv_error_stream, "%ld", *(long *)var); d1508 12 a1519 1 (void)fprintf(argv_error_stream, "%lu", *(unsigned long *)var); d1525 2 a1526 2 int bit_c; char first = ARGV_FALSE; d1528 4 a1531 1 (void)fputc('0', argv_error_stream); d1533 3 a1535 2 if (*(int *)var != 0) { (void)fputc('b', argv_error_stream); d1538 1 a1538 1 int bit = *(int *)var & (1 << bit_c); d1541 3 a1543 2 if (first) (void)fputc('0', argv_error_stream); d1546 2 a1547 2 (void)fputc('1', argv_error_stream); first = ARGV_TRUE; d1550 9 d1560 3 d1567 8 a1574 1 (void)fprintf(argv_error_stream, "%#o", *(int *)var); d1578 85 a1662 1 (void)fprintf(argv_error_stream, "%#x", *(int *)var); d1665 2 d1670 14 a1683 1 * Translate value from VAR into string STR depending on its TYPE. d1685 1 a1685 1 LOCAL void display_variables(const argv_t *args) d1689 2 d1694 2 a1695 1 int col_c, val_type = ARGV_TYPE(arg_p->ar_type); d1698 1 a1698 1 if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) d1700 1 d1703 15 a1717 1 if (arg_p->ar_short_arg == ARGV_MAND) d1719 3 a1721 1 else d1723 1 d1736 1 a1736 1 int len, tlen; d1742 1 a1742 1 if (arg_p->ar_type & ARGV_ARRAY) { d1756 1 a1756 1 if (arg_p->ar_type & ARGV_ARRAY) { d1769 1 a1769 1 if (arr_p->aa_entryn == 0) d1771 1 d1773 1 a1773 1 for (entry_c = 0; entry_c < arr_p->aa_entryn; entry_c++) { d1775 1 a1775 1 if (entry_c > 0) d1777 1 d1779 2 a1780 1 display_value(var, val_type); d1784 4 a1787 2 else display_value(arg_p->ar_variable, val_type); d1795 19 a1813 2 * Check out if WHICH argument from ARGS has an *or* specified * attached to it. Returns [NO]ERROR d1815 1 a1815 1 LOCAL int check_or(const argv_t *args, const argv_t *which) d1820 1 a1820 1 for (arg_p = which - 2; arg_p >= args; arg_p -= 2) { d1822 1 a1822 1 && (arg_p + 1)->ar_short_arg != ARGV_XOR) d1824 1 d1833 2 a1834 2 /* NOTE: we assume that which is not pointing now to ARGV_LAST */ for (arg_p = which + 2; d1839 1 a1839 1 && (arg_p - 1)->ar_short_arg != ARGV_XOR) d1841 1 d1850 1 a1850 1 if (match_p == NULL) d1852 1 d1854 1 a1854 1 if (argv_error_stream == NULL) d1856 1 d1864 3 a1866 2 if (match_p->ar_long_arg == NULL) (void)fprintf(argv_error_stream, " %s%c\n", d1868 4 a1871 2 else (void)fprintf(argv_error_stream, " %s%c (%s%s)\n", d1874 1 d1876 1 a1876 1 if (match_p == which) d1878 2 a1879 1 match_p = which; d1886 19 a1904 2 * Find all the XOR arguments and make sure each group has at least * one specified in it. Returns [NO]ERROR. d1906 1 a1906 1 LOCAL int check_xor(const argv_t *args) d1914 1 a1914 1 if (arg_p->ar_short_arg != ARGV_XOR) d1916 1 d1924 1 a1924 1 if ((arg_p - 1)->ar_type & ARGV_FLAG_USED) d1926 1 d1931 1 a1931 1 if (arg_p->ar_type & ARGV_FLAG_USED) d1933 2 a1934 1 if ((arg_p + 1)->ar_short_arg != ARGV_XOR) d1936 1 d1941 1 a1941 1 if (start_p != NULL) d1943 1 d1947 1 a1947 1 if (start_p == NULL) d1949 1 d1952 1 a1952 1 if (argv_error_stream == NULL) d1954 1 d1964 2 a1965 1 (void)fprintf(argv_error_stream, " %s%c", d1967 1 a1967 1 if ((arg_p - 1)->ar_long_arg != NULL) d1970 1 d1973 1 a1973 1 if (arg_p->ar_short_arg != ARGV_XOR) d1975 1 d1982 16 a1997 1 * Check to see if any mandatory arguments left. Returns [NO]ERROR. d1999 1 a1999 1 LOCAL int check_mand(const argv_t *args) d2002 1 a2002 1 int slot_c = 0; d2005 1 a2005 1 for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) d2007 30 a2036 3 && (! (arg_p->ar_type & ARGV_FLAG_USED)) && ! (arg_p->ar_type & ARGV_ARRAY)) slot_c++; d2038 1 a2038 6 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")); d2041 3 a2043 2 return NOERROR; d2047 17 a2063 1 * Check for any missing argument options. Returns [NO]ERROR d2065 1 a2065 1 LOCAL int check_opt(void) d2069 1 a2069 1 queue_c = QUEUE_COUNT(); d2071 1 a2071 1 if (argv_error_stream != NULL) d2076 1 d2086 29 a2114 2 * Read in arguments from PATH and run them from the GRID. OKAY_P is * a pointer to the boolean error marker. Returns [NO]ERROR. d2116 3 a2118 1 LOCAL void file_args(const char *path, argv_t *grid, char *okay_p) d2121 1 a2121 1 int argc, max; d2128 2 a2129 2 *okay_p = ARGV_FALSE; if (argv_error_stream != NULL) d2133 2 a2134 1 if (argv_interactive) d2136 1 d2141 1 a2141 1 argc = 0; d2145 1 a2145 1 *okay_p = ARGV_FALSE; d2147 1 a2147 1 if (argv_error_stream != NULL) d2151 2 a2152 1 if (argv_interactive) d2154 1 d2162 2 a2163 1 for (line_p = line; *line_p != '\n' && *line_p != '\0'; line_p++); d2168 1 a2168 1 *okay_p = ARGV_FALSE; d2173 2 a2174 2 argc++; if (argc == max) { d2178 1 a2178 1 *okay_p = ARGV_FALSE; d2180 1 a2180 1 if (argv_error_stream != NULL) d2184 2 a2185 1 if (argv_interactive) d2187 1 d2190 1 a2190 1 argv_p = argv + argc; d2195 1 a2195 1 do_list(grid, argc, argv, okay_p); d2198 1 a2198 1 for (argv_p = argv; argv_p < argv + argc; argv_p++) d2200 1 d2207 28 a2234 2 * Process an argument in MATCH_P which looking at GRID. sets okay_p to * FALSE if the argument was not okay. d2236 2 a2237 2 LOCAL void do_arg(argv_t *grid, argv_t *match_p, const char *close_p, char *okay_p) d2245 1 a2245 1 && (! (match_p->ar_type & ARGV_ARRAY)) d2247 1 a2247 1 if (argv_error_stream != NULL) d2252 2 a2253 1 *okay_p = ARGV_FALSE; d2266 1 a2266 1 *okay_p = ARGV_FALSE; d2275 4 a2278 3 if (translate_value(close_p, match_p->ar_variable, match_p->ar_type) != NOERROR) *okay_p = ARGV_FALSE; d2281 4 a2284 3 if (translate_value(NULL, match_p->ar_variable, match_p->ar_type) != NOERROR) *okay_p = ARGV_FALSE; d2287 48 a2334 3 if (translate_value(close_p, match_p->ar_variable, match_p->ar_type) != NOERROR) *okay_p = ARGV_FALSE; d2336 2 a2337 2 else QUEUE_ENQUEUE(match_p); d2341 28 a2368 3 * 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. d2370 3 a2372 2 LOCAL void do_list(argv_t *grid, const int argc, char **argv, char *okay_p) d2376 1 a2376 1 char last_arg = ARGV_FALSE; d2380 1 a2380 1 for (arg_p = argv; arg_p < argv + argc; arg_p++) { d2383 10 a2392 12 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++; d2397 17 a2413 1 if (! last_arg && strncmp(LONG_PREFIX, *arg_p, LONG_PREFIX_LENGTH) == 0) { d2420 1 a2420 1 if (argv_error_stream != NULL) d2424 2 a2425 1 *okay_p = ARGV_FALSE; d2433 1 a2433 1 if (grid_p->ar_long_arg == NULL) d2435 1 d2440 1 a2440 1 if (argv_error_stream != NULL) d2445 2 a2446 1 *okay_p = ARGV_FALSE; d2458 1 a2458 1 if (match_p != NULL && grid_p->ar_short_arg != ARGV_LAST) d2460 1 d2463 2 a2464 1 (void)do_arg(grid, match_p, close_p, okay_p); d2474 2 a2475 1 file_args(close_p, grid, okay_p); d2479 2 a2480 1 QUEUE_ENQUEUE(NULL); d2486 2 a2487 1 if (strncmp(USAGE_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { d2526 1 a2526 1 if (argv_help_string == NULL) d2530 5 a2534 2 else (void)fprintf(argv_error_stream, "%s\n", argv_help_string); d2545 1 a2545 1 if (argv_version_string == NULL) d2549 2 a2550 1 else d2552 1 d2562 1 a2562 1 if (argv_error_stream != NULL) d2564 1 d2570 1 a2570 1 if (argv_error_stream != NULL) d2574 2 a2575 1 *okay_p = ARGV_FALSE; d2580 1 a2580 1 if (! last_arg d2583 15 d2603 1 a2603 1 if (argv_error_stream != NULL) d2607 2 a2608 1 *okay_p = ARGV_FALSE; d2616 3 a2618 2 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]) d2620 2 d2635 32 d2668 1 a2668 1 if (argv_error_stream != NULL) d2673 2 a2674 1 *okay_p = ARGV_FALSE; d2678 1 a2678 1 do_arg(grid, match_p, close_p, okay_p); d2685 6 a2690 2 if (grid->ar_short_arg != ARGV_LAST && QUEUE_COUNT() > 0) { QUEUE_DEQUEUE(match_p); d2692 10 a2701 6 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; d2706 1 a2706 1 for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) d2708 2 a2709 1 && (! (grid_p->ar_type & ARGV_FLAG_USED))) d2711 2 d2715 5 a2719 5 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; d2724 1 a2724 1 for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) d2726 2 a2727 1 && (! (grid_p->ar_type & ARGV_FLAG_USED))) d2729 2 d2733 5 a2737 5 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; d2743 1 a2743 1 *okay_p = ARGV_FALSE; d2746 1 a2746 1 if (unwant_c > 0 && argv_error_stream != NULL) d2751 1 d2757 26 a2782 1 * Handle the args from the ENV variable. Returns [NO]ERROR. d2784 2 a2785 1 LOCAL int do_env_args(argv_t *args, char *okay_p) d2794 2 a2795 2 for (environ_p = env_name; *environ_p != NULLC; environ_p++) if (islower((int)*environ_p)) d2797 2 d2801 1 a2801 1 if (environ_p == NULL) d2803 1 d2807 1 a2807 1 if (environ_p == NULL) d2809 1 d2813 2 a2814 1 do_list(args, env_n, vect_p, okay_p); d2817 1 a2817 1 for (env_c = 0; env_c < env_n; env_c++) d2819 1 d2828 15 a2842 1 * Process the global env variable. Returns [NO]ERROR. d2844 1 a2844 1 LOCAL int process_env(void) d2846 2 a2847 2 static char done = ARGV_FALSE; char *environ_p, *env_p, *arg; d2851 1 a2851 1 if (done) d2853 1 d2855 1 a2855 1 done = ARGV_TRUE; d2858 2 a2859 2 environ_p = getenv(GLOBAL_NAME); if (environ_p == NULL) d2861 1 d2864 2 a2865 2 environ_p = string_copy(environ_p); if (environ_p == NULL) d2867 1 d2869 1 a2869 1 arg = environ_p; d2872 2 a2873 2 env_p = strtok(arg, " \t,:"); if (env_p == NULL) d2875 5 a2879 1 arg = NULL; d2882 6 a2887 3 if (strncmp(GLOBAL_CLOSE, env_p, len) == 0) { env_p += len; if (strcmp(env_p, "disable") == 0) d2889 5 a2893 1 else if (strcmp(env_p, "enable") == 0) d2895 26 d2922 1 a2922 1 if (argv_error_stream != NULL) d2925 2 a2926 1 __FILE__, GLOBAL_NAME, GLOBAL_CLOSE, env_p); d2932 3 a2934 3 if (strncmp(GLOBAL_ENV, env_p, len) == 0) { env_p += len; if (strcmp(env_p, "none") == 0) d2936 2 a2937 1 else if (strcmp(env_p, "before") == 0) d2939 2 a2940 1 else if (strcmp(env_p, "after") == 0) d2942 1 d2944 1 a2944 1 if (argv_error_stream != NULL) d2947 2 a2948 1 __FILE__, GLOBAL_NAME, GLOBAL_ENV, env_p); d2954 3 a2956 3 if (strncmp(GLOBAL_ERROR, env_p, len) == 0) { env_p += len; if (strcmp(env_p, "none") == 0) d2958 2 a2959 1 else if (strcmp(env_p, "see") == 0) d2961 2 a2962 1 else if (strcmp(env_p, "short") == 0) d2964 2 a2965 1 else if (strcmp(env_p, "shortrem") == 0) d2967 2 a2968 1 else if (strcmp(env_p, "long") == 0) d2970 2 a2971 1 else if (strcmp(env_p, "all") == 0) d2973 1 d2975 1 a2975 1 if (argv_error_stream != NULL) d2978 2 a2979 1 __FILE__, GLOBAL_NAME, GLOBAL_ERROR, env_p); d2985 3 a2987 3 if (strncmp(GLOBAL_MULTI, env_p, len) == 0) { env_p += len; if (strcmp(env_p, "reject") == 0) d2989 2 a2990 1 else if (strcmp(env_p, "accept") == 0) d2992 1 d2994 1 a2994 1 if (argv_error_stream != NULL) d2997 2 a2998 1 __FILE__, GLOBAL_NAME, GLOBAL_MULTI, env_p); d3004 3 a3006 3 if (strncmp(GLOBAL_USAGE, env_p, len) == 0) { env_p += len; if (strcmp(env_p, "short") == 0) d3008 2 a3009 1 else if (strcmp(env_p, "shortrem") == 0) d3011 2 a3012 1 else if (strcmp(env_p, "long") == 0) d3014 2 a3015 1 else if (strcmp(env_p, "all") == 0) d3017 1 d3019 1 a3019 1 if (argv_error_stream != NULL) d3022 2 a3023 1 __FILE__, GLOBAL_NAME, GLOBAL_USAGE, env_p); d3028 1 a3028 1 if (argv_error_stream != NULL) d3031 2 a3032 1 __FILE__, GLOBAL_NAME, env_p); d3035 1 a3035 1 free(environ_p); d3039 2 d3042 21 a3062 1 * Processes ARGS from ARGC and ARGV. Returns 0 if no error else -1. d3064 1 a3064 1 LOCAL int process_args(argv_t *args, const int argc, char **argv) d3066 1 a3066 1 int num_args; d3068 1 a3068 1 char okay = ARGV_TRUE; d3070 2 d3073 1 a3073 4 if (process_env() != NOERROR) return ERROR; if (args == NULL) d3075 1 d3077 2 a3078 2 if (argc < 0) { if (argv_error_stream != NULL) d3081 3 a3083 2 __FILE__, INTERNAL_ERROR_NAME, argc); if (argv_interactive) d3085 1 d3090 1 a3090 1 if (argv_error_stream != NULL) d3094 2 a3095 1 if (argv_interactive) d3097 1 d3103 1 a3103 1 argv_argc = argc; d3110 2 a3111 2 for (tmp_p = *argv; *tmp_p != NULLC; tmp_p++) if (*tmp_p == '/') d3113 2 d3121 4 a3124 3 num_args = 0; for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) num_args++; d3127 1 a3127 1 if (preprocess_array(args, num_args) != NOERROR) d3129 1 d3132 9 a3140 2 if (num_args > 0) QUEUE_ALLOC(argv_t *, num_args); d3144 2 a3145 1 if (do_env_args(args, &okay) != NOERROR) d3147 1 d3151 2 a3152 1 do_list(args, argc - 1, argv + 1, &okay); d3154 1 a3154 1 /* do the env args after? */ d3156 2 a3157 2 do_env_args(args, &okay); if (do_env_args(args, &okay) != NOERROR) d3159 1 d3163 9 a3171 6 if (check_mand(args) != NOERROR) okay = ARGV_FALSE; if (check_opt() != NOERROR) okay = ARGV_FALSE; if (check_xor(args) != NOERROR) okay = ARGV_FALSE; d3174 3 a3176 2 if (num_args > 0) QUEUE_FREE(); d3179 2 a3180 2 if (! okay) { if (argv_error_stream != NULL) d3182 2 a3183 1 if (argv_interactive) d3185 1 a3191 2 /***************************** exported routines *****************************/ d3193 6 a3198 3 * 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. d3202 9 d3212 1 a3212 1 EXPORT int argv_process(argv_t *args, const int argc, char **argv) d3214 1 a3214 1 if (! enabled) d3216 6 d3223 1 a3223 1 if (process_args(args, argc, argv) == NOERROR) d3225 2 a3226 1 else d3228 1 d3232 28 a3259 19 * 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) d3261 1 d3263 1 a3263 14 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); d3267 2 a3268 12 /* 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); return ERROR; d3271 2 a3272 10 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; d3274 2 a3275 18 /* 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; d3277 3 a3279 87 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; d3282 1 a3282 9 ret = process_args(args, argc, argv); free(copy); free(argv); if (ret == NOERROR) return NOERROR; else return ERROR; d3286 15 a3300 3 * 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. d3302 1 a3302 1 EXPORT int argv_web_process(argv_t *args, const char *arg0) d3304 1 a3304 2 char *env, *work = NULL; int ret, len; d3306 1 a3306 1 if (! enabled) d3308 1 d3310 4 a3313 18 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; d3315 2 a3316 17 } } 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; a3317 6 work[0] = NULLC; } else { work = string_copy(env); if (work == NULL) return ERROR; d3321 1 a3321 7 ret = argv_web_process_string(args, arg0, work, "&="); free(work); if (ret == NOERROR) return NOERROR; else return ERROR; d3325 3 a3327 3 * 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). d3329 11 a3339 28 * 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. d3341 1 a3341 1 EXPORT int argv_was_used(const argv_t *args, const char arg) d3345 1 a3345 1 if (! enabled) d3347 1 d3349 3 a3351 3 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) d3353 2 a3354 1 else d3356 1 d3358 1 d3364 5 a3368 1 * Frees up any allocations in ARGS that may have been done by d3371 8 d3380 1 a3380 1 EXPORT void argv_cleanup(const argv_t *args) d3385 1 a3385 1 if (! enabled) d3387 1 d3389 1 a3389 1 if (args == NULL) d3391 1 d3396 1 a3396 1 if (arg_p->ar_type & ARGV_ARRAY) { d3400 3 a3402 3 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++) d3404 1 d3409 1 a3409 1 arr_p->aa_entryn = 0; d3415 1 a3415 1 && ARGV_TYPE(arg_p->ar_type) == ARGV_CHARP) { d3423 11 a3433 2 * Copy all the args (after the 0th), one after the other, into BUF of * MAX_SIZE. Returns 0 on no error else -1. d3435 9 a3443 1 * NOTE: you can get the 0th argument from argv_argv[0]. d3445 1 a3445 1 EXPORT int argv_copy_args(char *buf, const int max_size) d3448 1 a3448 1 int argc, size_c = max_size; d3450 1 a3450 1 if (! enabled) d3452 1 d3454 3 a3456 2 if (process_env() != NOERROR) return ERROR; d3458 1 a3458 2 if (max_size == 0) return NOERROR; d3460 3 a3462 1 *buf_p = NULLC; d3464 1 a3464 1 if (argv_argv == NULL || max_size == 1) d3466 1 d3468 3 a3470 1 for (argv_p = argv_argv + 1, argc = 1; argc < argv_argc; argv_p++, argc++) { d3472 2 a3473 1 if (size_c < 2) d3475 1 d3482 2 a3483 1 for (arg_p = *argv_p; *arg_p != NULLC && size_c >= 2; size_c--) d3485 1 d3488 1 a3488 1 *buf_p = NULLC; d3490 31 @ 1.1.1.1 log @Imported Petidomo 2.2 as found on www.petidomo.com. @ text @@