From b9c9b4eb68af4536825b7dbca5bae36584b1c5be Mon Sep 17 00:00:00 2001 From: Peter Simons Date: Wed, 13 Dec 2000 15:37:35 +0000 Subject: [PATCH] Imported libargv version 2.4.0. --- libargv/Makefile | 67 - libargv/Makefile.inc | 11 - libargv/NEWS | 115 ++ libargv/SMakefile | 18 + libargv/argv.c | 2948 +++++++++++++++++++++---------- libargv/argv.h | 460 ++++- libargv/argv.texi | 833 +++++++++ libargv/argvSetDebugLevel.c | 91 +- libargv/{_argv.h => argv_loc.h} | 122 +- libargv/configure.in | 46 + libargv/test.c | 76 +- 11 files changed, 3541 insertions(+), 1246 deletions(-) delete mode 100644 libargv/Makefile delete mode 100644 libargv/Makefile.inc create mode 100644 libargv/NEWS create mode 100644 libargv/SMakefile create mode 100644 libargv/argv.texi rename libargv/{_argv.h => argv_loc.h} (75%) create mode 100644 libargv/configure.in diff --git a/libargv/Makefile b/libargv/Makefile deleted file mode 100644 index bd2023f..0000000 --- a/libargv/Makefile +++ /dev/null @@ -1,67 +0,0 @@ -# -# libargv Makefile -# -# $Header$ -# - -# Make Rules: -# =========== -# -.c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< - - -# Compiler Flags: -# =============== -# -CFLAGS = -Wall -ansi -pedantic -CPPFLAGS= - - -# -# Labels: -# ======= -# -SRCS = argv.c -OBJS = $(SRCS:.c=.o) -MANFILES= $(SRCS:.c=.3) - - -# -# Targets -# -.PHONY: all clean realclean distclean man depend - -all: libargv.a - -test: test.o libargv.a - $(CC) test.o libargv.a -o test - -clean: - rm -f test libargv.a *.o *.3 *.core - -realclean: clean - -distclean: realclean - -man: - -depend: - makedepend -Y /usr/include $(SRCS) - @rm -f Makefile.bak - - -# -# Actions -# -libargv.a: $(OBJS) - rm -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - - -# -# Dependencies -# - -argv.o: _argv.h argv.h diff --git a/libargv/Makefile.inc b/libargv/Makefile.inc deleted file mode 100644 index eb05518..0000000 --- a/libargv/Makefile.inc +++ /dev/null @@ -1,11 +0,0 @@ -# -# libargv -# -# $Id$ -# - -./libargv.a: ./argv.o - $(AR) cr $@ ./argv.o - $(RANLIB) $@ - -./argv.o: ./argv.c ./_argv.h ./argv.h diff --git a/libargv/NEWS b/libargv/NEWS new file mode 100644 index 0000000..51ef83f --- /dev/null +++ b/libargv/NEWS @@ -0,0 +1,115 @@ +------------------------------------------------------------------------------- +$Id$ +------------------------------------------------------------------------------- + +Version 2.4.0: + + * Migrated the web support functions out to argv_web.[ch]. + * Made a number of general code cleaning, format updating improvements. + * Added argv_value_string function to convert a variable into string. + * Added support for negative numbers. + +Version 2.3.1: + + * Added ARGV_FLAG_MAND which is used to set any option as mandatory. + * Renamed ARGV_ARRAY to be ARGV_FLAG_ARRAY. + * Fixed --argv-file to handle non close arguments. + * We now allow mandatory boolean args. + * Added ARGV_SIZE and ARGV_U_SIZE and renumbered the types. + * Updated the docs a tad. + * Renamed ARGV_CHARP to ARGV_CHAR_P. + +Version 2.3.0: + + * Renamed aa_entryn aa_entry_n. + * Added new ARGV_SIZE type to handle 10k and 15m. + * Added other enable/disable forms: yes/no, on/off, 1/0. + * Added lasttog env setting to have -- toggle last-arg on/off. + +Version 2.2.0: + + * Added --argv-file functionality. + * Improved usage message handing. + * Added argv_interactive flag which will exit on errors. + * Added argv_error_stream which can be set to FILE * were errors go. + * Removed some unresolved references: strcasecmp, strdup. + * Fixed some porting problems to Unixware. Unsigned chars. + * Improved the non-interactive workings of the library. + +Version 2.0.2: + + * CHARP types now strdup'd and then freed. + * Added BOOL_ARG for a variable which expects a yes or no. + * Added U_INT and U_LONG arg variable types. + * Re-added --usage-all for printing all the available options. + * Added web argument processing of environmental variables. + +Version 2.0.1: + + * Fixed a bug with XOR processing. + * Added ARGV_INCR variable type which increments variable. + * Improved some of the configuration for strings, etc. + * Added displaying of type and value with --argv-display. + +Version 2.0.0: + + * Added some new/better sections to the manual. + * Added new --argv-display routine to dump argument values. + * argv_shell initial version working for shell scripts. + * Added argv_was_used() call using the in structure used flag. + * Added better mechanisms for const definition. + * Finally added the env variable processing for GLOBAL_ARGV. + +Version 1.2.2: + + * Inlined version.h into argv.h + * Added new configure cc-ansi macro. + +Version 1.2.1: + + * Updated the manual a bit. + * Fixed problems with STDC arguments. + * Simplified the including of argv files into other modules. + * Merged in most external files into argv.c, argv.h, argv_loc.h + +Version 1.2.0: + + * minor fixes + +Version 1.1.9: + + * added argv_copy_args() + * added argv_argv and argv_argc global variables + * removed argv_zero + +Version 1.1.8: + + * More compatibility functions added. + +Version 1.1.7: + + * Added the ability to take NULL arg arrays. + +Version 1.1.6: + + * Worked on manual README and other notes files. + * Added ARGV_XOR functionality. + * Added -D=5 functionality. + * Removed LGPL copyright and put in its place fully free notices. + +Version 1.1.5: + + * Added ARGV_BOOL_NEG for booleans that get set to false if used. + * Added lots of files and configuration scripts. + * Added ARGV_MAYBE and probably some creepy crawlies. + +Version 1.1.3: + + * Removed ARGV_MORE and ARGV_PROCESS and argv_process now returns void. + * Fixed up default printing of long special-options. + +Version 1.1.2: + + * Added short-option help. + * Added array processing. Moved arg_t -> argv_t. + * Finally complete de-local'izing the code. diff --git a/libargv/SMakefile b/libargv/SMakefile new file mode 100644 index 0000000..634eda7 --- /dev/null +++ b/libargv/SMakefile @@ -0,0 +1,18 @@ +# +# Skeleton Makefile -- process with smake to create real Makefile. +# +# $Header$ +# +.opt -o GNUmakefile.in + +LIBRARY = argv +SRCS = argv.c + +.include +.include + +test: test.o libargv.a + $(CC) $(LDFLAGS) -o $@ $^ + +clean-local:: + rm -f test test.o diff --git a/libargv/argv.c b/libargv/argv.c index 7fc5ff1..ced409b 100644 --- a/libargv/argv.c +++ b/libargv/argv.c @@ -1,9 +1,10 @@ /* - * Generic argv processor... + * $Source$ + * $Revision$ + * $Date$ * - * Copyright 1995 by Gray Watson - * - * This file is part of the argv library. + * Copyright (c) 1999 by Gray Watson . + * All rights reserved. * * Permission to use, copy, modify, and distribute this software for * any purpose and without fee is hereby granted, provided that the @@ -13,94 +14,150 @@ * without specific, written prior permission. * * Gray Watson makes no representations about the suitability of the - * software described herein for any purpose. It is provided "as is" + * software described herein for any purpose. It is provided "as is" * without express or implied warranty. - * - * The author may be contacted at gray.watson@letters.com - * - * - Parse command line parameters conveniently. - * */ #include #include #include #include -#include -#include "_argv.h" +#include "argv.h" +#include "argv_loc.h" /* internal routines */ -LOCAL void do_list(argv_t *grid, const int argc, char **argv, - char *okay_p); +static void do_list(argv_t *grid, const int arg_c, char **argv, + argv_t **queue_list, int *queue_head_p, + int *queue_tail_p, int *okay_bp); /* * exported variables */ /* This is a processed version of argv[0], pre-path removed: /bin/ls -> ls */ -EXPORT char argv_program[PROGRAM_NAME + 1] = "Unknown"; +char argv_program[PROGRAM_NAME + 1] = "Unknown"; /* A global value of argv from main after argv_process has been called */ -EXPORT char **argv_argv = NULL; +char **argv_argv = NULL; /* A global value of argc from main after argv_process has been called */ -EXPORT int argv_argc = 0; +int argv_argc = 0; /* This should be set externally to provide general program help to user */ -EXPORT char *argv_help_string = NULL; +char *argv_help_string = NULL; /* This should be set externally to provide version information to the user */ -EXPORT char *argv_version_string = NULL; +char *argv_version_string = NULL; /* * Are we running interactively? This will exit on errors. Set to * false to return error codes instead. */ -EXPORT char argv_interactive = ARGV_TRUE; +int argv_interactive = ARGV_TRUE; /* * The FILE stream that argv out_puts all its errors. Set to NULL to * not dump any error messages. Default is stderr. */ -EXPORT FILE *argv_error_stream = ERROR_STREAM_INIT; +FILE *argv_error_stream = ERROR_STREAM_INIT; /* local variables */ -LOCAL_QUEUE_DECLARE(argv_t *); /* args waiting for values */ -LOCAL argv_t empty[] = {{ ARGV_LAST }}; /* empty argument array */ -LOCAL char enabled = ARGV_FALSE; /* are the lights on? */ +static argv_t empty[] = {{ ARGV_LAST }}; /* empty argument array */ +static int enabled_b = ARGV_FALSE; /* are the lights on? */ /* global settings */ -LOCAL int global_close = GLOBAL_CLOSE_ENABLE; /* close processing */ -LOCAL int global_env = GLOBAL_ENV_BEFORE; /* env processing */ -LOCAL int global_error = GLOBAL_ERROR_SEE; /* error processing */ -LOCAL int global_multi = GLOBAL_MULTI_ACCEPT; /* multi processing */ -LOCAL int global_usage = GLOBAL_USAGE_LONG; /* usage processing */ +static int global_close = GLOBAL_CLOSE_ENABLE; /* close processing */ +static int global_env = GLOBAL_ENV_BEFORE; /* env processing */ +static int global_error = GLOBAL_ERROR_SEE; /* error processing */ +static int global_multi = GLOBAL_MULTI_ACCEPT; /* multi processing */ +static int global_usage = GLOBAL_USAGE_LONG; /* usage processing */ +static int global_lasttog = GLOBAL_LASTTOG_DISABLE; /*last-arg toggling*/ /****************************** startup routine ******************************/ /* + * static void argv_startup + * + * DESCRIPTION: + * * Turn on the lights. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * None. */ -LOCAL void argv_startup(void) +static void argv_startup(void) { - if (enabled) + if (enabled_b) { return; - enabled = ARGV_TRUE; + } + enabled_b = ARGV_TRUE; /* ANSI says we cannot predefine this above */ - if (argv_error_stream == ERROR_STREAM_INIT) + if (argv_error_stream == ERROR_STREAM_INIT) { argv_error_stream = stderr; + } } /***************************** general utilities *****************************/ + +/*** ET: BSD's strsep funktion. See their man-page... ***/ + +char * +my_strsep(char **stringp, const char *delim) +{ + register char *s; + register const char *spanp; + register int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return NULL; + for (tok = s;;) + { + c = *s++; + spanp = delim; + do + { + if ((sc = *spanp++) == c) + { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return tok; + } + } while (sc != 0); + } + /* NOTREACHED */ +} + /* - * Binary STR to integer translation + * static int btoi + * + * DESCRIPTION: + * + * Binary string to integer translation. + * + * RETURNS: + * + * Integer converted from the string. + * + * ARGUMENTS: + * + * str - String of binary 0s and 1s that we are converting. */ -LOCAL int btoi(const char *str) +static int btoi(const char *str) { int ret = 0; /* strip off spaces */ - for (; isspace((int)*str); str++); + for (; isspace((int)*str); str++) { + } for (; *str == '0' || *str == '1'; str++) { ret *= 2; @@ -111,14 +168,27 @@ LOCAL int btoi(const char *str) } /* - * Octal STR to integer translation + * static int otoi + * + * DESCRIPTION: + * + * Octal string to integer translation. + * + * RETURNS: + * + * Integer converted from the string. + * + * ARGUMENTS: + * + * str - String of octal digits that we are converting. */ -LOCAL int otoi(const char *str) +static int otoi(const char *str) { int ret = 0; /* strip off spaces */ - for (; isspace((int)*str); str++); + for (; isspace((int)*str); str++) { + } for (; *str >= '0' && *str <= '7'; str++) { ret *= 8; @@ -129,174 +199,301 @@ LOCAL int otoi(const char *str) } /* - * Hexadecimal STR to integer translation + * static int htoi + * + * DESCRIPTION: + * + * Hexadecimal string to integer translation. + * + * RETURNS: + * + * Integer converted from the string. + * + * ARGUMENTS: + * + * str - String of hexadecimal characters and digits that we are + * converting. */ -LOCAL int htoi(const char *str) +static int htoi(const char *str) { int ret = 0; /* strip off spaces */ - for (; isspace((int)*str); str++); + for (; isspace((int)*str); str++) { + } /* skip a leading 0[xX] */ - if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) + if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) { str += 2; + } for (; isdigit((int)*str) || (*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F'); str++) { ret *= 16; - if (*str >= 'a' && *str <= 'f') + if (*str >= 'a' && *str <= 'f') { ret += *str - 'a' + 10; - else if (*str >= 'A' && *str <= 'F') + } + else if (*str >= 'A' && *str <= 'F') { ret += *str - 'A' + 10; - else + } + else { ret += *str - '0'; + } } return ret; } /* - * Basically a strdup for compatibility sake + * static char *string_copy + * + * DESCRIPTION: + * + * Basically a strdup for compatibility sake. + * + * RETURNS: + * + * Character pointer that must be freed later. + * + * ARGUMENTS: + * + * str - String we are copying. */ -LOCAL char *string_copy(const char *ptr) +static char *string_copy(const char *str) { - const char *ptr_p; - char *ret, *ret_p; + const char *str_p; + char *copy, *copy_p; int len; - len = strlen(ptr); - ret = (char *)malloc(len + 1); - if (ret == NULL) { - if (argv_error_stream != NULL) + len = strlen(str); + copy = (char *)malloc(len + 1); + if (copy == NULL) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return NULL; } - for (ptr_p = ptr, ret_p = ret; *ptr_p != NULLC;) - *ret_p++ = *ptr_p++; - *ret_p = NULLC; + for (str_p = str, copy_p = copy; *str_p != '\0';) { + *copy_p++ = *str_p++; + } + *copy_p = '\0'; - return ret; + return copy; } /* - * Break STR and return an array of char * whose values are tokenized - * by TOK. it passes back the number of tokens in TOKN. + * static char **vectorize * - * NOTE: the return value should be freed later and the STR should stay - * around until that time. + * DESCRIPTION: + * + * Break a string up into its arguments separated by one of the + * characters in a token string and return an array of char pointers. + * + * NOTE: the string argument should stay around until that time. + * + * RETURNS: + * + * Success - Allocated list of character poiners into the string + * argument which must be freed later. + * + * Failure - NULL + * + * ARGUMENTS: + * + * str - String we are tokenizing. + * + * tok - List of token characters to look for in the string. + * + * num_tok_p - Pointer to an integer which will be set to the number + * of tokens found in the string. */ -LOCAL char **vectorize(char *str, const char *tok, int *tokn) +static char **vectorize(char *str, const char *tok, int *num_tok_p) { char **vect_p; - char *tmp, *tok_p; - int tok_c; + char *tmp, *str_p, *tok_p; + int tok_c, tok_n; /* count the tokens */ tmp = string_copy(str); - if (tmp == NULL) + if (tmp == NULL) { return NULL; + } - tok_p = strtok(tmp, tok); - for (tok_c = 0; tok_p != NULL; tok_c++) - tok_p = strtok(NULL, tok); + str_p = tmp; + tok_c = 0; + while (1) { + tok_p = my_strsep(&str_p, tok); + if (tok_p == NULL) { + break; + } + if (*tok_p != '\0') { + tok_c++; + } + } + tok_n = tok_c; free(tmp); - *tokn = tok_c; + *num_tok_p = tok_n; - if (tok_c == 0) + if (tok_c == 0) { return NULL; + } /* allocate the pointer grid */ vect_p = (char **)malloc(sizeof(char *) * tok_c); if (vect_p == NULL) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return NULL; } /* load the tokens into the list */ - vect_p[0] = strtok(str, tok); - - for (tok_c = 1; tok_c < *tokn; tok_c++) - vect_p[tok_c] = strtok(NULL, tok); + str_p = str; + for (tok_c = 0; tok_c < tok_n;) { + tok_p = my_strsep(&str_p, tok); + if (tok_p == NULL) { + break; + } + if (*tok_p != '\0') { + vect_p[0] = tok_p; + tok_c++; + } + } return vect_p; } /* - * Display printable chars from BUF of SIZE, non-printables as \%03o + * static int expand_buf + * + * DESCRIPTION: + * + * Translates a buffer of bytes into its printable version. + * + * NOTE: it does _not_ add a \0 at the end of OUT. + * + * RETURNS: + * + * Number of characters written in to the output buffer. + * + * ARGUMENTS: + * + * buf - Input buffer of bytes. + * + * buf_size - Size of the input buffer. If < 0 then the routing will + * translate up to the first \0. + * + * out - Output buffer for the translated characters. + * + * out_size - Maximum size of the output buffer. */ -LOCAL char *expand_buf(const void *buf, const int size) +static int expand_buf(const void *buf, const int buf_size, + char *out, const int out_size) { - static char out[DUMP_SPACE_BUF]; - int size_c; - void *buf_p; - char *out_p; + int buf_c; + const unsigned char *buf_p, *spec_p; + char *max_p, *out_p = out; - for (size_c = 0, out_p = out, buf_p = (void *)buf; size_c < size; - size_c++, buf_p = (char *)buf_p + 1) { - char *spec_p; + /* setup our max pointer */ + max_p = out + out_size; - /* handle special chars */ - if (out_p + 2 >= out + sizeof(out)) - break; + /* run through the input buffer, counting the characters as we go */ + for (buf_c = 0, buf_p = (const unsigned char *)buf;; buf_c++, buf_p++) { + + /* did we reach the end of the buffer? */ + if (buf_size < 0) { + if (*buf_p == '\0') { + break; + } + } + else { + if (buf_c >= buf_size) { + break; + } + } /* search for special characters */ - for (spec_p = SPECIAL_CHARS + 1; *(spec_p - 1) != NULLC; spec_p += 2) - if (*spec_p == *(char *)buf_p) + for (spec_p = (unsigned char *)SPECIAL_CHARS + 1; + *(spec_p - 1) != '\0'; + spec_p += 2) { + if (*spec_p == *buf_p) { break; + } + } /* did we find one? */ - if (*(spec_p - 1) != NULLC) { - if (out_p + 2 >= out + sizeof(out)) + if (*(spec_p - 1) != '\0') { + if (out_p + 2 >= max_p) { break; + } (void)sprintf(out_p, "\\%c", *(spec_p - 1)); out_p += 2; continue; } - if (*(unsigned char *)buf_p < 128 && isprint((int)(*(char *)buf_p))) { - if (out_p + 1 >= out + sizeof(out)) + /* print out any 7-bit printable characters */ + if (*buf_p < 128 && isprint(*buf_p)) { + if (out_p + 1 >= max_p) { break; + } *out_p = *(char *)buf_p; out_p += 1; } else { - if (out_p + 4 >= out + sizeof(out)) + if (out_p + 4 >= max_p) { break; - (void)sprintf(out_p, "\\%03o", *(unsigned char *)buf_p); + } + (void)sprintf(out_p, "\\%03o", *buf_p); out_p += 4; } } - *out_p = NULLC; - return out; + return out_p - out; } + /****************************** usage routines *******************************/ /* + * static void usage_short + * + * DESCRIPTION: + * * Print a short-format usage message. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * args - Array of argv_t structions whose usage messages you print. + * + * flags - User flags. */ -LOCAL void usage_short(const argv_t *args, const int flag) +static void usage_short(const argv_t *args, const int flag) { const argv_t *arg_p; int len, col_c = 0; - char mark = ARGV_FALSE, *prefix; + int mark_b = ARGV_FALSE; + char *prefix; - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return; + } /* print the usage message header */ (void)fprintf(argv_error_stream, "%s%s", USAGE_LABEL, argv_program); @@ -310,18 +507,21 @@ LOCAL void usage_short(const argv_t *args, const int flag) /* skip or-specifiers */ if (arg_p->ar_short_arg == ARGV_OR - || arg_p->ar_short_arg == ARGV_XOR) + || arg_p->ar_short_arg == ARGV_XOR) { continue; + } /* skip non booleans */ - if (HAS_ARG(arg_p->ar_type)) + if (HAS_ARG(arg_p->ar_type)) { continue; + } /* skip args with no short component */ - if (arg_p->ar_short_arg == NULLC) + if (arg_p->ar_short_arg == '\0') { continue; + } - if (! mark) { + if (! mark_b) { len = 2 + SHORT_PREFIX_LENGTH; prefix = " ["; @@ -340,7 +540,7 @@ LOCAL void usage_short(const argv_t *args, const int flag) (void)fprintf(argv_error_stream, "%s%s", prefix, SHORT_PREFIX); col_c += len; - mark = ARGV_TRUE; + mark_b = ARGV_TRUE; } len = 1; @@ -359,7 +559,7 @@ LOCAL void usage_short(const argv_t *args, const int flag) col_c++; } - if (mark) { + if (mark_b) { (void)fprintf(argv_error_stream, "]"); col_c++; } @@ -371,15 +571,18 @@ LOCAL void usage_short(const argv_t *args, const int flag) /* skip or-specifiers */ if (arg_p->ar_short_arg == ARGV_OR - || arg_p->ar_short_arg == ARGV_XOR) + || arg_p->ar_short_arg == ARGV_XOR) { continue; + } /* skip booleans types */ - if (! HAS_ARG(arg_p->ar_type)) + if (! HAS_ARG(arg_p->ar_type)) { continue; + } if (arg_p->ar_var_label == NULL) { - if (ARGV_TYPE(arg_p->ar_type) == ARGV_BOOL_ARG) { + if (ARGV_TYPE(arg_p->ar_type) == ARGV_BOOL_ARG + || ARGV_TYPE(arg_p->ar_type) == ARGV_BOOL_INT_ARG) { var_str = BOOL_ARG_LABEL; var_len = BOOL_ARG_LENGTH; } @@ -451,102 +654,162 @@ LOCAL void usage_short(const argv_t *args, const int flag) (void)fprintf(argv_error_stream, "\n"); - if (flag == GLOBAL_USAGE_SHORTREM) + if (flag == GLOBAL_USAGE_SHORTREM) { (void)fprintf(argv_error_stream, "%*.*sUse the '%s%s' argument for more assistance.\n", (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", LONG_PREFIX, USAGE_ARG); + } } /* - * Display an argument type while keeping track of COL_C. + * static void display_arg + * + * DESCRIPTION: + * + * Display an argument type while keeping track of the column we are + * in. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * stream - Output stream we are writing to. + * + * arg_p - Argument that we are displaying. + * + * max - Maximum column position to write to. + * + * col_cp - Pointer to an integer to record the column position. */ -LOCAL void display_arg(FILE *stream, const argv_t *arg_p, const int max, - int *col_c) +static void display_arg(FILE *stream, const argv_t *arg_p, const int max, + int *col_cp) { int var_len, len; - if (arg_p->ar_var_label == NULL) + if (arg_p->ar_var_label == NULL) { var_len = 0; - else + } + else { var_len = strlen(arg_p->ar_var_label); + } switch (ARGV_TYPE(arg_p->ar_type)) { case ARGV_BOOL: case ARGV_BOOL_NEG: case ARGV_INCR: + case ARGV_BOOL_INT: + case ARGV_BOOL_INT_NEG: break; case ARGV_BOOL_ARG: + case ARGV_BOOL_INT_ARG: (void)fprintf(stream, "%s", BOOL_ARG_LABEL); - (*col_c) += BOOL_ARG_LENGTH; + (*col_cp) += BOOL_ARG_LENGTH; break; case ARGV_CHAR: - case ARGV_CHARP: - case ARGV_FLOAT: + case ARGV_CHAR_P: case ARGV_SHORT: + case ARGV_U_SHORT: case ARGV_INT: case ARGV_U_INT: case ARGV_LONG: case ARGV_U_LONG: + case ARGV_FLOAT: + case ARGV_DOUBLE: case ARGV_BIN: case ARGV_OCT: case ARGV_HEX: + case ARGV_SIZE: + case ARGV_U_SIZE: if (arg_p->ar_var_label == NULL) { - len = max - *col_c; + len = max - *col_cp; (void)fprintf(stream, "%-.*s", len, UNKNOWN_ARG); - *col_c += MIN(len, UNKNOWN_ARG_LENGTH); + *col_cp += MIN(len, (int)UNKNOWN_ARG_LENGTH); } else { - len = max - *col_c; + len = max - *col_cp; (void)fprintf(stream, "%-.*s", len, arg_p->ar_var_label); - *col_c += MIN(len, var_len); + *col_cp += MIN(len, var_len); } break; } } /* - * Display an option entry ARG_P to STREAM while counting COL_C. + * static void display_option + * + * DESCRIPTION: + * + * Display an option entry while while keeping track of the column we + * are in. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * stream - Output stream we are writing to. + * + * arg_p - Argument that we are displaying. + * + * max - Maximum column position to write to. + * + * col_cp - Pointer to an integer to record the column position. */ -LOCAL void display_option(FILE *stream, const argv_t *arg_p, int *col_c) +static void display_option(FILE *stream, const argv_t *arg_p, int *col_cp) { - if (stream == NULL) + if (stream == NULL) { return; + } (void)fputc('[', stream); - (*col_c)++; + (*col_cp)++; /* arg maybe does not have a -? preface */ if (arg_p->ar_short_arg != ARGV_MAYBE) { (void)fprintf(stream, "%s%c", SHORT_PREFIX, arg_p->ar_short_arg); - *col_c += SHORT_PREFIX_LENGTH + 1; + *col_cp += SHORT_PREFIX_LENGTH + 1; if (HAS_ARG(arg_p->ar_type)) { /* display optional argument */ (void)fputc(' ', stream); - (*col_c)++; + (*col_cp)++; } } - display_arg(stream, arg_p, LONG_COLUMN - 1, col_c); + display_arg(stream, arg_p, LONG_COLUMN - 1, col_cp); (void)fputc(']', stream); - (*col_c)++; + (*col_cp)++; } /* + * static void usage_long + * + * DESCRIPTION: + * * Print a long-format usage message. + * + * RETURNS: + * + * None. + * + * ars - Array of argv_t structures whose usage we are printing. */ -LOCAL void usage_long(const argv_t *args) +static void usage_long(const argv_t *args) { const argv_t *arg_p; int col_c, len; - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return; + } /* print the usage message header */ (void)fprintf(argv_error_stream, "%s%s\n", USAGE_LABEL, argv_program); @@ -555,8 +818,9 @@ LOCAL void usage_long(const argv_t *args) for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { /* skip or specifiers */ - if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) + if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) { continue; + } /* indent to the short-option col_c */ (void)fprintf(argv_error_stream, "%*.*s", SHORT_COLUMN, SHORT_COLUMN, ""); @@ -565,15 +829,21 @@ LOCAL void usage_long(const argv_t *args) col_c = SHORT_COLUMN; /* print the short-arg stuff if there */ - if (arg_p->ar_short_arg == NULLC) { + if (arg_p->ar_short_arg == '\0') { (void)fputc('[', argv_error_stream); col_c++; } else { - if (arg_p->ar_short_arg == ARGV_MAND) + if (arg_p->ar_short_arg == '\0') { + ; + } + else if (arg_p->ar_short_arg == ARGV_MAND) { display_arg(argv_error_stream, arg_p, COMMENT_COLUMN, &col_c); - else + } + else { + /* ARGV_MAYBE handled here */ display_option(argv_error_stream, arg_p, &col_c); + } /* put the long-option message on the correct column */ if (col_c < LONG_COLUMN) { @@ -586,18 +856,18 @@ LOCAL void usage_long(const argv_t *args) /* print the long-option message */ if (arg_p->ar_long_arg != NULL) { len = COMMENT_COLUMN - col_c - (LONG_PREFIX_LENGTH + 1); - if (arg_p->ar_short_arg != NULLC) { + if (arg_p->ar_short_arg != '\0') { (void)fprintf(argv_error_stream, "%s", LONG_LABEL); col_c += LONG_LABEL_LENGTH; len -= LONG_LABEL_LENGTH; } (void)fprintf(argv_error_stream, "%s%-.*s", LONG_PREFIX, len, arg_p->ar_long_arg); - col_c += LONG_PREFIX_LENGTH + MIN(len, strlen(arg_p->ar_long_arg)); + col_c += LONG_PREFIX_LENGTH + MIN(len, (int)strlen(arg_p->ar_long_arg)); } /* add the optional argument if no short-arg */ - if (arg_p->ar_short_arg == NULLC) { + if (arg_p->ar_short_arg == '\0') { if (HAS_ARG(arg_p->ar_type)) { (void)fputc(' ', argv_error_stream); col_c++; @@ -629,22 +899,41 @@ LOCAL void usage_long(const argv_t *args) } /* - * Do the usage depending on FLAG. + * static void do_usage + * + * DESCRIPTION: + * + * Print the usage messages. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * args - Array of argv_t structures. + * + * flag - Users flags which will tell us whether to display short or + * long usage messages. */ -LOCAL void do_usage(const argv_t *args, const int flag) +static void do_usage(const argv_t *args, const int flag) { - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return; + } - if (flag == GLOBAL_USAGE_SEE) + if (flag == GLOBAL_USAGE_SEE) { (void)fprintf(argv_error_stream, "%*.*sUse the '%s%s' argument for assistance.\n", (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", LONG_PREFIX, USAGE_ARG); - else if (flag == GLOBAL_USAGE_SHORT || flag == GLOBAL_USAGE_SHORTREM) + } + else if (flag == GLOBAL_USAGE_SHORT || flag == GLOBAL_USAGE_SHORTREM) { usage_short(args, flag); - else if (flag == GLOBAL_USAGE_LONG || flag == GLOBAL_USAGE_ALL) + } + else if (flag == GLOBAL_USAGE_LONG || flag == GLOBAL_USAGE_ALL) { usage_long(args); + } if (flag == GLOBAL_USAGE_ALL) { (void)fprintf(argv_error_stream, "\n"); @@ -682,122 +971,128 @@ LOCAL void do_usage(const argv_t *args, const int flag) /******************************* preprocessing *******************************/ /* - * Preprocess argument array ARGS of NUM_ARGS entries and set the MAND - * and MAYBE boolean arrays. Returns [NO]ERROR. + * static int preprocess_array + * + * DESCRIPTION: + * + * Preprocess argument array entries and set the mandatory and maybe + * flags. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures. + * + * arg_n - Number of entries in the argv_t array. We need this for a + * couple of reasons. */ -LOCAL int preprocess_array(argv_t *args, const int num_args) +static int preprocess_array(argv_t *args, const int arg_n) { argv_t *arg_p; - char mand_array = ARGV_FALSE, maybe_field = ARGV_FALSE; + int mand_array_b = ARGV_FALSE, maybe_field_b = ARGV_FALSE; /* count the args and find the first mandatory */ - for (arg_p = args; arg_p < args + num_args; arg_p++) { + for (arg_p = args; arg_p < args + arg_n; arg_p++) { /* clear internal flags */ arg_p->ar_type &= ~ARGV_FLAG_USED; /* do we have a mandatory-array? */ if (arg_p->ar_short_arg == ARGV_MAND) { - if (mand_array) { - if (argv_error_stream != NULL) + if (mand_array_b) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, no ARGV_MAND's can follow a MAND or MAYBE array\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } - if (maybe_field) { - if (argv_error_stream != NULL) + if (maybe_field_b) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, no ARGV_MAND's can follow a ARGV_MAYBE\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } -#if 0 - if (arg_p->ar_long_arg != NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: %s, ARGV_MAND's should not have long-options\n", - argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { + mand_array_b = ARGV_TRUE; } -#endif - - if (arg_p->ar_type & ARGV_ARRAY) - mand_array = ARGV_TRUE; } /* do we have a maybe field? */ if (arg_p->ar_short_arg == ARGV_MAYBE) { - if (mand_array) { - if (argv_error_stream != NULL) + if (mand_array_b) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, no ARGV_MAYBE's can follow a MAND or MAYBE array\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } - maybe_field = ARGV_TRUE; - if (arg_p->ar_type & ARGV_ARRAY) - mand_array = ARGV_TRUE; + maybe_field_b = ARGV_TRUE; + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { + mand_array_b = ARGV_TRUE; + } } /* handle initializing the argument array */ - if (arg_p->ar_type & ARGV_ARRAY) { + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { argv_array_t *arrp = (argv_array_t *)arg_p->ar_variable; if (! HAS_ARG(arg_p->ar_type)) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, cannot have an array of boolean values\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } if (ARGV_TYPE(arg_p->ar_type) == ARGV_INCR) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, cannot have an array of incremental values\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } - arrp->aa_entryn = 0; + arrp->aa_entry_n = 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; - } -#endif - /* verify variable pointer */ if (arg_p->ar_variable == NULL && arg_p->ar_short_arg != ARGV_OR && arg_p->ar_short_arg != ARGV_XOR) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, NULL variable specified in arg array\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } @@ -806,25 +1101,29 @@ LOCAL int preprocess_array(argv_t *args, const int num_args) || arg_p->ar_short_arg == ARGV_XOR) { /* that they are not at the start or end of list */ - if (arg_p == args || arg_p >= (args + num_args - 1)) { - if (argv_error_stream != NULL) + if (arg_p == args || arg_p >= (args + arg_n - 1)) { + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, ARGV_[X]OR entries cannot be at start or end of array\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } /* that two aren't next to each other */ if ((arg_p - 1)->ar_short_arg == ARGV_OR || (arg_p - 1)->ar_short_arg == ARGV_XOR) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, two ARGV_[X]OR entries cannot be next to each other\n", argv_program, INTERNAL_ERROR_NAME); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } } @@ -834,52 +1133,76 @@ LOCAL int preprocess_array(argv_t *args, const int num_args) } /* - * Translate string argument ARG into VAR depending on its TYPE. - * Returns [NO]ERROR. + * static int string_to_value + * + * DESCRIPTION: + * + * Translate string value argument into a variable value depending on + * its type. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * arg - Argument string. + * + * var - Pointer to our variable. + * + * type - Type of the variable. */ -LOCAL int translate_value(const char *arg, ARGV_PNT var, - const short type) +static int string_to_value(const char *arg, ARGV_PNT var, + const unsigned int type) { argv_array_t *arr_p; argv_type_t *type_p; - int val_type = ARGV_TYPE(type), size = 0; + unsigned int val_type = ARGV_TYPE(type), size = 0; /* find the type and the size for array */ - for (type_p = argv_types; type_p->at_value != 0; type_p++) + for (type_p = argv_types; type_p->at_value != 0; type_p++) { if (type_p->at_value == val_type) { size = type_p->at_size; break; } + } if (type_p->at_value == 0) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal variable type %d\n", __FILE__, val_type); + } return ERROR; } - if (type & ARGV_ARRAY) { + if (type & ARGV_FLAG_ARRAY) { arr_p = (argv_array_t *)var; - if (arr_p->aa_entryn == 0) + if (arr_p->aa_entry_n == 0) { arr_p->aa_entries = (char *)malloc(ARRAY_INCR *size); - else if (arr_p->aa_entryn % ARRAY_INCR == 0) + } + else if (arr_p->aa_entry_n % ARRAY_INCR == 0) { arr_p->aa_entries = - (char *)realloc(arr_p->aa_entries, (arr_p->aa_entryn + ARRAY_INCR) * + (char *)realloc(arr_p->aa_entries, (arr_p->aa_entry_n + ARRAY_INCR) * size); + } if (arr_p->aa_entries == NULL) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return ERROR; } - var = (char *)(arr_p->aa_entries) + arr_p->aa_entryn * size; - arr_p->aa_entryn++; + var = (char *)(arr_p->aa_entries) + arr_p->aa_entry_n * size; + arr_p->aa_entry_n++; } /* translate depending on type */ @@ -887,34 +1210,64 @@ LOCAL int translate_value(const char *arg, ARGV_PNT var, case ARGV_BOOL: /* if no close argument, set to true */ - if (arg == NULL) + if (arg == NULL) { *(char *)var = ARGV_TRUE; + } else if (*(char *)arg == 't' || *(char *)arg == 'T' || *(char *)arg == 'y' || *(char *)arg == 'Y' - || *(char *)arg == '1') + || *(char *)arg == '1') { *(char *)var = ARGV_TRUE; - else + } + 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_CHARP: + case ARGV_CHAR_P: *(char **)var = string_copy((char *)arg); - if (*(char **)var == NULL) + if (*(char **)var == NULL) { return ERROR; - break; - - case ARGV_FLOAT: - *(float *)var = (float)atof(arg); + } break; case ARGV_SHORT: *(short *)var = (short)atoi(arg); break; + case ARGV_U_SHORT: + *(unsigned short *)var = (unsigned short)atoi(arg); + break; + case ARGV_INT: *(int *)var = atoi(arg); break; @@ -931,6 +1284,14 @@ LOCAL int translate_value(const char *arg, ARGV_PNT var, *(unsigned long *)var = atol(arg); break; + case ARGV_FLOAT: + (void)sscanf(arg, "%f", (float *)var); + break; + + case ARGV_DOUBLE: + (void)sscanf(arg, "%lf", (double *)var); + break; + case ARGV_BIN: *(int *)var = btoi(arg); break; @@ -943,158 +1304,423 @@ LOCAL int translate_value(const char *arg, ARGV_PNT var, *(int *)var = htoi(arg); break; - case ARGV_BOOL_NEG: - /* if no close argument, set to false */ - if (arg == NULL) - *(char *)var = ARGV_FALSE; - else if (*(char *)arg == 't' || *(char *)arg == 'T' - || *(char *)arg == 'y' || *(char *)arg == 'Y' - || *(char *)arg == '1') - *(char *)var = ARGV_TRUE; - else - *(char *)var = ARGV_FALSE; - break; - case ARGV_INCR: /* if no close argument then increment else set the value */ - if (arg == NULL) + if (arg == NULL) { (*(int *)var)++; - else + } + else { *(int *)var = atoi(arg); + } break; - case ARGV_BOOL_ARG: + case ARGV_SIZE: + { + const char *arg_p; + long val; + + /* take initial integer point */ + val = atol(arg); + for (arg_p = arg; + *arg_p == ' ' || *arg_p == '-' || *arg_p == '+' + || (*arg_p >= '0' && *arg_p <= '9'); + arg_p++) { + } + if (*arg_p == 'b' || *arg_p == 'B') { + val *= 1; + } + else if (*arg_p == 'k' || *arg_p == 'B') { + val *= 1024; + } + else if (*arg_p == 'm' || *arg_p == 'M') { + val *= 1024 * 1024; + } + else if (*arg_p == 'g' || *arg_p == 'G') { + val *= 1024 * 1024 * 1024; + } + *(long *)var = val; + } + break; + + case ARGV_U_SIZE: + { + const char *arg_p; + unsigned long val; + + /* take initial integer point */ + val = (unsigned long)atol(arg); + for (arg_p = arg; + *arg_p == ' ' || *arg_p == '-' || *arg_p == '+' + || (*arg_p >= '0' && *arg_p <= '9'); + arg_p++) { + } + if (*arg_p == 'b' || *arg_p == 'B') { + val *= 1; + } + else if (*arg_p == 'k' || *arg_p == 'B') { + val *= 1024; + } + else if (*arg_p == 'm' || *arg_p == 'M') { + val *= 1024 * 1024; + } + else if (*arg_p == 'g' || *arg_p == 'G') { + val *= 1024 * 1024 * 1024; + } + *(unsigned long *)var = val; + } + break; + + case ARGV_BOOL_INT: + /* if no close argument, set to true */ + if (arg == NULL) { + *(int *)var = ARGV_TRUE; + } + else if (*(char *)arg == 't' || *(char *)arg == 'T' + || *(char *)arg == 'y' || *(char *)arg == 'Y' + || *(char *)arg == '1') { + *(int *)var = ARGV_TRUE; + } + else { + *(int *)var = ARGV_FALSE; + } + break; + + case ARGV_BOOL_INT_NEG: + /* if no close argument, set to false */ + if (arg == NULL) { + *(int *)var = ARGV_FALSE; + } + else if (*(char *)arg == 't' || *(char *)arg == 'T' + || *(char *)arg == 'y' || *(char *)arg == 'Y' + || *(char *)arg == '1') { + *(int *)var = ARGV_TRUE; + } + else { + *(int *)var = ARGV_FALSE; + } + break; + + case ARGV_BOOL_INT_ARG: if (*(char *)arg == 't' || *(char *)arg == 'T' || *(char *)arg == 'y' || *(char *)arg == 'Y' - || *(char *)arg == '1') - *(char *)var = ARGV_TRUE; - else - *(char *)var = ARGV_FALSE; + || *(char *)arg == '1') { + *(int *)var = ARGV_TRUE; + } + else { + *(int *)var = ARGV_FALSE; + } break; + } return NOERROR; } /* - * Translate value from VAR into string STR depending on its TYPE. + * static int value_to_string + * + * DESCRIPTION: + * + * Translate value from variable depending on its type intoits string + * represetnation in buffer. + * + * RETURNS: + * + * Number of characters added to the buffer. + * + * ARGUMENTS: + * + * var - Variable pointer. + * + * type - Type of variable. + * + * buf - User buffer to convert into. + * + * buf_size - Size of the user buffer. */ -LOCAL void display_value(const ARGV_PNT var, const short type) +static int value_to_string(const ARGV_PNT var, const unsigned int type, + char *buf, const int buf_size) { - int val_type = ARGV_TYPE(type); + int len = 0; + + /* + * NOTE: without a snprintf, we have to hope that buf_size > integer + * and the string repesentations of the numbers. + */ /* translate depending on type */ - switch (val_type) { + switch (ARGV_TYPE(type)) { case ARGV_BOOL: case ARGV_BOOL_NEG: case ARGV_BOOL_ARG: - if (*(char *)var) - (void)fprintf(argv_error_stream, "ARGV_TRUE"); - else - (void)fprintf(argv_error_stream, "ARGV_FALSE"); + if (*(char *)var) { + strncpy(buf, "true (! 0)", buf_size); + } + else { + strncpy(buf, "false (0)", buf_size); + } + buf[buf_size - 1] = '\0'; + len = strlen(buf); break; case ARGV_CHAR: - (void)fprintf(argv_error_stream, "'%s'", expand_buf((char *)var, 1)); + len = expand_buf((char *)var, 1, buf, buf_size); break; - case ARGV_CHARP: - { - int len; - if (*(char **)var == NULL) - (void)fprintf(argv_error_stream, "(null)"); - else { - len = strlen(*(char **)var); - (void)fprintf(argv_error_stream, "\"%s\"", - expand_buf(*(char **)var, len)); - } + case ARGV_CHAR_P: + if (*(char **)var == NULL) { + strncpy(buf, "(null)", buf_size); + buf[buf_size - 1] = '\0'; + len = strlen(buf); + } + else { + len = expand_buf(*(char **)var, -1, buf, buf_size); } break; - case ARGV_FLOAT: - (void)fprintf(argv_error_stream, "%f", *(float *)var); + case ARGV_SHORT: + (void)sprintf(buf, "%d", *(short *)var); + len = strlen(buf); break; - case ARGV_SHORT: - (void)fprintf(argv_error_stream, "%d", *(short *)var); + case ARGV_U_SHORT: + (void)sprintf(buf, "%d", *(unsigned short *)var); + len = strlen(buf); break; case ARGV_INT: - case ARGV_INCR: - (void)fprintf(argv_error_stream, "%d", *(int *)var); + (void)sprintf(buf, "%d", *(int *)var); + len = strlen(buf); break; case ARGV_U_INT: - (void)fprintf(argv_error_stream, "%u", *(unsigned int *)var); + (void)sprintf(buf, "%u", *(unsigned int *)var); + len = strlen(buf); break; case ARGV_LONG: - (void)fprintf(argv_error_stream, "%ld", *(long *)var); + (void)sprintf(buf, "%ld", *(long *)var); + len = strlen(buf); break; case ARGV_U_LONG: - (void)fprintf(argv_error_stream, "%lu", *(unsigned long *)var); + (void)sprintf(buf, "%lu", *(unsigned long *)var); + len = strlen(buf); + break; + + case ARGV_FLOAT: + (void)sprintf(buf, "%f", *(float *)var); + len = strlen(buf); + break; + + case ARGV_DOUBLE: + (void)sprintf(buf, "%f", *(double *)var); + len = strlen(buf); break; /* this should be a routine */ case ARGV_BIN: { - int bit_c; - char first = ARGV_FALSE; + int bit_c, bit, first_b = ARGV_FALSE; + char binary[2 + 128 + 1], *bin_p = binary; - (void)fputc('0', argv_error_stream); + if (*(int *)var == 0) { + strncpy(buf, "0", buf_size); + } + else { - if (*(int *)var != 0) { - (void)fputc('b', argv_error_stream); + /* initially write binary number into tmp buffer, then copy into out */ + *bin_p++ = '0'; + *bin_p++ = 'b'; for (bit_c = sizeof(int) * BITS_IN_BYTE - 1; bit_c >= 0; bit_c--) { - int bit = *(int *)var & (1 << bit_c); + bit = *(int *)var & (1 << bit_c); if (bit == 0) { - if (first) - (void)fputc('0', argv_error_stream); + if (first_b) { + *bin_p++ = '0'; + } } else { - (void)fputc('1', argv_error_stream); - first = ARGV_TRUE; + *bin_p++ = '1'; + first_b = ARGV_TRUE; } } + + /* add on the decimal equivalent */ + (void)sprintf(bin_p, " (%d)", *(int *)var); + /* find the \0 at end */ + for (; *bin_p != '\0'; bin_p++) { + } + + /* now we copy from the binary buffer to the output */ + strncpy(buf, binary, buf_size); } + + buf[buf_size - 1] = '\0'; + len = strlen(buf); } break; case ARGV_OCT: - (void)fprintf(argv_error_stream, "%#o", *(int *)var); + if (*(int *)var == 0) { + (void)strncpy(buf, "0", buf_size); + buf[buf_size - 1] = '\0'; + } + else { + (void)sprintf(buf, "%#o (%d)", *(int *)var, *(int *)var); + } + len = strlen(buf); break; case ARGV_HEX: - (void)fprintf(argv_error_stream, "%#x", *(int *)var); + if (*(int *)var == 0) { + (void)strcpy(buf, "0"); + } + else { + (void)sprintf(buf, "%#x (%d)", *(int *)var, *(int *)var); + } + len = strlen(buf); + break; + + case ARGV_INCR: + (void)sprintf(buf, "%d", *(int *)var); + len = strlen(buf); + break; + + case ARGV_SIZE: + { + long morf, val = *(long *)var; + + if (val == 0) { + (void)strcpy(buf, "0"); + } + else if (val % (1024 * 1024 * 1024) == 0) { + morf = val / (1024 * 1024 * 1024); + (void)sprintf(buf, "%ldg (%ld)", morf, val); + } + else if (val % (1024 * 1024) == 0) { + morf = val / (1024 * 1024); + (void)sprintf(buf, "%ldm (%ld)", morf, val); + } + else if (val % 1024 == 0) { + morf = val / 1024; + (void)sprintf(buf, "%ldk (%ld)", morf, val); + } + else { + (void)sprintf(buf, "%ld", val); + } + + len = strlen(buf); + } + break; + + case ARGV_U_SIZE: + { + unsigned long morf, val = *(unsigned long *)var; + + if (val == 0) { + (void)strcpy(buf, "0"); + } + else if (val % (1024 * 1024 * 1024) == 0) { + morf = val / (1024 * 1024 * 1024); + (void)sprintf(buf, "%ldg (%ld)", morf, val); + } + else if (val % (1024 * 1024) == 0) { + morf = val / (1024 * 1024); + (void)sprintf(buf, "%ldm (%ld)", morf, val); + } + else if (val % 1024 == 0) { + morf = val / 1024; + (void)sprintf(buf, "%ldk (%ld)", morf, val); + } + else { + (void)sprintf(buf, "%ld", val); + } + + len = strlen(buf); + } + break; + + case ARGV_BOOL_INT: + case ARGV_BOOL_INT_NEG: + case ARGV_BOOL_INT_ARG: + if (*(int *)var) { + strncpy(buf, "true (! 0)", buf_size); + } + else { + strncpy(buf, "false (0)", buf_size); + } + buf[buf_size - 1] = '\0'; + len = strlen(buf); + break; + + default: + strncpy(buf, "(unknown)", buf_size); + buf[buf_size - 1] = '\0'; + len = strlen(buf); break; } + + return len; } /* - * Translate value from VAR into string STR depending on its TYPE. + * static void display_variables + * + * DESCRIPTION: + * + * Display all of the variable values from our array. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * args - Array of argv_t structures whose variables we are + * displaying. */ -LOCAL void display_variables(const argv_t *args) +static void display_variables(const argv_t *args) { const argv_t *arg_p; argv_type_t *type_p; + char buf[256]; + int len, col_c, val_type; /* run through the argument structure */ for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { - int col_c, val_type = ARGV_TYPE(arg_p->ar_type); + + val_type = ARGV_TYPE(arg_p->ar_type); /* skip or specifiers */ - if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) + if (arg_p->ar_short_arg == ARGV_OR || arg_p->ar_short_arg == ARGV_XOR) { continue; + } col_c = 0; - if (arg_p->ar_short_arg == ARGV_MAND) + if (arg_p->ar_short_arg == '\0') { + if (arg_p->ar_long_arg != NULL) { + len = COMMENT_COLUMN - col_c - (LONG_PREFIX_LENGTH + 1); + if (arg_p->ar_short_arg != '\0') { + (void)fprintf(argv_error_stream, "%s", LONG_LABEL); + col_c += LONG_LABEL_LENGTH; + len -= LONG_LABEL_LENGTH; + } + (void)fprintf(argv_error_stream, "%s%-.*s", + LONG_PREFIX, len, arg_p->ar_long_arg); + col_c += LONG_PREFIX_LENGTH + MIN(len, + (int)strlen(arg_p->ar_long_arg)); + } + } + else if (arg_p->ar_short_arg == ARGV_MAND) { display_arg(argv_error_stream, arg_p, COMMENT_COLUMN, &col_c); - else + } + else { + /* ARGV_MAYBE handled here */ display_option(argv_error_stream, arg_p, &col_c); + } /* put the type in the correct column */ if (col_c < LONG_COLUMN) { @@ -1107,13 +1733,13 @@ LOCAL void display_variables(const argv_t *args) type_p = NULL; for (type_p = argv_types; type_p->at_value != 0; type_p++) { if (type_p->at_value == ARGV_TYPE(arg_p->ar_type)) { - int len, tlen; + int tlen; len = COMMENT_COLUMN - col_c - 1; tlen = strlen(type_p->at_name); (void)fprintf(argv_error_stream, " %-.*s", len, type_p->at_name); col_c += MIN(len, tlen); - if (arg_p->ar_type & ARGV_ARRAY) { + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { (void)fprintf(argv_error_stream, "%s", ARRAY_LABEL); col_c += sizeof(ARRAY_LABEL) - 1; } @@ -1127,7 +1753,7 @@ LOCAL void display_variables(const argv_t *args) col_c = COMMENT_COLUMN; } - if (arg_p->ar_type & ARGV_ARRAY) { + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { argv_array_t *arr_p; int entry_c, size = 0; @@ -1140,20 +1766,25 @@ LOCAL void display_variables(const argv_t *args) size = type_p->at_size; arr_p = (argv_array_t *)arg_p->ar_variable; - if (arr_p->aa_entryn == 0) + if (arr_p->aa_entry_n == 0) { (void)fprintf(argv_error_stream, "no entries"); + } else { - for (entry_c = 0; entry_c < arr_p->aa_entryn; entry_c++) { + for (entry_c = 0; entry_c < arr_p->aa_entry_n; entry_c++) { ARGV_PNT var; - if (entry_c > 0) + if (entry_c > 0) { (void)fputc(',', argv_error_stream); + } var = (char *)(arr_p->aa_entries) + entry_c * size; - display_value(var, val_type); + len = value_to_string(var, val_type, buf, sizeof(buf)); + (void)fwrite(buf, sizeof(char), len, argv_error_stream); } } } - else - display_value(arg_p->ar_variable, val_type); + else { + len = value_to_string(arg_p->ar_variable, val_type, buf, sizeof(buf)); + (void)fwrite(buf, sizeof(char), len, argv_error_stream); + } (void)fputc('\n', argv_error_stream); } } @@ -1161,18 +1792,36 @@ LOCAL void display_variables(const argv_t *args) /************************** checking used arguments **************************/ /* - * Check out if WHICH argument from ARGS has an *or* specified - * attached to it. Returns [NO]ERROR + * static int check_or + * + * DESCRIPTION: + * + * Check out if an argument has an ARGV_OR attached to it and both + * variables have not been set. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures that we are checking. + * + * which_p - Pointer to the specific argument that we are checking for + * the ARGV_OR. */ -LOCAL int check_or(const argv_t *args, const argv_t *which) +static int check_or(const argv_t *args, const argv_t *which_p) { const argv_t *arg_p, *match_p = NULL; /* check ORs below */ - for (arg_p = which - 2; arg_p >= args; arg_p -= 2) { + for (arg_p = which_p - 2; arg_p >= args; arg_p -= 2) { if ((arg_p + 1)->ar_short_arg != ARGV_OR - && (arg_p + 1)->ar_short_arg != ARGV_XOR) + && (arg_p + 1)->ar_short_arg != ARGV_XOR) { break; + } if (arg_p->ar_type & ARGV_FLAG_USED) { match_p = arg_p; break; @@ -1181,14 +1830,15 @@ LOCAL int check_or(const argv_t *args, const argv_t *which) /* check ORs above */ if (match_p == NULL) { - /* NOTE: we assume that which is not pointing now to ARGV_LAST */ - for (arg_p = which + 2; + /* NOTE: we assume that which_p is not pointing now to ARGV_LAST */ + for (arg_p = which_p + 2; arg_p->ar_short_arg != ARGV_LAST && (arg_p - 1)->ar_short_arg != ARGV_LAST; arg_p += 2) { if ((arg_p - 1)->ar_short_arg != ARGV_OR - && (arg_p - 1)->ar_short_arg != ARGV_XOR) + && (arg_p - 1)->ar_short_arg != ARGV_XOR) { break; + } if (arg_p->ar_type & ARGV_FLAG_USED) { match_p = arg_p; break; @@ -1197,11 +1847,13 @@ LOCAL int check_or(const argv_t *args, const argv_t *which) } /* did we not find a problem? */ - if (match_p == NULL) + if (match_p == NULL) { return NOERROR; + } - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return ERROR; + } (void)fprintf(argv_error_stream, "%s: %s, specify only one of the following:\n", @@ -1209,27 +1861,49 @@ LOCAL int check_or(const argv_t *args, const argv_t *which) /* little hack to print the one that matched and the one we were checking */ for (;;) { - if (match_p->ar_long_arg == NULL) - (void)fprintf(argv_error_stream, " %s%c\n", + if (match_p->ar_long_arg == NULL) { + (void)fprintf(argv_error_stream, "%*.*s%s%c\n", + (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", SHORT_PREFIX, match_p->ar_short_arg); - else - (void)fprintf(argv_error_stream, " %s%c (%s%s)\n", + } + else { + (void)fprintf(argv_error_stream, "%*.*s%s%c (%s%s)\n", + (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", SHORT_PREFIX, match_p->ar_short_arg, LONG_PREFIX, match_p->ar_long_arg); + } - if (match_p == which) + if (match_p == which_p) { break; - match_p = which; + } + match_p = which_p; } return ERROR; } /* - * Find all the XOR arguments and make sure each group has at least - * one specified in it. Returns [NO]ERROR. + * static int check_xor + * + * DESCRIPTION: + * + * Check out if an argument has an ARGV_XOR attached to it and that at + * least one but not both variables have been set. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures that we are checking. + * + * which_p - Pointer to the specific argument that we are checking for + * the ARGV_XOR. */ -LOCAL int check_xor(const argv_t *args) +static int check_xor(const argv_t *args) { const argv_t *start_p = NULL, *arg_p; @@ -1237,8 +1911,9 @@ LOCAL int check_xor(const argv_t *args) for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { /* only check the XORs */ - if (arg_p->ar_short_arg != ARGV_XOR) + if (arg_p->ar_short_arg != ARGV_XOR) { continue; + } start_p = arg_p; @@ -1246,31 +1921,37 @@ LOCAL int check_xor(const argv_t *args) * NOTE: we are guaranteed that we are on a XOR so there is * something below and above... */ - if ((arg_p - 1)->ar_type & ARGV_FLAG_USED) + if ((arg_p - 1)->ar_type & ARGV_FLAG_USED) { start_p = NULL; + } /* run through all XORs */ for (;;) { arg_p++; - if (arg_p->ar_type & ARGV_FLAG_USED) + if (arg_p->ar_type & ARGV_FLAG_USED) { start_p = NULL; - if ((arg_p + 1)->ar_short_arg != ARGV_XOR) + } + if ((arg_p + 1)->ar_short_arg != ARGV_XOR) { break; + } arg_p++; } /* were none of the xor's filled? */ - if (start_p != NULL) + if (start_p != NULL) { break; + } } /* did we not find a problem? */ - if (start_p == NULL) + if (start_p == NULL) { return NOERROR; + } /* arg_p points to the first XOR which failed */ - if (argv_error_stream == NULL) + if (argv_error_stream == NULL) { return ERROR; + } (void)fprintf(argv_error_stream, "%s: %s, must specify one of:\n", argv_program, USAGE_ERROR_NAME); @@ -1280,61 +1961,119 @@ LOCAL int check_xor(const argv_t *args) * NOTE: we are guaranteed that we are on a XOR so there is * something below and above... */ - (void)fprintf(argv_error_stream, " %s%c", + (void)fprintf(argv_error_stream, "%*.*s%s%c", + (int)USAGE_LABEL_LENGTH, (int)USAGE_LABEL_LENGTH, "", SHORT_PREFIX, (arg_p - 1)->ar_short_arg); - if ((arg_p - 1)->ar_long_arg != NULL) + if ((arg_p - 1)->ar_long_arg != NULL) { (void)fprintf(argv_error_stream, " (%s%s)", LONG_PREFIX, (arg_p - 1)->ar_long_arg); + } (void)fprintf(argv_error_stream, "\n"); - if (arg_p->ar_short_arg != ARGV_XOR) + if (arg_p->ar_short_arg != ARGV_XOR) { break; + } } return ERROR; } /* - * Check to see if any mandatory arguments left. Returns [NO]ERROR. + * static int check_mand + * + * DESCRIPTION: + * + * Verify that all of the mandatory arguments in our array have been + * specified. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures that we are checking. */ -LOCAL int check_mand(const argv_t *args) +static int check_mand(const argv_t *args) { const argv_t *arg_p; - int slot_c = 0; + int mand_c = 0, flag_c = 0; /* see if there are any mandatory args left */ - for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) + for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { if (arg_p->ar_short_arg == ARGV_MAND - && (! (arg_p->ar_type & ARGV_FLAG_USED)) - && ! (arg_p->ar_type & ARGV_ARRAY)) - slot_c++; - - if (slot_c > 0) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: %s, %d more mandatory argument%s must be specified\n", - argv_program, USAGE_ERROR_NAME, - slot_c, (slot_c == 1 ? "" : "s")); - return ERROR; + && (! (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"); + } + } } - return NOERROR; + 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; + } } /* - * Check for any missing argument options. Returns [NO]ERROR + * static int check_opt + * + * DESCRIPTION: + * + * Check for any missing argument options. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * queue_head - Head of the option queue. + * + * queue_tail - Tail of the option queue. */ -LOCAL int check_opt(void) +static int check_opt(const int queue_head, const int queue_tail) { int queue_c; - queue_c = QUEUE_COUNT(); + queue_c = queue_head - queue_tail; if (queue_c > 0) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, %d more option-argument%s must be specified\n", argv_program, USAGE_ERROR_NAME, queue_c, (queue_c == 1 ? "" : "s")); + } return ERROR; } @@ -1344,42 +2083,75 @@ LOCAL int check_opt(void) /**************************** argument processing ****************************/ /* - * Read in arguments from PATH and run them from the GRID. OKAY_P is - * a pointer to the boolean error marker. Returns [NO]ERROR. + * static void file_args + * + * DESCRIPTION: + * + * Read in arguments from a file and process them like they were + * specified on the command line. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * path -> File of the arguments we are reading in. + * + * grid -> Array of argv_t structures we are using. + * + * queue_list <-> Our option queue for storing options to arguments. + * + * queue_head_p <-> Pointer to integer which will be updated with the + * head position in our option queue. + * + * queue_tail_p <-> Pointer to integer which will be updated with the + * tail position in our option queue. + * + * okay_bp <- Pointer to an integer which is set with 0 if the + * arguments specified in the env variable are somehow invalid. */ -LOCAL void file_args(const char *path, argv_t *grid, char *okay_p) +static void file_args(const char *path, argv_t *grid, + argv_t **queue_list, int *queue_head_p, + int *queue_tail_p, int *okay_bp) { char **argv, **argv_p; - int argc, max; + int arg_c, max; FILE *infile; char line[FILE_LINE_SIZE + 1], *line_p; /* open the input file */ infile = fopen(path, "r"); if (infile == NULL) { - *okay_p = ARGV_FALSE; - if (argv_error_stream != NULL) + *okay_bp = ARGV_FALSE; + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: could not load command-line arguments from: %s\n", argv_program, path); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return; } /* get an array of char * */ - argc = 0; + arg_c = 0; max = ARRAY_INCR; argv = malloc(sizeof(char *) * max); if (argv == NULL) { - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; (void)fclose(infile); - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return; } argv_p = argv; @@ -1387,52 +2159,82 @@ LOCAL void file_args(const char *path, argv_t *grid, char *okay_p) /* read in the file lines */ while (fgets(line, FILE_LINE_SIZE, infile) != NULL) { /* punch the \n at end of line */ - for (line_p = line; *line_p != '\n' && *line_p != '\0'; line_p++); + for (line_p = line; *line_p != '\n' && *line_p != '\0'; line_p++) { + } *line_p = '\0'; *argv_p = string_copy(line); if (*argv_p == NULL) { - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; return; } argv_p++; - argc++; - if (argc == max) { + arg_c++; + if (arg_c == max) { max += ARRAY_INCR; argv = realloc(argv, sizeof(char *) * max); if (argv == NULL) { - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; (void)fclose(infile); - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); - if (argv_interactive) + } + if (argv_interactive) { (void)exit(EXIT_CODE); + } return; } - argv_p = argv + argc; + argv_p = argv + arg_c; } } /* now do the list */ - do_list(grid, argc, argv, okay_p); + do_list(grid, arg_c, argv, queue_list, queue_head_p, queue_tail_p, okay_bp); /* now free up the list */ - for (argv_p = argv; argv_p < argv + argc; argv_p++) + for (argv_p = argv; argv_p < argv + arg_c; argv_p++) { free(*argv_p); + } free(argv); (void)fclose(infile); } /* - * Process an argument in MATCH_P which looking at GRID. sets okay_p to - * FALSE if the argument was not okay. + * static void do_arg + * + * DESCRIPTION: + * + * Process an argument in MATCH_P which looking at GRID. sets okay_p + * to FALSE if the argument was not okay. + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * grid -> Our array of argv_t structures. + * + * match_p -> Entry in our argv_t structure array that matches the + * specified argument. + * + * close_p -> Pointer to the value closely associated (with an '=') + * with this option or NULL if none. + * + * queue_list <-> Our option queue for storing options to arguments. + * + * queue_head_p <-> Pointer to integer which will be updated with the + * head position in our option queue. + * + * okay_bp <- Pointer to an integer which is set with 0 if the + * arguments specified in the env variable are somehow invalid. */ -LOCAL void do_arg(argv_t *grid, argv_t *match_p, const char *close_p, - char *okay_p) +static void do_arg(argv_t *grid, argv_t *match_p, const char *close_p, + argv_t **queue_list, int *queue_head_p, int *okay_bp) { if (global_multi == GLOBAL_MULTI_REJECT) { /* @@ -1440,14 +2242,15 @@ LOCAL void do_arg(argv_t *grid, argv_t *match_p, const char *close_p, * NOTE: should this be a warning or a non-error altogether? */ if (match_p->ar_type & ARGV_FLAG_USED - && (! (match_p->ar_type & ARGV_ARRAY)) + && (! (match_p->ar_type & ARGV_FLAG_ARRAY)) && ARGV_TYPE(match_p->ar_type) != ARGV_INCR) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, you've already specified the '%c' argument\n", argv_program, USAGE_ERROR_NAME, match_p->ar_short_arg); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; } } @@ -1460,7 +2263,7 @@ LOCAL void do_arg(argv_t *grid, argv_t *match_p, const char *close_p, * don't return here else we might generate an XOR error * because the argument wasn't specified */ - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; } /* @@ -1469,69 +2272,157 @@ LOCAL void do_arg(argv_t *grid, argv_t *match_p, const char *close_p, * else queue it for needing a value argument. */ if (global_close == GLOBAL_CLOSE_ENABLE && close_p != NULL) { - if (translate_value(close_p, match_p->ar_variable, - match_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; + if (string_to_value(close_p, match_p->ar_variable, + match_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } } else if (! HAS_ARG(match_p->ar_type)) { - if (translate_value(NULL, match_p->ar_variable, - match_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; + if (string_to_value(NULL, match_p->ar_variable, + match_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } } else if (global_close == GLOBAL_CLOSE_ENABLE && close_p != NULL) { - if (translate_value(close_p, match_p->ar_variable, - match_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; + if (string_to_value(close_p, match_p->ar_variable, + match_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } + } + else { + queue_list[*queue_head_p] = match_p; + (*queue_head_p)++; } - else - QUEUE_ENQUEUE(match_p); } /* - * Process a list of arguments ARGV and ARGV as it applies to ARGS. - * on NUM_ARGS members. OKAY_P is a pointer to the boolean error - * marker. + * static 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. */ -LOCAL void do_list(argv_t *grid, const int argc, char **argv, - char *okay_p) +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; - char last_arg = ARGV_FALSE; + int last_arg_b = ARGV_FALSE; char *close_p = NULL, **arg_p; /* run throught rest of arguments */ - for (arg_p = argv; arg_p < argv + argc; arg_p++) { + for (arg_p = argv; arg_p < argv + arg_c; arg_p++) { /* have we reached the LAST_ARG marker? */ - if (! last_arg && strcmp(LAST_ARG, *arg_p) == 0) { - last_arg = ARGV_TRUE; - continue; - } - - /* check for close equals marker */ - if (! last_arg && global_close == GLOBAL_CLOSE_ENABLE) { - close_p = strchr(*arg_p, ARG_EQUALS); - /* if we find the special char then punch the null and set pointer */ - if (close_p != NULL) { - *close_p = NULLC; - close_p++; + if (strcmp(LAST_ARG, *arg_p) == 0) { + if (last_arg_b) { + if (global_lasttog == GLOBAL_LASTTOG_ENABLE) { + last_arg_b = ARGV_FALSE; + continue; + } + } + else { + last_arg_b = ARGV_TRUE; + continue; } } /* are we processing a long option? */ - if (! last_arg && strncmp(LONG_PREFIX, *arg_p, LONG_PREFIX_LENGTH) == 0) { + if ((! last_arg_b) + && strncmp(LONG_PREFIX, *arg_p, LONG_PREFIX_LENGTH) == 0) { + + /* + * check for close equals marker + * + * NOTE: duplicated in the short prefix section below. In here otherwise + * we process normal args with x=5 instead of just -x=5. + */ + if (global_close == GLOBAL_CLOSE_ENABLE) { + close_p = strchr(*arg_p, ARG_EQUALS); + /* if we found the special char then punch the null and set pointer */ + if (close_p != NULL) { + *close_p = '\0'; + close_p++; + } + } /* get length of rest of argument */ len = strlen(*arg_p) - LONG_PREFIX_LENGTH; /* we need more than the prefix */ if (len <= 0) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, empty long-option prefix '%s'\n", argv_program, USAGE_ERROR_NAME, *arg_p); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; continue; } @@ -1539,18 +2430,20 @@ LOCAL void do_list(argv_t *grid, const int argc, char **argv, /* run though long options looking for a match */ for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) { - if (grid_p->ar_long_arg == NULL) + if (grid_p->ar_long_arg == NULL) { continue; + } if (strncmp(*arg_p + LONG_PREFIX_LENGTH, grid_p->ar_long_arg, len) == 0) { if (match_p != NULL) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, '%s' might be '%s' or '%s'\n", argv_program, USAGE_ERROR_NAME, *arg_p, grid_p->ar_long_arg, match_p->ar_long_arg); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; break; } @@ -1562,11 +2455,13 @@ LOCAL void do_list(argv_t *grid, const int argc, char **argv, } /* if we found a match but quit then we must have found two matches */ - if (match_p != NULL && grid_p->ar_short_arg != ARGV_LAST) + if (match_p != NULL && grid_p->ar_short_arg != ARGV_LAST) { continue; + } if (match_p != NULL) { - (void)do_arg(grid, match_p, close_p, okay_p); + (void)do_arg(grid, match_p, close_p, queue_list, queue_head_p, + okay_bp); continue; } @@ -1576,17 +2471,20 @@ LOCAL void do_list(argv_t *grid, const int argc, char **argv, if (strncmp(FILE_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (global_close == GLOBAL_CLOSE_ENABLE && close_p != NULL) { /* open the file and read in the args */ - file_args(close_p, grid, okay_p); + file_args(close_p, grid, queue_list, queue_head_p, queue_tail_p, + okay_bp); } else { /* HACK: we enqueue null for the file argument */ - QUEUE_ENQUEUE(NULL); + queue_list[*queue_head_p] = NULL; + (*queue_head_p)++; } continue; } /* check for special usage value */ - if (strncmp(USAGE_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { + if (strncmp(USAGE_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0 + || strncmp(HELP_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { do_usage(grid, global_usage); (void)exit(0); @@ -1625,12 +2523,15 @@ LOCAL void do_list(argv_t *grid, const int argc, char **argv, if (strncmp(HELP_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { if (argv_error_stream != NULL) { - if (argv_help_string == NULL) + if (argv_help_string == NULL) { (void)fprintf(argv_error_stream, "%s: I'm sorry, no help is available.\n", argv_program); - else - (void)fprintf(argv_error_stream, "%s\n", argv_help_string); + } + else { + (void)fprintf(argv_error_stream, "%s: %s\n", + argv_program, argv_help_string); + } } (void)exit(0); } @@ -1641,12 +2542,14 @@ LOCAL void do_list(argv_t *grid, const int argc, char **argv, if (strncmp(VERSION_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { if (argv_error_stream != NULL) { - if (argv_version_string == NULL) + if (argv_version_string == NULL) { (void)fprintf(argv_error_stream, "%s: no version information is available.\n", argv_program); - else + } + else { (void)fprintf(argv_error_stream, "%s\n", argv_version_string); + } } (void)exit(0); } @@ -1656,35 +2559,53 @@ LOCAL void do_list(argv_t *grid, const int argc, char **argv, /* check for display arguments value */ if (strncmp(DISPLAY_ARG, *arg_p + LONG_PREFIX_LENGTH, len) == 0) { if (argv_interactive) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { display_variables(grid); + } (void)exit(0); } continue; } - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, unknown long option '%s'.\n", argv_program, USAGE_ERROR_NAME, *arg_p); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; continue; } /* are we processing a short option? */ - if (! last_arg + if ((! last_arg_b) && strncmp(SHORT_PREFIX, *arg_p, SHORT_PREFIX_LENGTH) == 0) { + /* + * check for close equals marker + * + * NOTE: duplicated in the long prefix section above. In here otherwise + * we process normal args with x=5 instead of just -x=5. + */ + if (global_close == GLOBAL_CLOSE_ENABLE) { + close_p = strchr(*arg_p, ARG_EQUALS); + /* if we found the special char then punch the null and set pointer */ + if (close_p != NULL) { + *close_p = '\0'; + close_p++; + } + } + /* get length of rest of argument */ len = strlen(*arg_p) - SHORT_PREFIX_LENGTH; /* we need more than the prefix */ if (len <= 0) { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, empty short-option prefix '%s'\n", argv_program, USAGE_ERROR_NAME, *arg_p); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; continue; } @@ -1692,9 +2613,12 @@ LOCAL void do_list(argv_t *grid, const int argc, char **argv, for (char_c = 0; char_c < len; char_c++) { /* run through the arg list looking for a match */ - for (match_p = grid; match_p->ar_short_arg != ARGV_LAST; match_p++) - if (match_p->ar_short_arg == (*arg_p)[SHORT_PREFIX_LENGTH + char_c]) + for (match_p = grid; match_p->ar_short_arg != ARGV_LAST; match_p++) { + if (match_p->ar_short_arg == + (*arg_p)[SHORT_PREFIX_LENGTH + char_c]) { break; + } + } /* did we not find argument? */ if (match_p->ar_short_arg == ARGV_LAST) { @@ -1708,83 +2632,157 @@ LOCAL void do_list(argv_t *grid, const int argc, char **argv, continue; } + /* + * allow values with negative signs if we are at the start + * of an argument list, and if the argument is a number, and + * we already have a variable looking for a value. Thanks + * to Nick Kisseberth for + * pointing out this oversight. + */ + if (char_c == 0 && is_number(*arg_p) + && *queue_head_p > *queue_tail_p) { + + match_p = queue_list[*queue_tail_p]; + /* + * NOTE: we don't advance the queue tail here unless we + * find out that we can use it below + */ + + switch (ARGV_TYPE(match_p->ar_type)) { + + case ARGV_SHORT: + case ARGV_INT: + case ARGV_LONG: + case ARGV_FLOAT: + case ARGV_DOUBLE: + string_to_value(*arg_p, match_p->ar_variable, match_p->ar_type); + char_c = len; + /* we actually used it so we advance the queue tail position */ + (*queue_tail_p)++; + continue; + break; + } + } + /* create an error string */ - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, unknown short option '%s%c'.\n", argv_program, USAGE_ERROR_NAME, SHORT_PREFIX, (*arg_p)[SHORT_PREFIX_LENGTH + char_c]); - *okay_p = ARGV_FALSE; + } + *okay_bp = ARGV_FALSE; continue; } - do_arg(grid, match_p, close_p, okay_p); + do_arg(grid, match_p, close_p, queue_list, queue_head_p, okay_bp); } continue; } /* could this be a value? */ - if (grid->ar_short_arg != ARGV_LAST && QUEUE_COUNT() > 0) { - QUEUE_DEQUEUE(match_p); + if (grid->ar_short_arg != ARGV_LAST && *queue_head_p > *queue_tail_p) { + + /* pull the variable waiting for a value from the queue */ + match_p = queue_list[*queue_tail_p]; + (*queue_tail_p)++; + /* HACK: is this the file argument */ - if (match_p == NULL) - file_args(close_p, grid, okay_p); - else - if (translate_value(*arg_p, match_p->ar_variable, - match_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; + if (match_p == NULL) { + file_args(*arg_p, grid, queue_list, queue_head_p, queue_tail_p, + okay_bp); + } + else { + if (string_to_value(*arg_p, match_p->ar_variable, + match_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } + } continue; } /* process mandatory args if some left to process */ - for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) + for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) { if (grid_p->ar_short_arg == ARGV_MAND - && (! (grid_p->ar_type & ARGV_FLAG_USED))) + && ((! (grid_p->ar_type & ARGV_FLAG_USED)) + || grid_p->ar_type & ARGV_FLAG_ARRAY)) { break; + } + } if (grid_p->ar_short_arg != ARGV_LAST) { /* absorb another mand. arg */ - if (translate_value(*arg_p, grid_p->ar_variable, - grid_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; - if (! (grid_p->ar_type & ARGV_ARRAY)) - grid_p->ar_type |= ARGV_FLAG_USED; + if (string_to_value(*arg_p, grid_p->ar_variable, + grid_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } + grid_p->ar_type |= ARGV_FLAG_USED; continue; } /* process maybe args if some left to process */ - for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) + for (grid_p = grid; grid_p->ar_short_arg != ARGV_LAST; grid_p++) { if (grid_p->ar_short_arg == ARGV_MAYBE - && (! (grid_p->ar_type & ARGV_FLAG_USED))) + && ((! (grid_p->ar_type & ARGV_FLAG_USED)) + || grid_p->ar_type & ARGV_FLAG_ARRAY)) { break; + } + } if (grid_p->ar_short_arg != ARGV_LAST) { /* absorb another maybe arg */ - if (translate_value(*arg_p, grid_p->ar_variable, - grid_p->ar_type) != NOERROR) - *okay_p = ARGV_FALSE; - if (! (grid_p->ar_type & ARGV_ARRAY)) - grid_p->ar_type |= ARGV_FLAG_USED; + if (string_to_value(*arg_p, grid_p->ar_variable, + grid_p->ar_type) != NOERROR) { + *okay_bp = ARGV_FALSE; + } + grid_p->ar_type |= ARGV_FLAG_USED; continue; } /* default is an error */ unwant_c++; - *okay_p = ARGV_FALSE; + *okay_bp = ARGV_FALSE; } - if (unwant_c > 0 && argv_error_stream != NULL) + if (unwant_c > 0 && argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: %s, %d unwanted additional argument%s\n", argv_program, USAGE_ERROR_NAME, unwant_c, (unwant_c == 1 ? "" : "s")); + } } /****************************** env processing *******************************/ /* - * Handle the args from the ENV variable. Returns [NO]ERROR. + * static int do_env_args + * + * DESCRIPTION: + * + * Handle the args from the environmentatl variable. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * args - Array of argv_t structures we are using. + * + * queue_list <-> Our option queue for storing options to arguments. + * + * queue_head_p <-> Pointer to integer which will be updated with the + * head position in our option queue. + * + * queue_tail_p <-> Pointer to integer which will be updated with the + * tail position in our option queue. + * + * okay_bp - Pointer to an integer which is set with 0 if the + * arguments specified in the env variable are somehow invalid. */ -LOCAL int do_env_args(argv_t *args, char *okay_p) +static int do_env_args(argv_t *args, argv_t **queue_list, + int *queue_head_p, int *queue_tail_p, int *okay_bp) { int env_c, env_n; char **vect_p, env_name[256], *environ_p; @@ -1793,26 +2791,32 @@ LOCAL int do_env_args(argv_t *args, char *okay_p) (void)sprintf(env_name, ENVIRON_FORMAT, argv_program); /* NOTE: by default the env name is all uppercase */ - for (environ_p = env_name; *environ_p != NULLC; environ_p++) - if (islower((int)*environ_p)) + for (environ_p = env_name; *environ_p != '\0'; environ_p++) { + if (islower((int)*environ_p)) { *environ_p = toupper((int)*environ_p); + } + } environ_p = getenv(env_name); - if (environ_p == NULL) + if (environ_p == NULL) { return NOERROR; + } /* break the list into tokens and do the list */ environ_p = string_copy(environ_p); - if (environ_p == NULL) + if (environ_p == NULL) { return ERROR; + } vect_p = vectorize(environ_p, " \t", &env_n); if (vect_p != NULL) { - do_list(args, env_n, vect_p, okay_p); + do_list(args, env_n, vect_p, queue_list, queue_head_p, queue_tail_p, + okay_bp); /* free token list */ - for (env_c = 0; env_c < env_n; env_c++) + for (env_c = 0; env_c < env_n; env_c++) { free(vect_p[env_c]); + } free(vect_p); } free(environ_p); @@ -1821,610 +2825,594 @@ LOCAL int do_env_args(argv_t *args, char *okay_p) } /* - * Process the global env variable. Returns [NO]ERROR. + * static int process_env + * + * DESCRIPTION: + * + * Process the global env variables. + * + * RETURNS: + * + * Success - 0 + * + * Faulure - -1 + * + * ARGUMENTS: + * + * None. */ -LOCAL int process_env(void) +static int process_env(void) { - static char done = ARGV_FALSE; - char *environ_p, *env_p, *arg; + static int done_b = ARGV_FALSE; + char *environ, *tok_p, *env_p; int len; /* make sure we only do this once */ - if (done) + if (done_b) { return NOERROR; + } - done = ARGV_TRUE; + done_b = ARGV_TRUE; /* get the argv information */ - environ_p = getenv(GLOBAL_NAME); - if (environ_p == NULL) + environ = getenv(GLOBAL_NAME); + if (environ == NULL) { return NOERROR; + } /* save a copy of it */ - environ_p = string_copy(environ_p); - if (environ_p == NULL) + environ = string_copy(environ); + if (environ == NULL) { return ERROR; + } - arg = environ_p; + env_p = environ; for (;;) { - env_p = strtok(arg, " \t,:"); - if (env_p == NULL) + tok_p = my_strsep(&env_p, " \t,:"); + if (tok_p == NULL) { break; - arg = NULL; + } + /* skip any empty tokens */ + if (*tok_p == '\0') { + continue; + } len = strlen(GLOBAL_CLOSE); - if (strncmp(GLOBAL_CLOSE, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "disable") == 0) + if (strncmp(GLOBAL_CLOSE, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "disable") == 0 + || strcmp(tok_p, "off") == 0 + || strcmp(tok_p, "no") == 0 + || strcmp(tok_p, "0") == 0) { global_close = GLOBAL_CLOSE_DISABLE; - else if (strcmp(env_p, "enable") == 0) + } + else if (strcmp(tok_p, "enable") == 0 + || strcmp(tok_p, "on") == 0 + || strcmp(tok_p, "yes") == 0 + || strcmp(tok_p, "1") == 0) { global_close = GLOBAL_CLOSE_ENABLE; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_CLOSE, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_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, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "none") == 0) + if (strncmp(GLOBAL_ENV, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "none") == 0) { global_env = GLOBAL_ENV_NONE; - else if (strcmp(env_p, "before") == 0) + } + else if (strcmp(tok_p, "before") == 0) { global_env = GLOBAL_ENV_BEFORE; - else if (strcmp(env_p, "after") == 0) + } + else if (strcmp(tok_p, "after") == 0) { global_env = GLOBAL_ENV_AFTER; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_ENV, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_ENV, tok_p); + } } continue; } len = strlen(GLOBAL_ERROR); - if (strncmp(GLOBAL_ERROR, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "none") == 0) + if (strncmp(GLOBAL_ERROR, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "none") == 0) { global_error = GLOBAL_ERROR_NONE; - else if (strcmp(env_p, "see") == 0) + } + else if (strcmp(tok_p, "see") == 0) { global_error = GLOBAL_ERROR_SEE; - else if (strcmp(env_p, "short") == 0) + } + else if (strcmp(tok_p, "short") == 0) { global_error = GLOBAL_ERROR_SHORT; - else if (strcmp(env_p, "shortrem") == 0) + } + else if (strcmp(tok_p, "shortrem") == 0) { global_error = GLOBAL_ERROR_SHORTREM; - else if (strcmp(env_p, "long") == 0) + } + else if (strcmp(tok_p, "long") == 0) { global_error = GLOBAL_ERROR_LONG; - else if (strcmp(env_p, "all") == 0) + } + else if (strcmp(tok_p, "all") == 0) { global_error = GLOBAL_ERROR_ALL; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_ERROR, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_ERROR, tok_p); + } } continue; } len = strlen(GLOBAL_MULTI); - if (strncmp(GLOBAL_MULTI, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "reject") == 0) + if (strncmp(GLOBAL_MULTI, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "reject") == 0) { global_multi = GLOBAL_MULTI_REJECT; - else if (strcmp(env_p, "accept") == 0) + } + else if (strcmp(tok_p, "accept") == 0) { global_multi = GLOBAL_MULTI_ACCEPT; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_MULTI, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_MULTI, tok_p); + } } continue; } len = strlen(GLOBAL_USAGE); - if (strncmp(GLOBAL_USAGE, env_p, len) == 0) { - env_p += len; - if (strcmp(env_p, "short") == 0) + if (strncmp(GLOBAL_USAGE, tok_p, len) == 0) { + tok_p += len; + if (strcmp(tok_p, "short") == 0) { global_usage = GLOBAL_USAGE_SHORT; - else if (strcmp(env_p, "shortrem") == 0) + } + else if (strcmp(tok_p, "shortrem") == 0) { global_usage = GLOBAL_USAGE_SHORTREM; - else if (strcmp(env_p, "long") == 0) + } + else if (strcmp(tok_p, "long") == 0) { global_usage = GLOBAL_USAGE_LONG; - else if (strcmp(env_p, "all") == 0) + } + else if (strcmp(tok_p, "all") == 0) { global_usage = GLOBAL_USAGE_ALL; + } else { - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' '%s' argument '%s'\n", - __FILE__, GLOBAL_NAME, GLOBAL_USAGE, env_p); + __FILE__, GLOBAL_NAME, GLOBAL_USAGE, tok_p); + } } continue; } - if (argv_error_stream != NULL) + if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: illegal env variable '%s' setting '%s'\n", - __FILE__, GLOBAL_NAME, env_p); - } - - free(environ_p); - return NOERROR; -} - -/* - * Processes ARGS from ARGC and ARGV. Returns 0 if no error else -1. - */ -LOCAL int process_args(argv_t *args, const int argc, char **argv) -{ - int num_args; - const char *prog_p; - char okay = ARGV_TRUE; - argv_t *arg_p; - - if (process_env() != NOERROR) - return ERROR; - - if (args == NULL) - args = empty; - - if (argc < 0) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: %s, argc argument to argv_process is %d\n", - __FILE__, INTERNAL_ERROR_NAME, argc); - if (argv_interactive) - (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 = argc; - - /* build the program name from the argv[0] path */ - { - const char *tmp_p; - - prog_p = *argv; - for (tmp_p = *argv; *tmp_p != NULLC; tmp_p++) - if (*tmp_p == '/') - prog_p = tmp_p + 1; - } - - /* so we can step on the environmental space */ - (void)strncpy(argv_program, prog_p, PROGRAM_NAME); - - /* count the args */ - num_args = 0; - for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) - num_args++; - - /* verify the argument array */ - if (preprocess_array(args, num_args) != NOERROR) - return ERROR; - - /* allocate our value queue */ - if (num_args > 0) - QUEUE_ALLOC(argv_t *, num_args); - - /* do the env args before? */ - if (global_env == GLOBAL_ENV_BEFORE) { - if (do_env_args(args, &okay) != NOERROR) - return ERROR; - } - - /* do the external args */ - do_list(args, argc - 1, argv + 1, &okay); - - /* do the env args after? */ - if (global_env == GLOBAL_ENV_AFTER) { - do_env_args(args, &okay); - if (do_env_args(args, &okay) != NOERROR) - return ERROR; - } - - /* make sure the XOR and MAND args and argument-options are okay */ - if (check_mand(args) != NOERROR) - okay = ARGV_FALSE; - if (check_opt() != NOERROR) - okay = ARGV_FALSE; - if (check_xor(args) != NOERROR) - okay = ARGV_FALSE; - - /* if we allocated the space then free it */ - if (num_args > 0) - QUEUE_FREE(); - - /* was there an error? */ - if (! okay) { - if (argv_error_stream != NULL) - do_usage(args, global_error); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; + __FILE__, GLOBAL_NAME, tok_p); + } } + free(environ); return NOERROR; } /***************************** exported routines *****************************/ /* - * Processes ARGC number of arguments from ARGV depending on argument - * info array ARGS (if null then an empty array is used). This - * routine will not modify the argv array in any way. + * int argv_process_no_env * - * NOTE: it will modify the args array by setting various flags in the - * type field. returns 0 if no error else -1. - */ -EXPORT int argv_process(argv_t *args, const int argc, char **argv) -{ - if (! enabled) - argv_startup(); - - if (process_args(args, argc, argv) == NOERROR) - return NOERROR; - else - return ERROR; -} - -/* - * Processes arguments sent in via the STRING that a web-server might - * send to program in ARG0. Use DELIM to set up the delimiters of the - * arguments in the string. query_string processing should have "&" - * and path_info should have "/". You may want to add "=" if you use - * arg=value. The '=' delimiter is treated as special so //x=// will - * strip the extra /'s in a row but will create a null argument for x. + * DESCRIPTION: * - * 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) - argv_startup(); - - if (delim == NULL) - delim_str = ""; - else - delim_str = delim; - - /* copy incoming string so we can punch nulls */ - copy = malloc(strlen(string) + 1); - if (copy == NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; - } - - /* create argv array */ - alloced = ARG_MALLOC_INCR; - argv = (char **)malloc(sizeof(char *) * alloced); - if (argv == NULL) { - free(copy); - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; - } - - argc = 0; - argv[argc++] = (char *)arg0; - str_p = string; - /* skip starting multiple arg delimiters */ - for (; *str_p != NULLC; str_p++) { - for (delim_p = delim_str; *delim_p != NULLC; delim_p++) - if (*str_p == *delim_p) - break; - if (*delim_p == NULLC) - break; - } - - /* 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; - } - - 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; - } - - ret = process_args(args, argc, argv); - - free(copy); - free(argv); - - if (ret == NOERROR) - return NOERROR; - else - return ERROR; -} - -/* - * 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. - */ -EXPORT int argv_web_process(argv_t *args, const char *arg0) -{ - char *env, *work = NULL; - int ret, len; - - if (! enabled) - argv_startup(); - - env = getenv("REQUEST_METHOD"); - if (env != NULL && strcmp(env, "POST") == 0) { - env = getenv("CONTENT_LENGTH"); - if (env != NULL) { - len = atoi(env); - if (len > 0) { - work = (char *)malloc(len + 1); - if (work == NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; - } - (void)read(STDIN, work, len); - work[len] = NULLC; - } - } - } - - if (work == NULL) { - env = getenv("QUERY_STRING"); - - /* if it is not set or empty, then nothing to do */ - if (env == NULL || *env == NULLC) { - work = (char *)malloc(1); - if (work == NULL) { - if (argv_error_stream != NULL) - (void)fprintf(argv_error_stream, - "%s: memory error during argument processing\n", - argv_program); - if (argv_interactive) - (void)exit(EXIT_CODE); - return ERROR; - } - work[0] = NULLC; - } - else { - work = string_copy(env); - if (work == NULL) - return ERROR; - } - } - - ret = argv_web_process_string(args, arg0, work, "&="); - free(work); - - if (ret == NOERROR) - return NOERROR; - else - return ERROR; -} - -/* - * 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). + * Process the user arguments with an argv_t structure array. Like + * argv_process_args but without the processing of the argv + * environmental variables. * - * NOTE: if this is called before argv_process then the program name may - * be messed up. + * 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. */ -EXPORT int argv_usage(const argv_t *args, const int which) +int argv_process_no_env(argv_t *args, const int arg_c, char **argv) { - if (! enabled) - argv_startup(); + 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 (process_env() != NOERROR) - return ERROR; - - if (args == NULL) + 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); + 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; } /* - * See if ARG argument was used in a previous call to argv_process on - * ARGS. Returns 1 if yes else 0. + * int argv_process + * + * DESCRIPTION: + * + * Processes a number of arguments depending on the argument array. + * This routine will not modify the argv array in any way. + * + * NOTE: it will modify the args array by setting various flags in the + * type field. returns 0 if no error else -1. + * + * ARGUMENTS: + * + * args - Array of argv_t structures that we are using to process the + * user argument array. If null then an empty array is used. + * + * argc - Number of arguments in the argv argument array. + * + * argv - Array of character pointer arguments terminated by a 0L. */ -EXPORT int argv_was_used(const argv_t *args, const char arg) +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) + if (! enabled_b) { argv_startup(); + } - for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) - if (arg_p->ar_short_arg == arg) { - if (arg_p->ar_type & ARGV_FLAG_USED) + for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { + if (arg_p->ar_short_arg == short_arg) { + if (arg_p->ar_type & ARGV_FLAG_USED) { return 1; - else + } + else { return 0; + } } + } return 0; } /* - * Frees up any allocations in ARGS that may have been done by + * 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. */ -EXPORT void argv_cleanup(const argv_t *args) +void argv_cleanup(const argv_t *args) { const argv_t *arg_p; int entry_c; - if (! enabled) + if (! enabled_b) { argv_startup(); + } - if (args == NULL) + if (args == NULL) { return; + } /* run through the argument structure */ for (arg_p = args; arg_p->ar_short_arg != ARGV_LAST; arg_p++) { /* handle any arrays */ - if (arg_p->ar_type & ARGV_ARRAY) { + if (arg_p->ar_type & ARGV_FLAG_ARRAY) { argv_array_t *arr_p = (argv_array_t *)arg_p->ar_variable; /* free any entries */ - if (arr_p->aa_entryn > 0) { - if (ARGV_TYPE(arg_p->ar_type) == ARGV_CHARP) { - for (entry_c = 0; entry_c < arr_p->aa_entryn; entry_c++) + if (arr_p->aa_entry_n > 0) { + if (ARGV_TYPE(arg_p->ar_type) == ARGV_CHAR_P) { + for (entry_c = 0; entry_c < arr_p->aa_entry_n; entry_c++) { free(ARGV_ARRAY_ENTRY(*arr_p, char *, entry_c)); + } } free(arr_p->aa_entries); } arr_p->aa_entries = NULL; - arr_p->aa_entryn = 0; + arr_p->aa_entry_n = 0; continue; } /* handle individual charps */ if (arg_p->ar_type & ARGV_FLAG_USED - && ARGV_TYPE(arg_p->ar_type) == ARGV_CHARP) { + && ARGV_TYPE(arg_p->ar_type) == ARGV_CHAR_P) { free(*(char **)arg_p->ar_variable); continue; } @@ -2432,44 +3420,102 @@ EXPORT void argv_cleanup(const argv_t *args) } /* - * Copy all the args (after the 0th), one after the other, into BUF of - * MAX_SIZE. Returns 0 on no error else -1. + * int argv_copy_args * - * NOTE: you can get the 0th argument from argv_argv[0]. + * 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. */ -EXPORT int argv_copy_args(char *buf, const int max_size) +int argv_copy_args(char *buf, const int buf_size) { char **argv_p, *buf_p = buf, *arg_p; - int argc, size_c = max_size; + int arg_c, size_c = buf_size; - if (! enabled) + if (! enabled_b) { argv_startup(); + } - if (process_env() != NOERROR) + if (buf_size <= 0) { + return NOERROR; + } + + *buf_p = '\0'; + + if (process_env() != NOERROR) { return ERROR; + } - if (max_size == 0) + if (argv_argv == NULL || buf_size == 1) { return NOERROR; + } - *buf_p = NULLC; + for (argv_p = argv_argv + 1, arg_c = 1; + arg_c < argv_argc; + argv_p++, arg_c++) { - if (argv_argv == NULL || max_size == 1) - return NOERROR; - - for (argv_p = argv_argv + 1, argc = 1; argc < argv_argc; argv_p++, argc++) { - - if (size_c < 2) + /* we compare against 2 for the ' ' and the \0 */ + if (size_c < 2) { break; + } if (argv_p > argv_argv + 1) { *buf_p++ = ' '; size_c--; } - for (arg_p = *argv_p; *arg_p != NULLC && size_c >= 2; size_c--) + /* we always compare against 2 to include the \0 */ + for (arg_p = *argv_p; *arg_p != '\0' && size_c >= 2; size_c--) { *buf_p++ = *arg_p++; + } } - *buf_p = NULLC; + *buf_p = '\0'; return NOERROR; } + +/* + * int argv_value_string + * + * DESCRIPTION: + * + * Convert the value of a RC entry to its string equivalent in the + * buffer provided. + * + * RETURNS: + * + * Length of bytes copied into the buffer. + * + * ARGUMENTS: + * + * argv_entry_p - Pointer to an entry in a argv_t list. + * + * buf - Buffer to convert the value into. + * + * buf_size - Size of the buffer. + */ +int argv_value_string(const argv_t *argv_entry_p, char *buf, + const int buf_size) +{ + if (! enabled_b) { + argv_startup(); + } + + return value_to_string(argv_entry_p->ar_variable, argv_entry_p->ar_type, + buf, buf_size); +} diff --git a/libargv/argv.h b/libargv/argv.h index 868557a..9f2943e 100644 --- a/libargv/argv.h +++ b/libargv/argv.h @@ -1,90 +1,398 @@ /* - * $Source$ - * $Revision$ - * $Date$ + * $Source$ + * $Revision$ + * $Date$ * - * Copyright (C) 1995 by Gray Watson + * 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. */ -#ifndef __LIB_ARGV_H__ -#define __LIB_ARGV_H__ 1 - -#include - -/********** Prototypes **********/ - -#define ARGV_PNT void * - -typedef struct { - char ar_short_arg; /* the char of the arg, 'd' if '-d' */ - char *ar_long_arg; /* long version of arg, 'delete' */ - short ar_type; /* type of option, see values below */ - ARGV_PNT ar_variable; /* address of variable that is arg */ - char *ar_var_label; /* label for variable descriptions */ - char *ar_comment; /* comment for usage message */ -} argv_t; - -typedef struct { - int aa_entryn; /* number of elements in aa_entrees */ - ARGV_PNT aa_entries; /* entry list specified */ -} argv_array_t; - -#define ARGV_ARRAY_COUNT(array) ((array).aa_entryn) -#define ARGV_ARRAY_ENTRY(array, type, which) \ - (((type *)(array).aa_entries)[which]) -#define ARGV_LAST ((char)255) -#define ARGV_MAND ((char)254) -#define ARGV_MAYBE ((char)253) -#define ARGV_OR ((char)252) -#define ARGV_ONE_OF ((char)251) -#define ARGV_XOR ((char)251) -#define ARGV_BOOL 1 /* boolean type, sets to ARGV_TRUE */ -#define ARGV_BOOL_NEG 2 /* like bool but sets to ARGV_FALSE */ -#define ARGV_BOOL_ARG 3 /* like bool but takes a yes/no arg */ -#define ARGV_CHAR 4 /* single character */ -#define ARGV_CHARP 5 /* same as STRING */ -#define ARGV_STRING 5 /* character string */ -#define ARGV_FLOAT 6 /* floating pointer number */ -#define ARGV_SHORT 7 /* integer number */ -#define ARGV_INT 8 /* integer number */ -#define ARGV_U_INT 9 /* unsigned integer number */ -#define ARGV_LONG 10 /* long integer number */ -#define ARGV_U_LONG 11 /* unsinged long integer number */ -#define ARGV_BIN 12 /* binary number (0s and 1s) */ -#define ARGV_OCT 13 /* octal number, (base 8) */ -#define ARGV_HEX 14 /* hexadecimal number, (base 16) */ -#define ARGV_INCR 15 /* int arg which gets ++ each time */ -#define ARGV_TYPE(t) ((t) & 0x3F) /* strip off all but the var type */ -#define ARGV_ARRAY (1 << 14) /* OR with type to indicate array */ -#define ARGV_USAGE_SHORT 1 /* print short usage messages */ -#define ARGV_USAGE_LONG 2 /* print long-format usage messages */ -#define ARGV_USAGE_DEFAULT 3 /* default usage messages */ -#define ARGV_FALSE 0 -#define ARGV_TRUE 1 +#ifndef __ARGV_H__ +#define __ARGV_H__ #ifdef __cplusplus extern "C" { #endif -extern char argv_program[/* PROGRAM_NAME + 1 */]; -extern char **argv_argv; -extern int argv_argc; -extern char *argv_help_string; -extern char *argv_version_string; -extern char argv_interactive; -extern FILE *argv_error_stream; -extern int argv_process(argv_t *args, const int argc, char **argv); -extern int argv_web_process_string(argv_t *args, const char *arg0, - const char *string, - const char *delim); -extern int argv_web_process(argv_t *args, const char *arg0); -extern int argv_usage(const argv_t *args, const int which); -extern int argv_was_used(const argv_t *args, const char arg); -extern void argv_cleanup(const argv_t *args); -extern int argv_copy_args(char *buf, const int max_size); +/* + * Version string for the library + * + * NOTE to gray: whenever this is changed, corresponding Changlog and + * NEWS entries *must* be entered and 2 entries in argv.texi must be + * updated. + * + * ARGV LIBRARY VERSION -- 2.4.0 + */ + +/* + * Generic and standardized argument processor. You describe the arguments + * that you are looking for along with their types and these routines do the + * work to convert them into values. + * + * These routines also provide standardized error and usage messages as well + * as good usage documentation and long and short options. + */ + +#include /* have to for FILE * below */ + +/* this defines what type the standard void memory-pointer is */ +typedef void * ARGV_PNT; + +/* + * argument information structure. this specifies the allowable options + * and some information about each one. + * + * { 'O', "optimize", ARGV_BOOL, &optimize, NULL, "turn on optimization" } + * { 'c', "config", ARGV_CHAR_P, &config, "file", "configuration file" } + */ +typedef struct { + char ar_short_arg; /* the char of the arg, 'd' if '-d' */ + char *ar_long_arg; /* long version of arg, 'delete' */ + unsigned int ar_type; /* type of option, see values below */ + ARGV_PNT ar_variable; /* address of variable that is arg */ + char *ar_var_label; /* label for variable descriptions */ + char *ar_comment; /* comment for usage message */ +} argv_t; + +/* + * argument array type. when ARGV_ARRAY is |'d with the ar_type in the above + * structure then multiple instances of the option are allowed and each + * instance is stored into the following structure that MUST be in ar_variable + * in the above arg_t structure. + * NOTE: after the arguments have been processed, if aa_entryn is > 0 then + * aa_entries needs to be free'd by user. argv_cleanup() can be used for this + */ +typedef struct { + int aa_entry_n; /* number of elements in aa_entrees */ + ARGV_PNT aa_entries; /* entry list specified */ +} argv_array_t; + +/* extract the count of the elements from an argv ARRAY */ +#define ARGV_ARRAY_COUNT(array) ((array).aa_entry_n) + +/* extract WHICH entry of TYPE from an argv ARRAY */ +#define ARGV_ARRAY_ENTRY(array, type, which) \ + (((type *)(array).aa_entries)[which]) + +/* extract a pointer to WHICH entry of TYPE from an argv ARRAY */ +#define ARGV_ARRAY_ENTRY_P(array, type, which) \ + (((type *)(array).aa_entries) + which) + +/* special ar_short_arg value to mark the last entry in the argument array */ +#define ARGV_LAST ((char)255) + +/* + * special ar_short_arg value to mark mandatory arguments (i.e. arguments that + * *must* be specified. for arguments that are not optional like [-b]. + * to have a variable number of mandatory args then make the last MAND + * entry be a ARG_ARRAY type. + */ +#define ARGV_MAND ((char)254) + +/* + * special ar_short_arg value to mark that there is the possibility of + * a mandatory argument here if one is specified. + */ +#define ARGV_MAYBE ((char)253) + +/* + * special ar_short_arg value to say that the previous and next arguments in + * the list should not be used together. + * {'a'...}, {ARG_OR}, {'b'...}, {ARG_OR}, {'c'...} means + * the user should only specific -a or -b or -c but not 2 or more. + */ +#define ARGV_OR ((char)252) + +/* + * special ar_short_arg value that is the same as ARGV_OR but one of the args + * must be used. + * {'a'...}, {ARG_ONE_OF}, {'b'...}, {ARG_ONE_OF}, {'c'...} means + * the user must specify one of -a or -b or -c but not 2 or more. + * ARGV_XOR is there for compatibility with older versions. + */ +#define ARGV_ONE_OF ((char)251) +#define ARGV_XOR ((char)251) + +/* + * ar_type values of arg_t + * NOTE: if this list is changed, some defines in argv_loc need to be changed + */ +#define ARGV_BOOL 1 /* boolean type, sets to ARGV_TRUE */ +#define ARGV_BOOL_NEG 2 /* like bool but sets to ARGV_FALSE */ +#define ARGV_BOOL_ARG 3 /* like bool but takes a yes/no arg */ +#define ARGV_CHAR 4 /* single character */ +#define ARGV_CHAR_P 5 /* same as STRING */ +#define ARGV_SHORT 6 /* short integer number */ +#define ARGV_U_SHORT 7 /* unsigned short integer number */ +#define ARGV_INT 8 /* integer number */ +#define ARGV_U_INT 9 /* unsigned integer number */ +#define ARGV_LONG 10 /* long integer number */ +#define ARGV_U_LONG 11 /* unsinged long integer number */ +#define ARGV_FLOAT 12 /* floating pointer number */ +#define ARGV_DOUBLE 13 /* double floating pointer number */ +#define ARGV_BIN 14 /* binary number (0s and 1s) */ +#define ARGV_OCT 15 /* octal number, (base 8) */ +#define ARGV_HEX 16 /* hexadecimal number, (base 16) */ +#define ARGV_INCR 17 /* int arg which gets ++ each time */ +#define ARGV_SIZE 18 /* long arg which knows mMbBkKgG */ +#define ARGV_U_SIZE 19 /* u_long arg which knows mMbBkKgG */ +#define ARGV_BOOL_INT 20 /* like bool but takes an integer var*/ +#define ARGV_BOOL_INT_NEG 21 /* like bool-neg but with an integer */ +#define ARGV_BOOL_INT_ARG 22 /* like bool-arg but with an integer */ + +#define ARGV_TYPE(t) ((t) & 0x3F) /* strip off all but the var type */ +#define ARGV_FLAG_ARRAY (1 << 14) /* OR with type to indicate array */ +#define ARGV_FLAG_MAND (1 << 13) /* OR with type to mark mandatory */ +/* NOTE: other internal flags defined in argv_loc.h */ + +/* argv_usage which argument values */ +#define ARGV_USAGE_SHORT 1 /* print short usage messages */ +#define ARGV_USAGE_LONG 2 /* print long-format usage messages */ +#define ARGV_USAGE_DEFAULT 3 /* default usage messages */ + +/* boolean type settings */ +#define ARGV_FALSE 0 +#define ARGV_TRUE 1 + +/*<<<<<<<<<< The below prototypes are auto-generated by fillproto */ + +/* This is a processed version of argv[0], pre-path removed: /bin/ls -> ls */ +extern +char argv_program[/* PROGRAM_NAME + 1 */]; + +/* A global value of argv from main after argv_process has been called */ +extern +char **argv_argv; + +/* A global value of argc from main after argv_process has been called */ +extern +int argv_argc; + +/* This should be set externally to provide general program help to user */ +extern +char *argv_help_string; + +/* This should be set externally to provide version information to the user */ +extern +char *argv_version_string; + +/* + * Are we running interactively? This will exit on errors. Set to + * false to return error codes instead. + */ +extern +int argv_interactive; + +/* + * The FILE stream that argv out_puts all its errors. Set to NULL to + * not dump any error messages. Default is stderr. + */ +extern +FILE *argv_error_stream; + +/* + * 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. + */ +extern +int argv_process_no_env(argv_t *args, const int arg_c, char **argv); + +/* + * 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. + */ +extern +int argv_process(argv_t *args, const int argc, char **argv); + +/* + * 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). + */ +extern +int argv_usage(const argv_t *args, const int which); + +/* + * 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. + */ +extern +int argv_was_used(const argv_t *args, const char short_arg); + +/* + * 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. + */ +extern +int argv_long_was_used(const argv_t *args, const char *long_arg); + +/* + * 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. + */ +extern +void argv_cleanup(const argv_t *args); + +/* + * 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. + */ +extern +int argv_copy_args(char *buf, const int buf_size); + +/* + * 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. + */ +extern +int argv_value_string(const argv_t *argv_entry_p, char *buf, + const int buf_size); + +/*<<<<<<<<<< This is end of the auto-generated output from fillproto. */ #ifdef __cplusplus } #endif -#endif /* !__LIB_ARGV_H__ */ +#endif /* ! __ARGV_H__ */ diff --git a/libargv/argv.texi b/libargv/argv.texi new file mode 100644 index 0000000..cb74bdc --- /dev/null +++ b/libargv/argv.texi @@ -0,0 +1,833 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename argv.info +@settitle Argv Tutorial +@c %**end of header + +@c ================================================================ +@c This file has the new style title page commands. +@c Also, it uses `@@include' files instead of `@@input' files. + +@c Run using special version of `texinfo.tex'. + +@c Also, run `makeinfo' rather than `texinfo-format-buffer'. +@c ================================================================ + +@c ================================================================ +@c $Id$ +@c ================================================================ + +@ifinfo +This file is an introduction to the Argv library which handles the +process of command-line arguments. + +Copyright 1992 to 1998 by Gray Watson. + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries a copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +chapter entitled ``Copying'' are included exactly as in the original, +and provided that the entire resulting derived work is distributed under +the terms of a permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that the chapter entitled ``Copying'' may be included in a +translation approved by the author instead of in the original English. +@end ifinfo + +@titlepage +@title Argv Library +@subtitle Version 2.4.0 +@subtitle October 1998 +@author Gray Watson + +@page +Copyright 1992 to 1998 by Gray Watson. + +Published by Gray Watson + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +chapter entitled ``Copying'' are included exactly as in the original, +and provided that the entire resulting derived work is distributed under +the terms of a permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that the chapter entitled ``Copying'' may be included in a +translation approved by the author instead of in the original English. +@end titlepage + +@node Top, Copying, (dir), (dir) +@top Argv Library + +@ifinfo +Version 2.4.0 -- October 1998 +@end ifinfo + +@cindex introduction +@cindex author + +The argv library has been designed to handle the argument processing +needs of most Unix software and to provide a consistent usage framework +for user applications. + +The library is reasonably portable having been run successfully on at +least the following operating systems: AIX, BSDI, DG/UX, FreeBSD, HPUX, +Irix, Linux, MS-DOG, NeXT, OSF, Solaris, SunOS, Ultrix, Unixware, and +even Unicos on a Cray Y-MP. + +The package includes the library, configuration scripts, shell-script +utility application, test program, and extensive documentation (text, +texi, info, ps). Documentation is available online at URL +@code{http://www.letters.com/argv/}. + +The library is available via ftp from @samp{ftp.letters.com} in the +@file{/src/argv} directory. @xref{How To Get}. I can be reached via my +web page @samp{http://www.letters.com/~gray/} with any questions or +feedback. Please include the version number of the library that you are +using as well as your machine and operating system types. + +Gray Watson. + +@menu +* Copying:: Library copying conditions. +* Overview:: Description of how to use the library. +* Details:: Details about the library's operations. +* General Usage:: Invoking Programs Which Use the Library. +* Plugs:: A couple soapbox comments. +* Index of Concepts:: Index of concepts in the manual. +@ifinfo +* Full Node Listings:: Listing of all the nodes in the manual. +@end ifinfo +@end menu + +@node Copying, Overview, Top, Top +@chapter Library Copying Conditions + +@cindex copying +@cindex license +@cindex library permissions +@cindex permissions of the library + +Copyright 1992 to 1998 by Gray Watson. + +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. The name of Gray Watson cannot be +used in advertising or publicity pertaining to distribution of the +document or software without specific, written prior permission. + +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. + +@node Overview, Details, Copying, Top +@chapter How to Use the Library + +@menu +* Concepts:: General concepts behind the library. +* How To Get:: How to get the library. +* Installation:: How to install the library. +* Getting Started:: Getting started with the library. +@end menu + +@node Concepts, How To Get, Overview, Overview +@section The General Concepts Behind the Library + +@cindex command line arguments +@cindex unix command line + +One thing that almost all Unix executables need to do is process the +@dfn{command line arguments}. Whether this is to enable verbose mode or +specify the files for a utility to work on, code has to be written to +process these user specified options. + +@example + int main(int argc, char **argv) + @{ + ... + @} +@end example + +As you must know, the command line arguments in most Unix systems are +passed in as arguments to @code{main()} (seen above). The @code{argc} +integer argument contains the number of arguments specified. The +@code{argv} variable holds the arguments themselves. It can be thought +of as a pointer to a list of character pointers -- or an array of +character pointers. + +To get a particular argument from @code{argv}, you use @code{argv[x]} +where @code{x} is an integer whose value is from 0 to @code{argc - 1}. +In most Unix implementations, the zeroth argument is always the name the +program was executed with. For instance, if you typed @samp{./ls -al}, +@code{argc} would equal 2 and the value of @code{argv[0]} would be +@samp{"./ls"}. The value for @code{argv[1]} would be @samp{"-al"}. + +@cindex getopt +Currently, most programmers either write code on a per program basis to +process arguments or they use the @code{getopt()} routine. Writing +argument processing code for each program results in improper and +inconsistent argument handling. Although better, @code{getopt()} does +not provide the structure needed to ensure conformity in argument +processing and still requires significant code to be written by the +programmer. + +The goal for this library was to achieve a standardized way of +processing arguments -- especially in terms of error and usage messages. +Important consideration was also given to reducing the programming time +necessary to enable the functionality. + +@node How To Get, Installation, Concepts, Overview +@section How to get the library. + +@cindex downloading the library +@cindex getting the source + +The newest versions of the argv library are available via anonymous ftp +from @samp{ftp.letters.com} in the @file{/src/argv} directory. + +@cindex anonymous ftp +@cindex ftp + +To use anonymous ftp, you ftp to the site and when the system prompts +you for a login-id or username you enter @kbd{anonymous}. When it +prompts you for a password you enter your email address. You then can +change-directory (cd) into @file{/src/argv} and get the @file{README} +and @file{argv.tar.gz} files. + +The versions in this repository also include such files as a +postscript version of the manual and other large files which may not +have been included in the distribution you received. + +@node Installation, Getting Started, How To Get, Overview +@section Installing the Library + +@cindex installing the library +@cindex compiling the library +@cindex building the library +@cindex configuring the library +@cindex making the library + +To configure, compile, and install the library, follow these steps +carefully. + +@enumerate + +@cindex configure script +@cindex conf.h file + +@item Type @kbd{sh ./configure} to configure the library. You may want +to first examine the @file{config.help} file for some information about +configure. Configure should generate the @file{Makefile} and some +configuration files automatically. + +@emph{NOTE}: It seems that some versions of tr (especially from HP-UX) +don't understand @code{tr '[a-z]' '[A-Z]'}. Since configure uses tr +often, you may need to either get GNU's tr (in their textutils package) +or generate the @file{Makefile} and @file{conf.h} files by hand. + +@item You may want to examine the @file{Makefile} and @file{conf.h} files +created by configure to make sure it did its job correctly. + +@item Typing @kbd{make} should be enough to build @file{libargv.a} +and the @file{argv_shell} utility. If it does not work, please send me +some notes so future users can profit from your experiences. + +@cindex ANSI-C compiler +@cindex Deansify.pl script + +@emph{NOTE}: The code is pretty dependent on a good ANSI-C compiler. If +the configure script gives the @samp{WARNING} that you do not have an +ANSI-C compiler, you may still be able to add some sort of option to +your compiler to make it ANSI. If there such is an option, please send +it to the author so it can be added to the configure script. Otherwise, +you will have to try @kbd{make noansi}. This will run the +@file{Deansify.pl} perl script on the code which: + +@itemize @bullet +@item @emph{WARNING}: modifies the source code in place +@item changes all @code{void *} references to @code{char *}. +@item fixes all functions to remove @code{foo(char * var)} declarations. +@end itemize + +If it doesn't work you may have to do Deansify.pl's job by hand. + +@item Typing @kbd{make tests} should build the @file{argv_t} test +program. This can be run and given arguments to test the various +library features. + +@item Typing @kbd{make install} should install the @file{libargv.a} +library in @file{/usr/local/lib}, the @file{argv_shell} utility in +@file{/usr/local/bin}, and the @file{argv.info} documentation file in +@file{/usr/local/info}. + +You may have specified a @samp{--prefix=PATH} option to configure in +which can @samp{/usr/local} will have been replaced with @samp{PATH}. + +@end enumerate + +See the Getting Started section to get up and running with the library. +@xref{Getting Started}. + +@node Getting Started, , Installation, Overview +@section Getting Started with the Library + +@cindex quick start +@cindex getting started +@cindex jump start +@cindex how to begin +@cindex where to begin + +This section should give you a quick idea on how to get going. + +@enumerate + +@item Make sure you have the latest version of the library. It is +available via anonymous ftp from @samp{ftp.letters.com} in the +@file{/src/argv} directory. @xref{How To Get}. + +@item Follow the installation instructions on how to configure and +make and install the library (i.e. type: @kbd{make install}). +@xref{Installation}. + +@item Examine the @file{argv_t.c} test program source to see an +example of how to program with the library. After adding the +appropriate @code{argv_t} structure array to your main source file, you +need to compile and link your programs with the library. + +@item The first time your program is run, the library makes a number +of checks as to the validity of the argument structures being used. You +may have to note and fix reported problems. + +@item Run your program with the @samp{--usage} argument and voila. + +@end enumerate + +@node Details, General Usage, Overview, Top +@chapter The Library's Operations + +@menu +* Argv_t Structure:: The argv_t structure and it's usage. +* Special Short Args:: The special ar_short_arg values. +* Types of Variables:: The different variable types. +* Variable Arrays:: Using arguments which ``absorb'' arrays. +@end menu + +@node Argv_t Structure, Special Short Args, Details, Details +@section The argv_t Structure and It's Usage + +The argv_t argument structure is as follows: + +@example +typedef struct @{ + char ar_short_arg; /* short argument */ + char *ar_long_arg; /* long argument */ + short ar_type; /* type of variable */ + void *ar_variable; /* point to variable to set */ + char *ar_var_label; /* label for var description */ + char *ar_help_label; /* help lable for the arg */ +@} argv_t; +@end example + +The @code{ar_short_arg} element contains the character value of the +short option ('d' for @samp{-d}) or special codes such as ARGV_LAST +which identifies the last element in the array. @xref{Special Short +Args}. + +The @code{ar_long_arg} element (if not-NULL) holds the string which is +the long version of @code{ar_short_arg}. For instance, with @samp{-d}, +you might have "delete". This would mean that @samp{-d} and +@samp{--delete} would be equivalent. @samp{--} is the long-option +prefix per POSIX specs. + +You would define an array of these arguments at the top of the file with +@code{main()} in it. + +@example +static char copy = ARGV_FALSE; + +static argv_t args[] = @{ + @{ 'c', "copy", ARGV_BOOL, ©, NULL, "copy-files flag" @}, + @{ 'g', "group", ARGV_CHAR_P, &group, "group", "name of group to set" @}, + ... + @{ ARGV_LAST @} +@}; + +... + +int main(int argc, char ** argv) +@{ + argv_process(args, argc, argv); +@} +@end example + +@node Special Short Args, Types of Variables, Argv_t Structure, Details +@section The Special ar_short_arg Values + +There are 3 types of arguments: + +@table @dfn +@item optional +Arguments that may or may not be supplied by the user. + +@item mandatory +Arguments that must be supplied by the user. For instance grep must be +given an expression on the command line. + +If the argument is a mandatory argument which has no -%c prefix then the +@code{ar_short_arg} element should be assigned ARGV_MAND. + +@item maybe +Arguments that might be specified by the caller but are not mandatory. +For instance, you can grep a file or you can grep standard-input. The +file should be a maybe argument. + +If this is a maybe argument then use ARGV_MAYBE in the +@code{ar_short_arg} field. + +@end table + +To mark the last entry in the structure list use ARGV_LAST. ARGV_OR +also works. + +@node Types of Variables, Variable Arrays, Special Short Args, Details +@section The argv_t Structure and It's Usage + +Ar_type holds the type of the argument whether an optional argument or +mandatory. Below are the available values for this field. + +@table @code +@item ARGV_BOOL +character type, sets the variable to ARGV_TRUE if used + +@item ARGV_BOOL_NEG +like ARGV_BOOL but sets the variable to ARGV_FALSE if used + +@item ARGV_BOOL_ARG +like ARGV_BOOL but takes a yes/no argument + +@item ARGV_CHAR +a single character + +@item ARGV_CHAR_P +a string of characters (character pointer) + +@item ARGV_FLOAT +a floating pointer number + +@item ARGV_SHORT +a short integer number + +@item ARGV_INT +an integer number + +@item ARGV_U_INT +an unsigned integer number + +@item ARGV_LONG +a long integer number + +@item ARGV_U_LONG +an unsigned long integer number + +@item ARGV_BIN +a binary base-2 number (0s and 1s) + +@item ARGV_OCT +an octal base-8 number (0 to 7) + +@item ARGV_HEX +a hexadecimal base-16 number (0 to 9 and A to F) + +@item ARGV_INCR +a integer type which is incremented each time it is specified + +@item ARGV_SIZE +a long integer size number which understands b for bytes, k for +kilobytes, m for megabytes, and g for gigabytes + +@item ARGV_U_SIZE +an unsigned long integer version of ARGV_SIZE + +@item ARGV_BOOL_INT +like ARGV_BOOL except the variable is an integer and not a character + +@item ARGV_BOOL_INT_NEG +like ARGV_BOOL_NEG except the variable is an integer and not a character + +@item ARGV_BOOL_INT_ARG +like ARGV_BOOL_ARG except the variable is an integer and not a character + +@end table + +For printing out of the type of the argument on the command line, use +the @samp{--argv-display} option which will display the argument, its +type and value. It will display the variables' default values if no +arguments specified before it on the command line otherwise it will show +the values the variables are set to after processing the arguments. + +Basically the argument processing routines, examine the type of the +variable, absorb another argument (if necessary), and then translate the +string argument (if necessary) and write the data into the address +stored in the ar_variable field. + +ARGV_BOOL, ARGV_BOOL_NEG, ARGV_INCR, ARGV_BOOL_INT, and +ARGV_BOOL_INT_NEG are special in the above list in that they do not +require another argument. With @samp{ls -l}, for example, the @samp{-l} +flag lives on its own. With @samp{install -m 444 @dots{}}, on the other +hand, @samp{444} is an octal number argument associated with @samp{-m} +and will be translated and assigned to the @samp{-m} mode variable. + +@node Variable Arrays, , Types of Variables, Details +@section Using Arguments Which ``Absorb'' Arrays. + +Needs to be written. Sorry. + +@node General Usage, Plugs, Details, Top +@chapter Invoking Programs Which Use the Library + +@menu +* Usage Messages:: How to get usage messages from argv programs. +* Specifying Arguments:: How to specify arguments to argv programs. +* Long Versus Short:: Long versus short arguments. +* Global Environment Variable:: Settings for all argv programs. +* Program Environment Variable:: Arguments for a specific argv program. +@end menu + +@node Usage Messages, Specifying Arguments, General Usage, General Usage +@section How to get usage messages from argv programs + +If a program @samp{install} has the library compiled in you should be +able to do a @samp{install --usage-long} to get the long-format usage +message. + +@example +Usage: install + [-c] or --copy-files = copy file(s), don't move %t + [-g group] or --group-id = group id name (default bin) %s + [-m octal-mode] or --mode-value = permissions mode value %o + [-o owner] or --owner-id = owner id name (default bin) %s + [-s] or --strip = strip destination binary %t + [file(s)] directory/destination = files to install or mkdir arg +@end example + +In the above example, the program install's usage message is detailed. +The @samp{[-c]} line details the copy-files flag. You can either enable +it with a @samp{-c} or @samp{--copy-files}. The description of the flag +follows with lastly, a @samp{%t} showing that it is a @dfn{true/false} +flag. + +The @samp{[-g]} line shows the group-id flag. It is different from the +@samp{-c} flag since, if used, it takes a group string argument (notice +the @samp{%s} at the end of the line indicating it takes a string +argument). + +@samp{install --usage-short} or just @samp{--usage} will get you a +condensed usage message: + +@example +Usage: install [-cs] [-g group] [-m octal-mode] [-o owner] [file(s)] + directory/destination +@end example + +@node Specifying Arguments, Long Versus Short, Usage Messages, General Usage +@section How to Specify Arguments to Argv Programs + +Specifying arguments to a program which uses the library is quite +straight-forward and standardized. Once you have learned how to do it +once, you can use any program with it. + +There are five basic types of arguments as defined by the library: + +@table @dfn + +@item true/false flags +Do not have an associated value and the program will get a True if one +is specified else False. + +The @samp{-c} in @samp{install -c}. + +@item variable flags +Have an associate value which will be supplied to the program. + +The @samp{-m} in @samp{install -m 0644} will get the value @samp{0644}. + +@item values +Arguments without a @samp{-} and are associated values for the variable +flags. + +@item mandatory +Arguments without a @samp{-} but are @emph{not} associated to variable +flags. These can be supplied to the program if allowed. They are +mandatory in that they must be supplied. If the program asks for 3 +arguments, 3 must be supplied. @emph{NOTE} that order is important with +these. + +The @samp{from} and @samp{to} arguments in @samp{install from to}. + +@item maybe +These are the same as the mandatory arguments except they are optional +arguments and can but do not have to be supplied. + +The @samp{file} argument in @samp{ls file} since @samp{ls} does not +require a file to be listed to work. + +@end table + +The values for the variable flags are assigned in a straight +First-In-First-Out queue. In @samp{install -m -g 0644 bin}, the value +@samp{0644} is assigned to the @samp{-m} flag and the value @samp{bin} +is assigned to @samp{-g}. + +Additional values that cannot be matched to variable flags will become +mandatory or maybe arguments if the program is configured to accept +them. + +@example + install from -c -m -g 0644 -o wheel -s jim to +@end example + +In the previous convoluted example, @samp{from} and @samp{to} are +mandatory arguments, @samp{-c} and @samp{-s} are true/false flags, +@samp{-m} gets assigned @samp{0644}, @samp{-g} gets @samp{wheel}, and +@samp{-o} gets @samp{jim}. It would be much easier to write it as: + +@example + install -cs -m 0644 -g wheel -o jim to from +@end example + +@node Long Versus Short, Global Environment Variable, Specifying Arguments, General Usage +@section Long Versus Short Arguments + +Needs to be written. Sorry. + +@node Global Environment Variable, Program Environment Variable, Long Versus Short, General Usage +@section Global Settings For All Argv Programs + +@cindex environment variable +@cindex GLOBAL_ARGV + +An @dfn{environment variable} is a variable that is part of the user's +working environment and is shared by all the programs. The +@samp{GLOBAL_ARGV} variable is used by the argv library to customize its +behavior at runtime. It can be set by hand and should probably be +entered into your shell's runtime configuration or @dfn{RC} file. + +@cindex C shell usage +@cindex csh usage +@cindex tcsh usage +To set the variable, C shell (csh or tcsh) users need to invoke: + +@example +setenv GLOBAL_ARGV value +@end example + +@cindex Bourne shell usage +@cindex sh usage +@cindex bash usage +@cindex ksh usage +@cindex zsh usage +Bourne shell (sh, bash, ksh, or zsh) users should use: + +@example +GLOBAL_ARGV=value +export GLOBAL_ARGV +@end example + +The value in the above example is a comma separated list of tokens each +having a corresponding value. The tokens and their values are described +below: + +@itemize @bullet + +@item close -- close argument acceptance + +Enables the handling of arguments such as @samp{-m=444} where @samp{-m} +is a flag and @samp{444} is its value. + +Values: disable, enable. + +@itemize @bullet +@item disable -- treat @samp{=} like a normal argument +@item enable (default) -- enable the @samp{-x=10} format +@end itemize + +@item env -- environment variable handling + +Enables the processing of the @samp{ARGV_*} variables. If you have a +set of options that you always use for @samp{ls} for instance, you cat +set the @samp{ARGV_LS} environmental variable to hold these options. +For instance: @samp{setenv ARGV_LS "-sCF"}. + +Values: none, before, after. + +@itemize @bullet +@item none -- No processed at all +@item before (default) -- options from env variable are processed +Before command line +@item after -- env options processed After command line +@end itemize + +@item error -- handling of usage errors + +Whenever you do not use a command correctly, this token determines how +the library reports errors to you. + +Values: none, see, short, shortrem, long, all. + +@itemize @bullet +@item none -- on errors print nothing but error message +@item see (default) -- on errors print see --usage for more info. +@item short -- on errors print the short-format usage messages +@item shortrem -- on errors print short-format + how to get long +@item long -- on errors print the long-format usage messages +@item all -- on errors print the long-format usage messages + help, etc. +@end itemize + +@item multi -- the handling of arguments specified more than once + +If you use am argument twice on the command line, this token determines +if the library should say it is an error. + +Values: accept, reject. + +@itemize @bullet +@item accept (default) -- it's NOT an error if specified more than once +@item reject -- it's an error if specified more than once +@end itemize + +@item usage -- usage messages for --usage + +Determines what messages the library prints when you use the +@samp{--usage} option. + +Values: short, shortrem, long, all. + +@itemize @bullet +@item short (default) -- default is the short-format messages +@item shortrem -- default is the short-format messages + how to get long +@item long -- default is the long-format messages +@item all -- default is the long-format messages + help, usage, version +@end itemize + +@end itemize + +Examples: + +@example + # accept -x=10, no env variables, long messages on errors, + # accept multiple uses, and print all messages on --usage. + setenv GLOBAL_ARGV close=accept,env=none,error=long,multi=accept,usage=all + + # process env variable options before command line, + # and reject multiple argument uses + setenv GLOBAL_ARGV env=before,error=long,multi=reject +@end example + +@node Program Environment Variable, , Global Environment Variable, General Usage +@section Arguments For a Specific Argv Program + +Needs to be written. Sorry. + +@node Plugs, Index of Concepts, General Usage, Top +@chapter Plugs and Soapbox Comments + +@cindex plugs +@cindex soapbox comments + +Since I have your attention I would like to talk for a second about a +couple of things that I feel strongly about. If you would like any more +information about the below, please mail to the supplied addresses or +drop me a line with any questions. + +@table @asis +@item The Electronic Frontier Foundation (EFF) +@cindex EFF +@cindex Electronic Frontier Foundation +The EFF is a organization committed to ensuring that the rules, +regulations, and laws being applied to emerging communications +technologies are in keeping with our society's highest traditions of the +free and open flow of ideas and information while protecting personal +privacy. http://www.eff.org/ + +@item Computer Professionals for Social Responsibility (CPSR) +@cindex CPSR +@cindex Computer Professionals for Social Responsibility +CPSR is a public-interest alliance of computer scientists and others +interested in the impact of computer technology on society. We work to +influence decisions regarding the development and use of computers +because those decisions have far-reaching consequences and reflect basic +values and priorities. http://www.cpsr.org/ +@end table + +@node Index of Concepts, Full Node Listings, Plugs, Top +@unnumbered Concept Index + +@printindex cp +@contents + +@ifinfo + +@node Full Node Listings, , Index of Concepts, Top +@unnumbered Detailed Node Listing + +@menu +Top. + +* Copying:: Library copying conditions. +* Overview:: Description of how to use the library. +* Details:: Details about the library's operations. +* General Usage:: Invoking Programs Which Use the Library. +* Plugs:: A couple soapbox comments. +* Index of Concepts:: Index of concepts in the manual. +* Full Node Listings:: Listing of all the nodes in the manual. + +Overview. + +* Concepts:: General concepts behind the library. +* How To Get:: How to get the library. +* Installation:: How to install the library. +* Getting Started:: Getting started with the library. + +Details + +* Argv_t Structure:: The argv_t structure and it's usage. +* Special Short Args:: The special ar_short_arg values. +* Types of Variables:: The different variable types. +* Variable Arrays:: Using arguments which ``absorb'' arrays. + +General Usage + +* Usage Messages:: How to get usage messages from argv programs. +* Specifying Arguments:: How to specify arguments to argv programs. +* Long Versus Short:: Long versus short arguments. +* Global Environment Variable:: Settings for all argv programs. +* Program Environment Variable:: Arguments for a specific argv program. + +@end menu + +@end ifinfo +@bye diff --git a/libargv/argvSetDebugLevel.c b/libargv/argvSetDebugLevel.c index b391363..9fb17df 100644 --- a/libargv/argvSetDebugLevel.c +++ b/libargv/argvSetDebugLevel.c @@ -1,18 +1,44 @@ /* - * $Source$ - * $Revision$ - * $Date$ + * $Source$ + * $Revision$ + * $Date$ * - * Copyright (C) 1996,97 by CyberSolutions GmbH. - * All rights reserved. + * Copyright (c) 1996-99 by Peter Simons + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Peter Simons. + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "_funclib.h" - -#ifdef DEBUG - -extern unsigned int DebugModules[]; -extern const char * const ModuleTable[]; +#include +#include +#include "argv.h" /* This routine is a convenient way to enable or disable various debugging modules according to the wishes of the user. It takes a @@ -39,33 +65,40 @@ extern const char * const ModuleTable[]; */ int -argvSetDebugLevel(argv_array_t debug /* parameter array as returned by the argv routines */ - ) -{ +argvSetDebugLevel(argv_array_t debug) + { +#ifdef DEBUG + extern const char* const ModuleTable[]; + void setDebugLevel(unsigned short, unsigned short); + char * ModuleName; char * DebugLevel; unsigned int count, i; - for (count = 0; count < debug.aa_entryn; count++) { + for (count = 0; count < debug.aa_entry_n; count++) + { ModuleName = strtok(ARGV_ARRAY_ENTRY(debug, char *, count), ",/:"); DebugLevel = strtok(NULL, ",/:"); - if (ModuleName == NULL || DebugLevel == NULL - || atoi(DebugLevel) < 0 || atoi(DebugLevel) > 9) { + if (ModuleName == NULL || DebugLevel == NULL || atoi(DebugLevel) < 0 || atoi(DebugLevel) > 9) + { fprintf(stderr, "\"%s\" is not a valid debug-level specification.\n", ARGV_ARRAY_ENTRY(debug, char *, count)); return -1; - } - for (i = 0; ModuleTable[i] != NULL; i++) { - if (!strcasecmp(ModuleName, ModuleTable[i])) { + } + for (i = 0; ModuleTable[i] != NULL; i++) + { + if (!strcasecmp(ModuleName, ModuleTable[i])) + { setDebugLevel(i, atoi(DebugLevel)); break; - } - } - if (ModuleTable[i] == NULL) { - fprintf(stderr, "\"%s\" is not a valid debug-module name.\n", ModuleName); - return -1; - } - } - return 0; -} + } + } + if (ModuleTable[i] == NULL) + { + fprintf(stderr, "\"%s\" is not a valid debug-module name.\n", ModuleName); + return -1; + } + } #endif + return 0; + } diff --git a/libargv/_argv.h b/libargv/argv_loc.h similarity index 75% rename from libargv/_argv.h rename to libargv/argv_loc.h index e1eb1bf..c764a17 100644 --- a/libargv/_argv.h +++ b/libargv/argv_loc.h @@ -1,9 +1,10 @@ /* - * Local defines for the argv module + * $Source$ + * $Revision$ + * $Date$ * - * Copyright 1995 by Gray Watson - * - * This file is part of the argv library. + * Copyright (c) 1999 by Gray Watson . + * All rights reserved. * * Permission to use, copy, modify, and distribute this software for * any purpose and without fee is hereby granted, provided that the @@ -13,30 +14,18 @@ * without specific, written prior permission. * * Gray Watson makes no representations about the suitability of the - * software described herein for any purpose. It is provided "as is" + * software described herein for any purpose. It is provided "as is" * without express or implied warranty. - * - * The author may be contacted at gray.watson@letters.com - * - * $Id$ */ #ifndef __ARGV_LOC_H__ #define __ARGV_LOC_H__ -#include "argv.h" +#include "argv.h" /* to get the types */ -/* - * global variable and procedure scoping for code readability - */ -#undef EXPORT -#define EXPORT - -#undef IMPORT -#define IMPORT extern - -#undef LOCAL -#define LOCAL static +#ifdef __cplusplus +extern "C" { +#endif /* * generic constants @@ -46,9 +35,6 @@ #define NULL 0L #endif -#undef NULLC -#define NULLC '\0' - #undef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -76,8 +62,8 @@ #define FILE_LINE_SIZE 1024 /* max size of file lines */ /* internal flags set in the ar_type field */ -/* ARGV_ARRAY is defined in argv.h */ -#define ARGV_FLAG_USED (1 << 13) /* if arg has been specified */ +/* NOTE: other external flags defined in argv.h */ +#define ARGV_FLAG_USED (1 << 12) /* if arg has been specified */ /* error messages */ #define USAGE_ERROR_NAME "usage problem" @@ -97,6 +83,7 @@ #define GLOBAL_ERROR "error=" /* error setting */ #define GLOBAL_MULTI "multi=" /* multi setting */ #define GLOBAL_USAGE "usage=" /* usage setting */ +#define GLOBAL_LASTTOG "lasttog=" /* last-arg toggle */ #define GLOBAL_CLOSE_DISABLE 1 /* disable close args */ #define GLOBAL_CLOSE_ENABLE 2 /* enable close args */ @@ -114,7 +101,10 @@ #define GLOBAL_MULTI_REJECT 11 /* reject multiple arg use */ #define GLOBAL_MULTI_ACCEPT 12 /* accept multiple arg use */ -#define GLOBAL_ERROR_NONE 13 /* print only error */ +#define GLOBAL_LASTTOG_DISABLE 13 /* toggling of last-arg off */ +#define GLOBAL_LASTTOG_ENABLE 14 /* toggling of last-arg on */ + +#define GLOBAL_ERROR_NONE 15 /* print only error */ #define GLOBAL_ERROR_SEE GLOBAL_USAGE_SEE /* error + see messages */ #define GLOBAL_ERROR_SHORT GLOBAL_USAGE_SHORT /* error + short */ #define GLOBAL_ERROR_SHORTREM GLOBAL_USAGE_SHORTREM /* err + short + remind*/ @@ -127,6 +117,7 @@ #define SHORT_PREFIX "-" /* prefix for short args */ #define UNKNOWN_ARG "??" /* unknown argument output */ #define ARG_EQUALS '=' /* to assign value to option */ +#define NUMBER_ARG_CHARS "0123456789+-." /* characters in numbers */ /* how to produce the env var using sprintf and the argv_program variable */ #define ENVIRON_FORMAT "ARGV_%s" @@ -175,13 +166,13 @@ /* strcture defining argv types */ typedef struct { - int at_value; /* value of the type */ + unsigned int at_value; /* value of the type */ char *at_name; /* name of the type */ - int at_size; /* size of type */ + unsigned int at_size; /* size of type */ char *at_desc; /* description of the type */ } argv_type_t; -LOCAL argv_type_t argv_types[] = { +static argv_type_t argv_types[] = { { ARGV_BOOL, "flag", sizeof(char), "if option used, set variable to true" }, { ARGV_BOOL_NEG, "negative flag", sizeof(int), @@ -190,12 +181,12 @@ LOCAL argv_type_t argv_types[] = { "like flag but you specify with yes/no argument" }, { ARGV_CHAR, "character", sizeof(char), "single character" }, - { ARGV_CHARP, "string", sizeof(char *), + { ARGV_CHAR_P, "string", sizeof(char *), "multiple characters terminated with a '\\0'" }, - { ARGV_FLOAT, "floating point", sizeof(float), - "real number with decimal point" }, { ARGV_SHORT, "short integer", sizeof(short), "decimal short-sized integer value" }, + { ARGV_U_SHORT, "unsigned short integer", sizeof(unsigned short), + "decimal unsigned short-sized integer value" }, { ARGV_INT, "integer", sizeof(int), "decimal integer value" }, { ARGV_U_INT, "unsigned integer", sizeof(unsigned int), @@ -204,6 +195,10 @@ LOCAL argv_type_t argv_types[] = { "decimal long-sized integer value" }, { ARGV_U_LONG, "unsigned long", sizeof(unsigned long), "decimal unsigned long-sized integer value" }, + { ARGV_FLOAT, "floating point", sizeof(float), + "real number with decimal point" }, + { ARGV_DOUBLE, "double floating point", sizeof(double), + "double precision real number with decimal point" }, { ARGV_BIN, "binary", sizeof(int), "base 2 value with digits of 0 or 1" }, { ARGV_OCT, "octal", sizeof(int), @@ -212,62 +207,15 @@ LOCAL argv_type_t argv_types[] = { "base 16 value with digits from 0-9, A-F" }, { ARGV_INCR, "increment", sizeof(int), "increment variable each time option used" }, + { ARGV_SIZE, "long size", sizeof(long), + "size as long int + [bkmg] b=byte,k=kilo,m=meg,g=gig" }, + { ARGV_U_SIZE, "unsigned long size", sizeof(unsigned long), + "size as unsigned long int + [bkmg] b=byte,k=kilo,m=meg,g=gig" }, { 0 } }; -/******************************** queue code *********************************/ - -/* - * Generic inline queue defines. - */ - -/* declare the arguments needed to maintain a queue for type TYPE */ -#define QUEUE_DECLARE(type) \ - type *queue_alloc = NULL; \ - int queue_head = 0; \ - int queue_tail = 0; \ - int queue_count = 0; \ - int queue_max = 1 -#define LOCAL_QUEUE_DECLARE(type) \ - static type *queue_alloc = NULL; \ - static int queue_head = 0; \ - static int queue_tail = 0; \ - static int queue_count = 0; \ - static int queue_max = 1 - -/* test to see if the queue has not been allocated */ -#define QUEUE_IS_NULL() (queue_alloc == NULL) - -/* allocate a mini-queue */ -#define QUEUE_ALLOC(type, num) \ - do { \ - queue_alloc = (type *)malloc(sizeof(type) * num); \ - queue_head = 0; \ - queue_tail = 0; \ - queue_count = 0; \ - queue_max = num; \ - } while(0) - -/* allocate a mini-queue's allocation */ -#define QUEUE_FREE() free(queue_alloc) - -/* enqueue items from the mini-queue */ -#define QUEUE_ENQUEUE(item) \ - do { \ - queue_alloc[queue_head] = item; \ - queue_head = (queue_head + 1) % queue_max; \ - queue_count++; \ - } while(0) - -/* dequeue items from the mini-queue */ -#define QUEUE_DEQUEUE(item) \ - do { \ - item = queue_alloc[queue_tail]; \ - queue_tail = (queue_tail + 1) % queue_max; \ - queue_count--; \ - } while(0) - -/* count the number of items in the mini-queue */ -#define QUEUE_COUNT() queue_count +#ifdef __cplusplus +} +#endif #endif /* ! __ARGV_LOC_H__ */ diff --git a/libargv/configure.in b/libargv/configure.in new file mode 100644 index 0000000..81905c7 --- /dev/null +++ b/libargv/configure.in @@ -0,0 +1,46 @@ +dnl +dnl Process this file with autoconf to produce a configure script. +dnl +dnl NOTE: the beginning comments should be dnl'ed so we get the #!/bin/sh +dnl at the very top of the configure script. +dnl +dnl Copyright 1995 by Gray Watson +dnl +dnl This file is part of the argv library. +dnl +dnl Permission to use, copy, modify, and distribute this software for +dnl any purpose and without fee is hereby granted, provided that the +dnl above copyright notice and this permission notice appear in all +dnl copies, and that the name of Gray Watson not be used in advertising +dnl or publicity pertaining to distribution of the document or software +dnl without specific, written prior permission. +dnl +dnl Gray Watson makes no representations about the suitability of the +dnl software described herein for any purpose. It is provided "as is" +dnl without express or implied warranty. +dnl +dnl The author may be contacted at gray.watson@letters.com +dnl +dnl $Id$ +dnl +AC_REVISION($Revision$)dnl +AC_INIT(argv.c) + +dnl Checks for paths and programs. +dnl +AC_PROG_CC +AC_PROG_RANLIB + +dnl Enable warning flags for gcc. +dnl +if test "$GCC" = yes; then + CFLAGS="$CFLAGS -Wall -pedantic -ansi" +fi + +dnl Remove '-g' and '-O2' from the compile flags. +dnl +CFLAGS=`echo $CFLAGS | sed -e "s/-g//" -e "s/-O2//"` + +dnl Write results. +dnl +AC_OUTPUT(GNUmakefile) diff --git a/libargv/test.c b/libargv/test.c index 3856475..db0eff0 100644 --- a/libargv/test.c +++ b/libargv/test.c @@ -1,39 +1,65 @@ /* - * $Source$ - * $Revision$ - * $Date$ + * $Source$ + * $Revision$ + * $Date$ * - * Copyright (C) 1997 by CyberSolutions GmbH. - * All rights reserved. + * Copyright (c) 1996-99 by Peter Simons + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Peter Simons. + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "argv.h" -/* These variables should be global/static because the ANSI C standard - doesn't allow to reference to local variables at compile time, as - we do when filling out the args[] array. */ - -static char * filename = "/tmp/defaultfile"; -static char do_something = ARGV_TRUE; -static argv_array_t parameters; - int main(int argc, char ** argv) { - argv_t args[] = { - { 's', "something", ARGV_BOOL_ARG, &do_something, NULL, - "Do something?"}, - { 0, "filename", ARGV_CHARP, &filename, "logfile", - "Path of the logfile."}, - { ARGV_MAND, 0L, ARGV_CHARP | ARGV_ARRAY, ¶meters, "parameters", - "Whatever..."}, - {ARGV_LAST} + /* These variables should be static because the ANSI C standard + doesn't allow to reference to local variables at compile time, + as would need it when filling out the args[] array. */ + + static char * filename = "/tmp/defaultfile"; + static char do_something = ARGV_TRUE; + static argv_array_t parameters; + + argv_t args[] = { + { 's', "something", ARGV_BOOL_ARG, &do_something, NULL, "Do something?"}, + { 0, "filename", ARGV_CHAR_P, &filename, "logfile", "Path of the logfile."}, + { ARGV_MAND, 0L, ARGV_CHAR_P | ARGV_FLAG_ARRAY, ¶meters, "parameters", "Whatever..."}, + {ARGV_LAST} }; - unsigned int i; + unsigned int i; /* Parse the command line. */ - argv_help_string = "BigBrother Internet Surveillance Daemon"; + argv_help_string = "You need help with a test program?"; argv_version_string = "libargv test programm"; argv_process(args, argc, argv); @@ -43,8 +69,8 @@ main(int argc, char ** argv) printf("logfile : %s\n", filename); printf("do_something: %s\n", (do_something == ARGV_TRUE) ? "yes" : "no"); printf("parameters : "); - for (i = 0; i < parameters.aa_entryn; i++) { - if (i+1 < parameters.aa_entryn) + for (i = 0; i < ARGV_ARRAY_COUNT(parameters); i++) { + if (i+1 < ARGV_ARRAY_COUNT(parameters)) printf("'%s', ", ARGV_ARRAY_ENTRY(parameters, char *, i)); else printf("'%s'", ARGV_ARRAY_ENTRY(parameters, char *, i));