/* * Copyright (C) 2016 Andre Noll * * Licensed under the LGPL v3, see https://www.gnu.org/licenses/lgpl-3.0.html */ #include #define LLS_ABI_VERSION 2 /* * Concat "lls_abi_version" and the ABI version number to produce the name of a * variable. To concat the *expansion* of the macro arguments, we have to use * two levels of macros since otherwise the arguments are not macro-expanded * first. */ #define LLS_CONCAT_EXPAND(_prefix, _suffix) LLS_CONCAT(_prefix, _suffix) #define LLS_CONCAT(_prefix, _suffix) _prefix ## _suffix #define LLS_ABI_VERSION_VAR LLS_CONCAT_EXPAND(lls_abi_version, LLS_ABI_VERSION) /* * Declare the variable. It is defined in lopsub.c, which is part of the * library. The single mission of this variable is to cause an error at link * time on ABI version mismatches. The actual value of the variable is * irrelevant. When the lopsubgen utility translates a suite into a .c file, * the generated C code references this variable, using the *lopsubgen* ABI * version for the reference. Therefore, if the lopsubgen ABI version differs * from the ABI version of the library, the symbol can not be resolved, * resulting in a link error. */ extern const unsigned LLS_ABI_VERSION_VAR; /* * Options may have an optional or mandatory argument. * * The lobsubgen command initializes the ->arg_info field of each lls_option * structure from the corresponding line of the .suite file. * * See also: ->arg_info of struct lls_option. */ enum lls_arg_info { LLS_NO_ARGUMENT, /* Option does not take an argument. */ LLS_REQUIRED_ARGUMENT, /* An argument must be given. */ LLS_OPTIONAL_ARGUMENT, /* Option takes an optional argument. */ }; /* * In addition to the argument type, there is a set of flags associated with * each option. All but the LLS_IGNORED flag correspond directly to the * possible values of the flag directive in the suite file. */ enum lls_option_flag { /* Store each given argument (rather than only the last). */ LLS_MULTIPLE = 1, /* It's an error if the option is not given. */ LLS_REQUIRED = 2, /* Whether a default value was specified in the suite file. */ LLS_HAS_DEFAULT = 4, /* For help text not related to any particular option. */ LLS_IGNORED = 8, }; /* * Ignored if arg_info is LLS_NO_ARGUMENT. A value of zero means no argument. * We don't need an identifier like LLS_NONE though, because we can test the * arg_info field to tell whether an argument can be supplied. * * See also: union lls_val. */ enum lls_arg_type { /* Option takes a string argument. */ LLS_STRING = 1, /* Signed 32 bit integer. */ LLS_INT32, /* Unsigned 32 bit integer. */ LLS_UINT32, /* Signed 64 bit integer. */ LLS_INT64, /* Unsigned 64 bit integer. */ LLS_UINT64, }; /* * Stores the argument to an option. * * The default value of an option, the set of possible values for an option and * the actually given value are all stored in an instance of this union. * * To determine the relevant alternative of the union, both the ->arg_type and * the ->values field of the corresponding struct lls_option are * important. For the values array itself, ->arg_type always determines the * alternative of each element in the array. For other objects the following * rule applies. If ->values is not given, ->arg_type determines the * alternative for both ->default_val and lls_opt_result->value. On the other * hand, if ->values is given, the ->uint32_val alternative is the index into * the ->values array that indicates which of the possible values is the * default value (for ->default_val) or was given in the arguments to * lls_parse() (lls_opt_result). */ union lls_val { char *string_val; /* LLS_STRING */ int32_t int32_val; /* LLS_INT32 */ uint32_t uint32_val; /* LLS_UINT32 */ int64_t int64_val; /* LLS_INT64 */ uint64_t uint64_val; /* LLS_UINT64 */ }; /* * Describes one option of one command of a suite. * * For each option of every command in the .suite file, lopsubgen * generates one structure of this type. */ struct lls_option { /* The long name (short-only options are not supported). */ const char * const name; /* Optional one-character variant. */ const char short_opt; /* Mandatory one-line summary. */ const char * const summary; /* Whether the option takes an argument, and if it is mandatory. */ const enum lls_arg_info arg_info; /* Which alternative of the lls_val union is chosen. */ const enum lls_arg_type arg_type; /* Description of the type of values (used for help output). */ const char * const typestr; /* See enum lls_option_flag. */ const unsigned flags; /* If not given, integer values default to 0, strings to NULL. */ const union lls_val default_val; /* Optional multi-line help text. */ const char * const help; /* If this is not NULL, only the given values are allowed. */ const union lls_val * const values; }; /* Describes a command of a suite. */ struct lls_command { /* Only identifiers are allowed as command names. */ const char * const name; /* One line of text, shown in all variants of help text. */ const char * const purpose; /* Multi line text in long help and man page. */ const char * const description; /* How non-option arguments should be called in the synopsis. */ const char * const non_opts_name; /* Optional, will be computed if not given. */ const char * const synopsis; /* Array of options for this command. */ const struct lls_option * const options; /* Closing remarks after the option list in long help and man page. */ const char * const closing; /* Initialized to com_NAME_user_data with NAME being the command name. */ const void * const user_data; /* Contains the array size of ->options. */ const int num_options; }; struct lls_suite { const char * const name; const char * const caption; const struct lls_command * const commands; const int num_subcommands; }; struct lls_opt_result { unsigned given; /* for multiple options, one value for each time the option was given */ union lls_val *value; }; struct lls_parse_result { char **inputs; /* non-options, non-args */ unsigned num_inputs; struct lls_opt_result *opt_result; /* one per option */ }; /* * Most library functions return a negative error code on failure. The * LLS_ERRORS macro expands to a list of all possible errors, optionally * including the text of each error code. The LLS_ERROR macro (without the * trailing S) controls how each error is expanded. */ #define LLS_ERRORS \ LLS_ERROR(SUCCESS, "success") \ LLS_ERROR(NOMEM, "allocation failure") \ LLS_ERROR(BAD_OPTION, "option not recognized") \ LLS_ERROR(AMBIG_OPTION, "option is ambiguous") \ LLS_ERROR(OPT_MANDATORY, "mandatory option not given") \ LLS_ERROR(ARG_GIVEN, "argument given to non-arg option") \ LLS_ERROR(NO_ARG_GIVEN, "argument required but not given") \ LLS_ERROR(TRAILING_BACKSLASH, "unexpected trailing backslash") \ LLS_ERROR(UNMATCHED_QUOTE, "unmatched quote character") \ LLS_ERROR(TRAILING_GARBAGE, "garbage at end of line or argument") \ LLS_ERROR(YY_SCAN, "error setting up lex input buffer") \ LLS_ERROR(YY_LEX, "yylex() failed") \ LLS_ERROR(BAD_SUBCMD, "invalid subcommand") \ LLS_ERROR(AMBIG_SUBCMD, "ambiguous subcommand") \ LLS_ERROR(BAD_ARG_COUNT, "invalid number of arguments") \ LLS_ERROR(OVERFLOW, "value too large") \ LLS_ERROR(NO_DIGITS, "no digits found in string") \ LLS_ERROR(ENUM, "invalid value for enum option") \ /* * Given an identifier and a string literal, forget the string, and prefix the * identifier with E_LLS_ to produce an identifier for an error code like * E_LLS_OVERFLOW. Finally, append a comma. While this definition of LLS_ERROR * is active, LLS_ERRORS expands to a comma-separated list of error codes. See * enum lls_errors below. */ #define LLS_ERROR(_n, _s) E_LLS_ ## _n, /* * Declare the enumeration of all error codes as identifiers like like * E_LLS_OVERFLOW. Also, the total number of error codes is declared as * NUM_LLS_ERRORS. */ enum lls_errors {LLS_ERRORS NUM_LLS_ERRORS}; #undef LLS_ERROR