mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* util - Utility function library
|
||||
*
|
||||
* Parse the command line options
|
||||
*
|
||||
* Copyright IBM Corp. 2016, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <argz.h>
|
||||
#include <libgen.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_panic.h"
|
||||
#include "lib/util_prg.h"
|
||||
|
||||
/*
|
||||
* Private data
|
||||
*/
|
||||
/// @cond
|
||||
static struct util_opt_l {
|
||||
/* Option character string for getopt_long() */
|
||||
char *opt_str;
|
||||
/* Option array for getopt_long() */
|
||||
struct option *option_vec;
|
||||
/* Original util_opt array */
|
||||
struct util_opt *opt_vec;
|
||||
/* Length of longest option string */
|
||||
int opt_max;
|
||||
/* Command used for parsing */
|
||||
const char *command;
|
||||
} l;
|
||||
|
||||
struct util_opt_l *util_opt_l = &l;
|
||||
|
||||
/// @endcond
|
||||
|
||||
#define util_opt_iterate(opt) \
|
||||
for (opt = &l.opt_vec[0]; opt->desc != NULL; opt++)
|
||||
|
||||
#define MAX_OPTLEN 256
|
||||
|
||||
static int opt_max_len(void);
|
||||
|
||||
/**
|
||||
* Initialize the command line options
|
||||
*
|
||||
* Build short option string and long option array to be used for getopt_long().
|
||||
* The ":" prefix is added to the short option string for handling of "missing
|
||||
* required arguments".
|
||||
*
|
||||
* @param[in] opt_vec Option array
|
||||
* @param[in] opt_prefix Optional option string prefix
|
||||
*/
|
||||
void util_opt_init(struct util_opt *opt_vec, const char *opt_prefix)
|
||||
{
|
||||
int i, j, count;
|
||||
char *str;
|
||||
size_t prefix_len = opt_prefix ? strlen(opt_prefix) : 0;
|
||||
|
||||
opterr = 0;
|
||||
/* Get number of options */
|
||||
for (count = 0; opt_vec[count].desc != NULL; count++);
|
||||
/*
|
||||
* Allocate short option string for worst case when all options have
|
||||
* optional parameters e.g "x::" and long option string.
|
||||
*/
|
||||
l.opt_str = util_malloc(sizeof(char) * count * 3 + 2 + prefix_len);
|
||||
l.option_vec = util_malloc(sizeof(struct option) * (count + 1));
|
||||
l.opt_vec = opt_vec;
|
||||
|
||||
str = l.opt_str;
|
||||
if (opt_prefix) {
|
||||
strcpy(str, opt_prefix);
|
||||
str += prefix_len;
|
||||
}
|
||||
/* Force getopt_long() to return ':' for missing required arguments */
|
||||
*str++ = ':';
|
||||
/* Construction of input structures for getopt_long() function. */
|
||||
for (i = 0, j = 0; i < count; i++) {
|
||||
if (opt_vec[i].flags & UTIL_OPT_FLAG_SECTION)
|
||||
continue;
|
||||
if (!(opt_vec[i].flags & UTIL_OPT_FLAG_NOLONG)) {
|
||||
memcpy(&l.option_vec[j++], &opt_vec[i].option,
|
||||
sizeof(struct option));
|
||||
}
|
||||
if (opt_vec[i].flags & UTIL_OPT_FLAG_NOSHORT)
|
||||
continue;
|
||||
*str++ = opt_vec[i].option.val;
|
||||
switch (opt_vec[i].option.has_arg) {
|
||||
case no_argument:
|
||||
break;
|
||||
case required_argument:
|
||||
*str++ = ':';
|
||||
break;
|
||||
case optional_argument:
|
||||
*str++ = ':';
|
||||
*str++ = ':';
|
||||
break;
|
||||
default:
|
||||
util_panic("Unexpected \"has_arg\" parameter: %d\n",
|
||||
opt_vec[i].option.has_arg);
|
||||
}
|
||||
}
|
||||
/* Add end marker to option array and short option string */
|
||||
memset(&l.option_vec[j], 0, sizeof(struct option));
|
||||
*str = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current command for command line option processing
|
||||
*
|
||||
* @param[in] command The current command or NULL for no command
|
||||
*/
|
||||
void util_opt_set_command(const char *command)
|
||||
{
|
||||
l.command = command;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true, if option belongs to current command setting
|
||||
*/
|
||||
static bool opt_is_active(struct util_opt *opt)
|
||||
{
|
||||
if (!opt->command || !l.command)
|
||||
return true;
|
||||
return (strcmp(opt->command, l.command) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for getopt_long
|
||||
*
|
||||
* @param[in] argc Count of command line parameters
|
||||
* @param[in] argv Array of command line parameters
|
||||
*/
|
||||
int util_opt_getopt_long(int argc, char *argv[])
|
||||
{
|
||||
struct util_opt *opt;
|
||||
int val;
|
||||
|
||||
val = getopt_long(argc, argv, l.opt_str, l.option_vec, NULL);
|
||||
|
||||
switch (val) {
|
||||
case ':':
|
||||
case '?':
|
||||
case -1:
|
||||
break;
|
||||
default:
|
||||
if (!l.command)
|
||||
break;
|
||||
util_opt_iterate(opt) {
|
||||
if (!opt_is_active(opt))
|
||||
continue;
|
||||
if (opt->option.val == val)
|
||||
goto out;
|
||||
}
|
||||
/* No valid option found for command */
|
||||
val = '?';
|
||||
if (optarg)
|
||||
optind--;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Format option name: Add short, long option and argument (as applicable)
|
||||
*/
|
||||
static void format_opt(char *buf, size_t maxlen, const struct util_opt *opt)
|
||||
{
|
||||
int has_arg, flags, rc;
|
||||
char val, *arg_str;
|
||||
const char *name;
|
||||
|
||||
has_arg = opt->option.has_arg;
|
||||
name = opt->option.name;
|
||||
val = opt->option.val;
|
||||
flags = opt->flags;
|
||||
|
||||
/* Prepare potential option argument string */
|
||||
if (has_arg == optional_argument) {
|
||||
if (flags & UTIL_OPT_FLAG_NOLONG)
|
||||
util_asprintf(&arg_str, "[%s]", opt->argument);
|
||||
else
|
||||
util_asprintf(&arg_str, "[=%s]", opt->argument);
|
||||
} else if (has_arg == required_argument) {
|
||||
util_asprintf(&arg_str, " %s", opt->argument);
|
||||
} else {
|
||||
util_asprintf(&arg_str, "");
|
||||
}
|
||||
|
||||
/* Format the option */
|
||||
if (flags & UTIL_OPT_FLAG_NOLONG)
|
||||
rc = snprintf(buf, maxlen, "-%c%s", val, arg_str);
|
||||
else if (flags & UTIL_OPT_FLAG_NOSHORT)
|
||||
rc = snprintf(buf, maxlen, " --%s%s", name, arg_str);
|
||||
else
|
||||
rc = snprintf(buf, maxlen, "-%c, --%s%s", val, name, arg_str);
|
||||
|
||||
util_assert(rc < (int)maxlen, "Option too long: %s\n", name);
|
||||
free(arg_str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true, if option is to be printed for the current command setting
|
||||
*/
|
||||
static bool should_print_opt(const struct util_opt *opt)
|
||||
{
|
||||
if (l.command) {
|
||||
/* Print only options that belong to command */
|
||||
return opt->command ? !strcmp(opt->command, l.command) : false;
|
||||
} else {
|
||||
/* Print only common options (standard for non-command tools) */
|
||||
return opt->command ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return size of the longest formatted option
|
||||
*/
|
||||
static int opt_max_len(void)
|
||||
{
|
||||
const struct util_opt *opt;
|
||||
unsigned int max = 0;
|
||||
char opt_str[MAX_OPTLEN];
|
||||
|
||||
util_opt_iterate(opt) {
|
||||
if (opt->flags & UTIL_OPT_FLAG_SECTION)
|
||||
continue;
|
||||
if (!should_print_opt(opt))
|
||||
continue;
|
||||
format_opt(opt_str, MAX_OPTLEN, opt);
|
||||
max = MAX(max, strlen(opt_str));
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an option name, followed by a description indented to fit the
|
||||
* longest option name
|
||||
*/
|
||||
void util_opt_print_indented(const char *opt, const char *desc)
|
||||
{
|
||||
printf(" %-*s ", l.opt_max + 1, opt);
|
||||
util_print_indented(desc, 3 + l.opt_max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the usage of the command line options to the console
|
||||
*/
|
||||
void util_opt_print_help(void)
|
||||
{
|
||||
char opt_str[MAX_OPTLEN];
|
||||
struct util_opt *opt;
|
||||
int first = 1;
|
||||
|
||||
/*
|
||||
* Create format string: " -%c, --%-<long opt size>s %s"
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* -p, --print STRING Print STRING to console
|
||||
*/
|
||||
l.opt_max = opt_max_len();
|
||||
|
||||
util_opt_iterate(opt) {
|
||||
if (!should_print_opt(opt))
|
||||
continue;
|
||||
if (opt->flags & UTIL_OPT_FLAG_SECTION) {
|
||||
printf("%s%s\n", first ? "" : "\n", opt->desc);
|
||||
first = 0;
|
||||
continue;
|
||||
}
|
||||
format_opt(opt_str, MAX_OPTLEN, opt);
|
||||
util_opt_print_indented(opt_str, opt->desc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print option parsing error message
|
||||
*
|
||||
* This function should be used when the return code of the
|
||||
* util_opt_getopt_long() function returns a character that does
|
||||
* not match any of the expected options.
|
||||
*
|
||||
* @param[in] opt Short option returned by getopt_long()
|
||||
* @param[in] argv Option array
|
||||
*/
|
||||
void util_opt_print_parse_error(char opt, char *argv[])
|
||||
{
|
||||
char optopt_str[3];
|
||||
|
||||
switch (opt) {
|
||||
case ':':
|
||||
/* A required option argument has not been specified */
|
||||
util_prg_print_required_arg(argv[optind - 1]);
|
||||
break;
|
||||
case '?':
|
||||
/* An invalid option has been specified */
|
||||
if (optopt) {
|
||||
/* Short option */
|
||||
sprintf(optopt_str, "-%c", optopt);
|
||||
util_prg_print_invalid_option(optopt_str);
|
||||
} else {
|
||||
/* Long option */
|
||||
util_prg_print_invalid_option(argv[optind - 1]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
util_panic("Option '%c' should not be handled here\n", opt);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user