📄 dmalloc_argv.c
字号:
/* * Generic argv processor... * * Copyright 1995 by Gray Watson * * This file is part of the argv library. * * 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. * * The author may be contacted via http://dmalloc.com/ */#include <ctype.h>#include <stdio.h>#if HAVE_STRING_H# include <string.h>#endif#if HAVE_STDLIB_H# include <stdlib.h>#endif#include "conf.h"#include "dmalloc_argv.h"#include "dmalloc_argv_loc.h"#include "compat.h"/* internal routines */static void do_list(argv_t *grid, const int arg_c, char **argv, argv_t **queue_list, int *queue_head_p, int *queue_tail_p, int *okay_bp);/* * exported variables *//* This is a processed version of argv[0], pre-path removed: /bin/ls -> ls */char argv_program[PROGRAM_NAME + 1] = "Unknown";/* A global value of argv from main after argv_process has been called */char **argv_argv = NULL;/* A global value of argc from main after argv_process has been called */int argv_argc = 0;/* This should be set externally to provide general program help to user */char *argv_help_string = NULL;/* This should be set externally to provide version information to the user */char *argv_version_string = NULL;/* * Are we running interactively? This will exit on errors. Set to * false to return error codes instead. */int argv_interactive = ARGV_TRUE;/* * The FILE stream that argv out_puts all its errors. Set to NULL to * not dump any error messages. Default is stderr. */FILE *argv_error_stream = ERROR_STREAM_INIT;/* * global settings *//* * Set to 1 (the default) to enable the handling of -l=foo or * --logfile=foo type of arguments. Set to 0 to disable. This allows * you to specifically assign a value to an argument. * * NOTE: this is set by argv_process automatically. If you do not * want this behavior, you should use argv_process_no_env. */int argv_close_enable_b = 1;/* * If the library sees a "--" argument, it will turn off further * argument process. Set to 1 to enable the ability of specifying * additional "--" arguments to reenable (basically toggle on then * off) argument processing. Set to 0 (the default) to disable this * behavior. * * NOTE: this is set by argv_process automatically. If you do not * want this behavior, you should use argv_process_no_env. */int argv_last_toggle_b = 0;/* * Set to 1 (the default) to have the library accept multiple usage of * the same argument. Set to 0 to have the library generate an error * if you use an argument twice. * * NOTE: this is set by argv_process automatically. If you do not * want this behavior, you should use argv_process_no_env. */int argv_multi_accept_b = 1;/* * Set to one of the ARGV_USAGE_ defines in the argv.h file. This * tell the library what usage information to display when --usage is * specified by the user. Default is ARGV_USAGE_LONG. * * NOTE: this is set by argv_process automatically. If you do not * want this behavior, you should use argv_process_no_env. */int argv_usage_type = ARGV_USAGE_LONG;/* * Set to one of the ARGV_USAGE_ defines in the argv.h file. This * tell the library what usage information to display when an error is * encountered. The usage information accompanies the error message. * Default is ARGV_USAGE_SEE. * * NOTE: this is set by argv_process automatically. If you do not * want this behavior, you should use argv_process_no_env. */int argv_error_type = ARGV_USAGE_SEE;/* * Set to 1 (the default) if you want the library look for associated * arguments from the associated program's environmental variable. If * set the 0 then no environmental variable will be used. If you are * running program foo then the library will look for the * environmental variable ARGV_foo and will add those to the argument * list specified on the command line. By default they will be * inserted in front of those on the command line unless the * argv_env_after_b is set to 1. * * NOTE: this is set by argv_process automatically. If you do not * want this behavior, you should use argv_process_no_env. */int argv_process_env_b = 1;/* * Set to 1 if you want the library to append the arguments from the * program's environmental variable after those specified on the * command line. If set the 0 (the default) then they will be * inserted before those specified on the command line. See * argv_process_env_b for more information. * * NOTE: this is set by argv_process automatically. If you do not * want this behavior, you should use argv_process_no_env. */int argv_env_after_b = 0;/* local variables */static argv_t empty[] = {{ ARGV_LAST }}; /* empty argument array */static int enabled_b = ARGV_FALSE; /* are the lights on? *//****************************** startup routine ******************************//* * static void argv_startup * * DESCRIPTION: * * Turn on the lights. * * RETURNS: * * None. * * ARGUMENTS: * * None. */static void argv_startup(void){ if (enabled_b) { return; } enabled_b = ARGV_TRUE; /* ANSI says we cannot predefine this above */ if (argv_error_stream == ERROR_STREAM_INIT) { argv_error_stream = stderr; }}/***************************** general utilities *****************************//* * static int btoi * * DESCRIPTION: * * Binary string to integer translation. * * RETURNS: * * Integer converted from the string. * * ARGUMENTS: * * str - String of binary 0s and 1s that we are converting. */static int btoi(const char *str){ int ret = 0; /* strip off spaces */ for (; isspace(*str); str++) { } for (; *str == '0' || *str == '1'; str++) { ret *= 2; ret += *str - '0'; } return ret;}/* * static int otoi * * DESCRIPTION: * * Octal string to integer translation. * * RETURNS: * * Integer converted from the string. * * ARGUMENTS: * * str - String of octal digits that we are converting. */static int otoi(const char *str){ int ret = 0; /* strip off spaces */ for (; isspace(*str); str++) { } for (; *str >= '0' && *str <= '7'; str++) { ret *= 8; ret += *str - '0'; } return ret;}/* * static int htoi * * DESCRIPTION: * * Hexadecimal string to integer translation. * * RETURNS: * * Integer converted from the string. * * ARGUMENTS: * * str - String of hexadecimal characters and digits that we are * converting. */static int htoi(const char *str){ int ret = 0; /* strip off spaces */ for (; isspace(*str); str++) { } /* skip a leading 0[xX] */ if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) { str += 2; } for (; isdigit(*str) || (*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F'); str++) { ret *= 16; if (*str >= 'a' && *str <= 'f') { ret += *str - 'a' + 10; } else if (*str >= 'A' && *str <= 'F') { ret += *str - 'A' + 10; } else { ret += *str - '0'; } } return ret;}/* * static char *string_copy * * DESCRIPTION: * * Basically a strdup for compatibility sake. * * RETURNS: * * Character pointer that must be freed later. * * ARGUMENTS: * * str - String we are copying. */static char *string_copy(const char *str){ const char *str_p; char *copy, *copy_p; int len; len = strlen(str); copy = (char *)malloc(len + 1); if (copy == NULL) { if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); } if (argv_interactive) { (void)exit(EXIT_CODE); } return NULL; } for (str_p = str, copy_p = copy; *str_p != '\0';) { *copy_p++ = *str_p++; } *copy_p = '\0'; return copy;}/* * static char **vectorize * * DESCRIPTION: * * Break a string up into its arguments separated by one of the * characters in a token string and return an array of char pointers. * * NOTE: the string argument should stay around until that time. * * RETURNS: * * Success - Allocated list of character poiners into the string * argument which must be freed later. * * Failure - NULL * * ARGUMENTS: * * str - String we are tokenizing. * * tok - List of token characters to look for in the string. * * num_tok_p - Pointer to an integer which will be set to the number * of tokens found in the string. */static char **vectorize(char *str, const char *tok, int *num_tok_p){ char **vect_p; char *tmp, *str_p, *tok_p; int tok_c, tok_n; /* count the tokens */ tmp = string_copy(str); if (tmp == NULL) { return NULL; } str_p = tmp; tok_c = 0; while (1) { tok_p = strsep(&str_p, tok); if (tok_p == NULL) { break; } if (*tok_p != '\0') { tok_c++; } } tok_n = tok_c; free(tmp); *num_tok_p = tok_n; if (tok_c == 0) { return NULL; } /* allocate the pointer grid */ vect_p = (char **)malloc(sizeof(char *) * tok_c); if (vect_p == NULL) { if (argv_error_stream != NULL) { (void)fprintf(argv_error_stream, "%s: memory error during argument processing\n", argv_program); } if (argv_interactive) { (void)exit(EXIT_CODE); } return NULL; } /* load the tokens into the list */ str_p = str; for (tok_c = 0; tok_c < tok_n;) { tok_p = strsep(&str_p, tok); if (tok_p == NULL) { break; } if (*tok_p != '\0') { vect_p[0] = tok_p; tok_c++; } } return vect_p;}/* * static int expand_buf * * DESCRIPTION: * * Translates a buffer of bytes into its printable version. * * NOTE: it does _not_ add a \0 at the end of OUT. * * RETURNS: * * Number of characters written in to the output buffer. * * ARGUMENTS: * * buf - Input buffer of bytes. * * buf_size - Size of the input buffer. If < 0 then the routing will * translate up to the first \0. * * out - Output buffer for the translated characters. * * out_size - Maximum size of the output buffer. */static int expand_buf(const void *buf, const int buf_size, char *out, const int out_size){ int buf_c; const unsigned char *buf_p, *spec_p; char *max_p, *out_p = out; /* setup our max pointer */ max_p = out + out_size; /* run through the input buffer, counting the characters as we go */ for (buf_c = 0, buf_p = (const unsigned char *)buf;; buf_c++, buf_p++) { /* did we reach the end of the buffer? */ if (buf_size < 0) { if (*buf_p == '\0') { break; } } else { if (buf_c >= buf_size) { break; } } /* search for special characters */ for (spec_p = (unsigned char *)SPECIAL_CHARS + 1; *(spec_p - 1) != '\0'; spec_p += 2) { if (*spec_p == *buf_p) { break; } } /* did we find one? */ if (*(spec_p - 1) != '\0') { if (out_p + 2 >= max_p) { break; } (void)loc_snprintf(out_p, max_p - out_p, "\\%c", *(spec_p - 1)); out_p += 2; continue; } /* print out any 7-bit printable characters */ if (*buf_p < 128 && isprint(*buf_p)) { if (out_p + 1 >= max_p) { break; } *out_p = *(char *)buf_p; out_p += 1; } else { if (out_p + 4 >= max_p) { break; } (void)loc_snprintf(out_p, max_p - out_p, "\\%03o", *buf_p); out_p += 4; } } return out_p - out;}/****************************** usage routines *******************************//* * static void usage_short * * DESCRIPTION: * * Print a short-format usage message. * * RETURNS: * * None. * * ARGUMENTS: * * args - Array of argv_t structions whose usage messages you print. * * flags - User flags. */static void usage_short(const argv_t *args, const int flag){ const argv_t *arg_p; int len, col_c = 0; int mark_b = ARGV_FALSE; char *prefix; if (argv_error_stream == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -