Subject: [PATCH] [FEAT RTL1601] libutil: Add utility functions From: Peter Oberparleiter Summary: libutil: Add utility functions Description: Introduce utility functions for use by s390-tools. Upstream-ID: - Problem-ID: RTL1601 Signed-off-by: Peter Oberparleiter --- include/util_base.h | 2 include/util_libc.h | 125 +++++++++++++++++++ include/util_opt.h | 82 ++++++++++++ include/util_panic.h | 45 ++++++ include/util_prg.h | 55 ++++++++ libutil/Makefile | 11 + libutil/util_libc.c | 155 +++++++++++++++++++++++ libutil/util_opt.c | 281 +++++++++++++++++++++++++++++++++++++++++++ libutil/util_panic.c | 119 ++++++++++++++++++ libutil/util_prg.c | 111 ++++++++++++++++ 10 files changed, 985 insertions(+), 1 deletion(-) --- a/include/util_base.h +++ b/include/util_base.h @@ -15,4 +15,6 @@ void util_hexdump(FILE *fh, const char * void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int group, int cnt, int indent); +#define UTIL_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + #endif /* UTIL_BASE_H */ --- /dev/null +++ b/include/util_libc.h @@ -0,0 +1,125 @@ +/** + * @defgroup util_libc_h util_libc: Libc wrapper interface + * @{ + * @brief Handle standard errors for libc functions + * + * Copyright IBM Corp. 2016 + */ + +#ifndef UTIL_LIBC_H +#define UTIL_LIBC_H + +#include + +/** + * Allocate memory or panic in case of failure + * + * @param[in] size Number of bytes to be allocated + * + * @returns Pointer to allocated memory buffer + */ +#define util_malloc(size) \ + __util_malloc(__func__, __FILE__, __LINE__, size) + +void *__util_malloc(const char *func, const char *file, int line, size_t size); + +/** + * Allocate zero-initialized memory or panic in case of failure + * + * @param[in] size Number of bytes to be allocated + * + * @returns Pointer to allocated memory buffer initialized with zeroes + */ +#define util_zalloc(size) \ + __util_zalloc(__func__, __FILE__, __LINE__, size) + +void *__util_zalloc(const char *func, const char *file, int line, size_t size); + + +/** + * Re-allocate memory or exit in case of failure + * + * @param[in] ptr Pointer ot old memory buffer + * @param[in] size Number of bytes to be allocated + * + * @returns Pointer to allocated memory buffer + */ +#define util_realloc(ptr, size) \ + __util_realloc(__func__, __FILE__, __LINE__, ptr, size) + +void *__util_realloc(const char *func, const char *file, int line, + void *ptr, size_t size); + +/** + * Duplicate a string buffer or exit in case of failure + * + * @param[in] str String to be duplicated + * + * @returns Pointer to newly allocated and copied string + */ +#define util_strdup(str) \ + __util_strdup(__func__, __FILE__, __LINE__, str) + +void *__util_strdup(const char *func, const char *file, int line, + const char *str); + +/** + * Print to allocated string or exit in case of failure + * + * @param[in] strp String to be allocated + * @param[in] fmt Format string for generation of string + * @param[in] ap Parameters for format string + * + * @returns num Number of formatted characters + */ +#define util_vasprintf(strp, fmt, ap) \ + __util_vasprintf(__func__, __FILE__, __LINE__, strp, fmt, ap) + +#define UTIL_VASPRINTF(strp, fmt, ap) \ +do { \ + va_start(ap, fmt); \ + util_vasprintf(strp, fmt, ap); \ + va_end(ap); \ +} while (0) + +int __util_vasprintf(const char *func, const char *file, int line, + char **strp, const char *fmt, va_list ap); + +/** + * Print to newly allocated string or exit in case of failure + * + * @param[in] strp String to be allocated + * @param[in] ... Format string and parameters for format string + * + * @returns num Number of formatted characters + */ +#define util_asprintf(strp, ...) \ + __util_asprintf(__func__, __FILE__, __LINE__, strp, ##__VA_ARGS__) + +int __util_asprintf(const char *func, const char *file, int line, + char **strp, const char *fmt, ...); + + +/** + * Print to string buffer or exit in case of failure + * + * @param[in] str String buffer + * @param[in] fmt Format string for generation of string + * @param[in] ap Parameters for format string + * + * @returns num Number of formatted characters + */ +#define util_vsprintf(str, fmt, ap) \ + __util_vsprintf(__func__, __FILE__, __LINE__, str, fmt, ap) + +#define UTIL_VSPRINTF(str, fmt, ap) \ +do { \ + va_start(ap, fmt); \ + util_vsprintf(str, fmt, ap); \ + va_end(ap); \ +} while (0) + +int __util_vsprintf(const char *func, const char *file, int line, + char *str, const char *fmt, va_list ap); + +#endif /** UTIL_LIBC_H @} */ --- /dev/null +++ b/include/util_opt.h @@ -0,0 +1,82 @@ +/** + * @defgroup util_opt_h util_opt: Command line options interface + * @{ + * @brief Parse the command line options + * + * Copyright IBM Corp. 2016 + */ + +#ifndef UTIL_OPT_H +#define UTIL_OPT_H + +#include +#include + +/* Flag indicating that an option does not have a short form */ +#define UTIL_OPT_FLAG_NOSHORT 1 + +/* Flag indicating that an option does not have a long form */ +#define UTIL_OPT_FLAG_NOLONG 2 + +/* Flag indicating that this is a section heading */ +#define UTIL_OPT_FLAG_SECTION 4 + +/** + * Command line option + */ +struct util_opt { + /** Defined by getopt.h, see "man getopt_long" */ + struct option option; + /** For options with arguments: Argument name */ + char *argument; + /** Description displayed for --help */ + char *desc; + /** Flags for this option */ + int flags; +}; + +/** + * Standard option: --help + */ +#define UTIL_OPT_HELP \ +{ \ + .option = { "help", 0, NULL, 'h' }, \ + .desc = "Print this help, then exit", \ +} + +/** + * Standard option: --version + */ +#define UTIL_OPT_VERSION \ +{ \ + .option = { "version", 0, NULL, 'v' }, \ + .desc = "Print version information, then exit", \ +} + +/** + * End-marker for the option pointer vector + */ +#define UTIL_OPT_END \ +{ \ + .option = { NULL, 0, NULL, 0 }, \ +} + +/** + * Section header + */ +#define UTIL_OPT_SECTION(title) \ +{ \ + .desc = (title), \ + .flags = UTIL_OPT_FLAG_SECTION, \ +} + +/* + * Option functions + */ +void util_opt_init(struct util_opt *opt_vec, const char *opt_prefix); +int util_opt_getopt_long(int argc, char *argv[]); +void util_opt_print_help(void); +void util_opt_print_indented(const char *opt, const char *desc); +void util_opt_print_parse_error(char opt, char *argv[]); + +#endif /** UTIL_OPT_H @} */ --- /dev/null +++ b/include/util_panic.h @@ -0,0 +1,45 @@ +/** + * @defgroup util_panic_h util_panic: Panic interface + * @{ + * @brief Collect FFDC data for unexpected errors + * + * Copyright IBM Corp. 2016 + */ + +#ifndef UTIL_PANIC_H +#define UTIL_PANIC_H + +#include "zt_common.h" + +#ifndef __noreturn +#define __noreturn +#endif + +/** + * Write message, print backtrace and then call the abort() function + * + * @param[in] ... Format string and parameters describing the panic reason + */ +#define util_panic(...) \ + __util_panic(__func__, __FILE__, __LINE__, ##__VA_ARGS__) + +void __util_panic(const char *func, const char *file, int line, + const char *fmt, ...) __noreturn; + +/** + * Ensure that assumption is not true, otherwise panic + * + * Example: util_assert(ptr == NULL, "The ptr must be NULL, but is %p", ptr) + * + * @param[in] assumption This assumption has to be true + * @param[in] ... Format string and parameters describing the assumption + */ +#define util_assert(assumption, ...) \ + __util_assert(#assumption, __func__, __FILE__, __LINE__, \ + assumption, ##__VA_ARGS__) + +void __util_assert(const char *assertion_string, + const char *func, const char *file, int line, + int assumption, const char *fmt, ...); + +#endif /** UTIL_PANIC_H @} */ --- /dev/null +++ b/include/util_prg.h @@ -0,0 +1,55 @@ +/** + * @defgroup util_prg_h util_prg: Program interface + * @{ + * @brief Print standard program messages + * + * Copyright IBM Corp. 2016 + */ + +#ifndef UTIL_PRG_H +#define UTIL_PRG_H + +#include +#include +#include +#include +#include + +/** + * Copyright description + */ +struct util_prg_copyright { + /** Name of the copyright owner, e.g. IBM */ + const char *owner; + /** Year of first publishing */ + int pub_first; + /** Year of last major changes */ + int pub_last; +}; + +/** + * @brief Coypright end marker + */ +#define UTIL_PRG_COPYRIGHT_END {NULL, 0, 0} + +/** + * Program description + */ +struct util_prg { + /** Description for help */ + const char *desc; + /** Positional arguments */ + const char *args; + /** Copyright list */ + struct util_prg_copyright copyright_vec[]; +}; + +void util_prg_init(const struct util_prg *prg); +void util_prg_print_parse_error(void); +void util_prg_print_required_arg(const char *option); +void util_prg_print_invalid_option(const char *option); +void util_prg_print_arg_error(const char *arg_name); +void util_prg_print_version(void); +void util_prg_print_help(void); + +#endif /** UTIL_PRG_H @} */ --- a/libutil/Makefile +++ b/libutil/Makefile @@ -2,12 +2,21 @@ include ../common.mak CPPFLAGS += -I../include -all: util_base.o util_list.o util_part.o util_proc.o +all: util_base.o util_list.o util_part.o util_proc.o util_libc.o util_opt.o \ + util_panic.o util_prg.o util_list.o: util_list.c ../include/util.h util_proc.o: util_proc.c ../include/util_proc.h +util_libc.o: util_libc.c ../include/util_libc.h + +util_opt.o: util_opt.c ../include/util_opt.h + +util_panic.o: util_panic.c ../include/util_panic.h + +util_prg.o: util_prg.c ../include/util_prg.h + install: all clean: --- /dev/null +++ b/libutil/util_libc.c @@ -0,0 +1,155 @@ +/* + * util - Utility function library + * + * Handle standard errors for libc functions + * + * Copyright IBM Corp. 2016 + */ + +#define _GNU_SOURCE /* for program_invocation_short_name */ + +#include +#include +#include +#include +#include + +#include "util_base.h" +#include "util_panic.h" +#include "util_libc.h" + +/* + * Return size as string of largest unit, e.g. 1025 = "1 KiB" + */ +static void format_size(char *str, size_t size) +{ + static const char * const unit_vec[] = + {"byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; + unsigned int i; + + for (i = 0; i < UTIL_ARRAY_SIZE(unit_vec); i++) { + if (size / 1024 == 0) { + sprintf(str, "%zu %s", size, unit_vec[i]); + return; + } + size /= 1024; + } + sprintf(str, "huge"); +} + +static void __util_oom(const char *func, const char *file, int line, + size_t size) +{ + char size_str[256]; + + fprintf(stderr, "%s: Failed to allocate memory", + program_invocation_short_name); + if (size > 0) { + format_size(size_str, size); + fprintf(stderr, " (%s)", size_str); + } + fprintf(stderr, " at %s:%d %s()\n", file, line, func); + exit(EXIT_FAILURE); +} + +/* + * Allocate memory or exit in case of failure + */ +void *__util_malloc(const char *func, const char *file, int line, size_t size) +{ + void *buf; + + buf = malloc(size); + + if (buf == NULL) + __util_oom(func, file, line, size); + + return buf; +} + +/* + * Allocate zero-initialized memory or exit in case of failure + */ +void *__util_zalloc(const char *func, const char *file, int line, size_t size) +{ + void *buf = __util_malloc(func, file, line, size); + + memset(buf, 0, size); + + return buf; +} + +/* + * Re-allocate memory or exit in case of failure + */ +void *__util_realloc(const char *func, const char *file, int line, + void *ptr, size_t size) +{ + void *buf; + + buf = realloc(ptr, size); + + if (buf == NULL) + __util_oom(func, file, line, size); + + return buf; +} + +/* + * Duplicate a string buffer or exit in case of failure + */ +void *__util_strdup(const char *func, const char *file, int line, + const char *str) +{ + void *buf = strdup(str); + + if (buf == NULL) + __util_oom(func, file, line, strlen(str) + 1); + + return buf; +} + +/* + * Print to newly allocated string or exit in case of failure + */ +int __util_vasprintf(const char *func, const char *file, int line, + char **strp, const char *fmt, va_list ap) +{ + int rc; + + rc = vasprintf(strp, fmt, ap); + if (rc == -1) + __util_oom(func, file, line, 0); + + return rc; +} + +/* + * Print to newly allocated string or exit in case of failure + */ +int __util_asprintf(const char *func, const char *file, int line, + char **strp, const char *fmt, ...) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = __util_vasprintf(func, file, line, strp, fmt, ap); + va_end(ap); + return rc; +} + +/* + * Print to string buffer or exit in case of failure + */ +int __util_vsprintf(const char *func, const char *file, int line, + char *str, const char *fmt, va_list ap) +{ + int rc; + + rc = vsprintf(str, fmt, ap); + if (rc == -1) + __util_assert("rc != -1", func, file, line, + rc != -1, "Could not format string\n"); + return rc; +} --- /dev/null +++ b/libutil/util_opt.c @@ -0,0 +1,281 @@ +/* + * util - Utility function library + * + * Parse the command line options + * + * Copyright IBM Corp. 2016 + */ + +#include +#include +#include +#include +#include + +#include "util_base.h" +#include "util_libc.h" +#include "util_opt.h" +#include "util_panic.h" +#include "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; +} 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(x, y) ((x) < (y) ? (y) : (x)) +#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; + 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'; + + l.opt_max = opt_max_len(); +} + +/** + * 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[]) +{ + return getopt_long(argc, argv, l.opt_str, l.option_vec, NULL); +} + +/* + * 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 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; + format_opt(opt_str, MAX_OPTLEN, opt); + max = MAX(max, strlen(opt_str)); + } + return max; +} + +/* + * Print option description with indentation + */ +static void print_opt_description(const char *desc_in, int indent) +{ + char *word, *line, *desc, *desc_ptr; + int word_len, pos = indent; + + desc = desc_ptr = util_strdup(desc_in); + line = strsep(&desc, "\n"); + while (line) { + word = strsep(&line, " "); + pos = indent; + while (word) { + word_len = strlen(word); + if (pos + word_len + 1 > 80) { + printf("\n%*s", indent, " "); + pos = indent; + } + printf(" %s", word); + pos += word_len + 1; + word = strsep(&line, " "); + } + if (desc) + printf("\n%*s", indent, " "); + line = strsep(&desc, "\n"); + } + printf("\n"); + free(desc_ptr); +} + +/** + * 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, opt); + print_opt_description(desc, 2 + 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, --%-s %s" + * + * Example: + * + * -p, --print STRING Print STRING to console + */ + util_opt_iterate(opt) { + 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); + } +} + --- /dev/null +++ b/libutil/util_panic.c @@ -0,0 +1,119 @@ +/* + * util - Utility function library + * + * Collect FFDC data for unexpected errors + * + * Copyright IBM Corp. 2016 + */ + +#include +#include + +#include +#include +#include +#include + +#include "util_base.h" +#include "util_panic.h" + +/* + * Obtain a backtrace and print it to stderr + * + * To get symbols, compile the code with "-rdynamic". + */ +static void print_backtrace(void) +{ + void *array[256]; + size_t i, size; + char **strings; + + fprintf(stderr, "Backtrace:\n\n"); + size = backtrace(array, UTIL_ARRAY_SIZE(array)); + strings = backtrace_symbols(array, size); + if (strings == NULL) { + fprintf(stderr, " Could not obtain backtrace (ENOMEM)\n"); + return; + } + for (i = 0; i < size; i++) + fprintf(stderr, " %s\n", strings[i]); + + free(strings); +} + +/* + * Check for core ulimit + */ +static void ulimit_core_check(void) +{ + struct rlimit limit; + + if (getrlimit(RLIMIT_CORE, &limit) != 0) + return; + if (limit.rlim_cur != 0) + return; + fprintf(stderr, "Core dump size is zero. To get a full core dump use 'ulimit -c unlimited'.\n"); +} + +/* + * Print FFDC data and then abort + */ +static void panic_finish(const char *func, const char *file, int line, + const char *fmt, va_list ap) +{ + /* Write panic error string */ + fprintf(stderr, "\n"); + fprintf(stderr, "Error string:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + /* Write file, line number, and function name */ + fprintf(stderr, "Location:\n\n"); + fprintf(stderr, " %s:%d: %s()\n", file, line, func); + fprintf(stderr, "\n"); + + /* Print the function backtrace */ + print_backtrace(); + fprintf(stderr, "\n"); + + ulimit_core_check(); + fprintf(stderr, "----------------------------------------------------------------------->8-----\n"); + abort(); +} + +/* + * Do panic processing if the assumption is not true + */ +void __util_assert(const char *assertion_str, + const char *func, const char *file, int line, + int assumption, const char *fmt, ...) +{ + va_list ap; + + if (assumption) + return; + va_start(ap, fmt); + fprintf(stderr, "---8<-------------------------------------------------------------------------\n"); + fprintf(stderr, "ASSERTION FAILED: The application terminated due to an internal or OS error\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "The following assumption was *not* true:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " %s\n", assertion_str); + panic_finish(func, file, line, fmt, ap); +} + +/* + * Do panic processing + */ +void __util_panic(const char *func, const char *file, int line, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "---8<-------------------------------------------------------------------------\n"); + fprintf(stderr, "PANIC: The application terminated due to an unrecoverable error\n"); + panic_finish(func, file, line, fmt, ap); + while(1); +} --- /dev/null +++ b/libutil/util_prg.c @@ -0,0 +1,111 @@ +/* + * util - Utility function library + * + * Print standard program messages + * + * Copyright IBM Corp. 2016 + */ + +#define _GNU_SOURCE /* for program_invocation_short_name */ + +#include +#include + +#include "util_prg.h" +#include "zt_common.h" + +/* + * Private data + */ +static struct util_prg_l { + const struct util_prg *prg; +} l; + +struct util_prg_l *util_prg_l = &l; + +/** + * Print program usage information for the --help option + */ +void util_prg_print_help(void) +{ + printf("Usage: %s [OPTIONS]", program_invocation_short_name); + if (l.prg->args) + printf(" %s", l.prg->args); + printf("\n\n%s\n\n", l.prg->desc); +} + +/** + * Print program version information for the --version option + */ +void util_prg_print_version(void) +{ + const struct util_prg_copyright *copyright; + + printf("%s version %s\n", program_invocation_short_name, + RELEASE_STRING); + copyright = l.prg->copyright_vec; + while (copyright->owner) { + if (copyright->pub_first == copyright->pub_last) + printf("Copyright %s %d\n", copyright->owner, + copyright->pub_first); + else + printf("Copyright %s %d, %d\n", copyright->owner, + copyright->pub_first, copyright->pub_last); + copyright++; + } +} + +/* + * Ask user to use the --help option + */ +void util_prg_print_parse_error(void) +{ + fprintf(stderr, "Try '%s --help' for more information.\n", + program_invocation_short_name); +} + +/** + * An option has been specified that is not supported + * + * @param[in] option Option string (short or long) + */ +void util_prg_print_invalid_option(const char *opt_name) +{ + fprintf(stderr, "%s: Invalid option '%s'\n", + program_invocation_short_name, opt_name); + util_prg_print_parse_error(); +} + +/** + * A required argument for an option is missing + * + * @param[in] option Option string + */ +void util_prg_print_required_arg(const char *opt_name) +{ + fprintf(stderr, "%s: Option '%s' requires an argument\n", + program_invocation_short_name, opt_name); + util_prg_print_parse_error(); +} + +/** + * A superfluous invalid positional argument has been specified + * + * @param[in] arg_name Name of the invalid argument + */ +void util_prg_print_arg_error(const char *arg_name) +{ + fprintf(stderr, "%s: Invalid argument '%s'\n", + program_invocation_short_name, arg_name); + util_prg_print_parse_error(); +} + +/** + * Initialize the program module + * + * @param[in] prg Program description + */ +void util_prg_init(const struct util_prg *prg) +{ + l.prg = prg; +}