1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
/*
* Copyright (C) 2016 Andre Noll <maan@tuebingen.mpg.de>
*
* Licensed under the LGPL v3, see https://www.gnu.org/licenses/lgpl-3.0.html
*/
#include <inttypes.h>
#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
|