1 #ifndef _LIBHX_OPTION_H
2 #define _LIBHX_OPTION_H 1
3 
4 #ifdef __cplusplus
5 #	include <cstddef>
6 #	include <cstdio>
7 #else
8 #	include <stddef.h>
9 #	include <stdio.h>
10 #endif
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 #ifndef __libhx_internal_hxmc_t_defined
17 #define __libhx_internal_hxmc_t_defined 1
18 typedef char hxmc_t;
19 #endif
20 
21 struct HXoption;
22 
23 /*
24  *	FORMAT.C
25  */
26 extern struct HXformat_map *HXformat_init(void);
27 extern void HXformat_free(struct HXformat_map *);
28 extern int HXformat_add(struct HXformat_map *, const char *, const void *,
29 	unsigned int);
30 extern int HXformat_aprintf(const struct HXformat_map *,
31 	hxmc_t **, const char *);
32 extern int HXformat_sprintf(const struct HXformat_map *,
33 	char *, size_t, const char *);
34 extern int HXformat_fprintf(const struct HXformat_map *,
35 	FILE *, const char *);
36 
37 /*
38  *	OPT.C
39  */
40 
41 /**
42  * Available types for struct HXoption.type.
43  * %HXTYPE_NONE:	[-o] (int *) No argument; counts presence.
44  * %HXTYPE_VAL:		[-o] (int *) Set to value in .val.
45  * %HXTYPE_SVAL:	[-o] (const char *) Set to value in .uptr.
46  * %HXTYPE_BOOL:	[fo] (int *) Parse argument as boolean
47  * 			     ("yes", "no", "true", "false", 0 or non-zero)
48  * %HXTYPE_BYTE:	[fo] (unsigned char *) Take first char of argument
49  * %HXTYPE_UCHAR:	[fo] (unsigned char *) An integer.
50  * %HXTYPE_CHAR:	[fo] (char *) An integer.
51  * %HXTYPE_USHORT:	[fo] (unsigned short *) An integer.
52  * %HXTYPE_SHORT:	[fo] (short *) An integer.
53  * %HXTYPE_UINT:	[fo] (unsigned int *) An integer.
54  * %HXTYPE_INT:		[fo] (int *) An integer.
55  * %HXTYPE_ULONG:	[fo] (unsigned long *) An integer.
56  * %HXTYPE_LONG:	[fo] (long *) An integer.
57  * %HXTYPE_ULLONG:	[fo] (unsigned long long *) An integer.
58  * %HXTYPE_LLONG:	[fo] (long long *) An integer.
59  * %HXTYPE_FLOAT:	[fo] (float *) Read a floating point number
60  * %HXTYPE_DOUBLE:	[fo] (double *) Read a floating point number
61  * %HXTYPE_STRING:	[fo] (char **) Any string.
62  * %HXTYPE_STRP:	[f-] (const char *const *) A string.
63  * %HXTYPE_STRDQ:	[-o] (struct HXdeque *) A string.
64  * %HXTYPE_UINT8:	[-o] (uint8_t *) An integer.
65  * %HXTYPE_UINT16:	[-o] (uint8_t *) An integer.
66  * %HXTYPE_UINT32:	[-o] (uint8_t *) An integer.
67  * %HXTYPE_UINT64:	[-o] (uint8_t *) An integer.
68  * %HXTYPE_INT8:	[-o] (uint8_t *) An integer.
69  * %HXTYPE_INT16:	[-o] (uint8_t *) An integer.
70  * %HXTYPE_INT32:	[-o] (uint8_t *) An integer.
71  * %HXTYPE_INT64:	[-o] (uint8_t *) An integer.
72  * %HXTYPE_MCSTR:	[-o] (hxmc_t *) A string.
73  * %HXTYPE_XSNTMARK:	[-o] Internal sentinal marker (used in HXOPT_TABLEEND)
74  * %HXTYPE_XHELP:	[-o] Internal helper marker (used in HXOPT_AUTOHELP)
75  * %HXTYPE_SIZE_T:	[-o] (size_t *) An integer.
76  *
77  * Type expected of struct HXoption.ptr is given in ().
78  * HX_getopt (o) and HXformat_* (f) support different sets, marked with [].
79  */
80 enum HX_option_type {
81 	HXTYPE_NONE = 0,
82 	HXTYPE_VAL,
83 	HXTYPE_SVAL,
84 	HXTYPE_BOOL,
85 	HXTYPE_BYTE,
86 	HXTYPE_UCHAR, /* 5 */
87 	HXTYPE_CHAR,
88 	HXTYPE_USHORT,
89 	HXTYPE_SHORT,
90 	HXTYPE_UINT,
91 	HXTYPE_INT, /* 10 */
92 	HXTYPE_ULONG,
93 	HXTYPE_LONG,
94 	HXTYPE_ULLONG,
95 	HXTYPE_LLONG,
96 	HXTYPE_FLOAT, /* 15 */
97 	HXTYPE_DOUBLE,
98 	HXTYPE_STRING,
99 	HXTYPE_STRP, /* (const char **) */
100 	HXTYPE_STRDQ,
101 	HXTYPE_UINT8, /* 20 */
102 	HXTYPE_UINT16,
103 	HXTYPE_UINT32,
104 	HXTYPE_UINT64,
105 	HXTYPE_INT8,
106 	HXTYPE_INT16, /* 25 */
107 	HXTYPE_INT32,
108 	HXTYPE_INT64,
109 	HXTYPE_MCSTR,
110 	HXTYPE_XSNTMARK,
111 	HXTYPE_XHELP, /* 30 */
112 	HXTYPE_SIZE_T,
113 };
114 
115 /**
116  * Extra flags to be OR'ed into struct HXoption.type.
117  * %HXOPT_OPTIONAL:	argument to option is optional
118  * 			(it's bad taste to use this)
119  * %HXOPT_INC:		increase variable pointed to by .ptr.
120  * 			(only applies to %HXTYPE_NONE)
121  * %HXOPT_DEC:		increase variable pointed to by .ptr.
122  * 			(only applies to %HXTYPE_NONE)
123  * %HXOPT_NOT:		negate input (*ptr), this is done before OR/AND
124  * %HXOPT_OR:		OR *ptr by argument
125  * %HXOPT_AND:		AND *ptr by argument
126  * %HXOPT_XOR:		XOR *ptr by argument
127  */
128 enum {
129 	HXOPT_OPTIONAL = 1 << 6,
130 	HXOPT_INC      = 1 << 7,
131 	HXOPT_DEC      = 1 << 8,
132 	HXOPT_NOT      = 1 << 9,
133 	HXOPT_OR       = 1 << 10,
134 	HXOPT_AND      = 1 << 11,
135 	HXOPT_XOR      = 1 << 12,
136 };
137 
138 /**
139  * Flags (4th arg) to HX_getopt.
140  * %HXOPT_PTHRU:	pass-through unknown options to new argv
141  * %HXOPT_DESTROY_OLD:	destroy old argv after parsing is successful
142  * %HXOPT_QUIET:	do not output any warnings to stderr
143  * %HXOPT_HELPONERR:	print out help when a parsing error occurs
144  * %HXOPT_USAGEONERR:	print out short usage when a parsing error occurs
145  * %HXOPT_RQ_ORDER:	require option order/POSIX mode:
146  * 			first non-option terminates option processing
147  */
148 enum {
149 	HXOPT_PTHRU       = 1 << 0,
150 	HXOPT_DESTROY_OLD = 1 << 1,
151 	HXOPT_QUIET       = 1 << 2,
152 	HXOPT_HELPONERR   = 1 << 3,
153 	HXOPT_USAGEONERR  = 1 << 4,
154 	HXOPT_RQ_ORDER    = 1 << 5,
155 };
156 
157 /**
158  * (Positive-ranged) return values for HX_getopt.
159  * %HXOPT_ERR_SUCCESS:	success
160  * %HXOPT_ERR_UNKN:	unknown option was encountered
161  * %HXOPT_ERR_VOID:	long option takes no value
162  * %HXOPT_ERR_MIS:	option requires a value argument
163  * %HXOPT_ERR_AMBIG:	long option abbreviation was ambiguous
164  */
165 enum {
166 	HXOPT_ERR_SUCCESS = 0,
167 	HXOPT_ERR_UNKN,
168 	HXOPT_ERR_VOID,
169 	HXOPT_ERR_MIS,
170 	HXOPT_ERR_AMBIG,
171 };
172 
173 /**
174  * Extra flags to be OR'ed into HXformat_add()'s 4th arg.
175  * %HXFORMAT_IMMED:	do not dereference the 4th arg to get at the value
176  */
177 enum {
178 	HXFORMAT_IMMED = 1 << 13,
179 };
180 
181 /**
182  * Flags for HX_shconfig_pv()
183  * %SHCONF_ONE:		only read one configuration file
184  */
185 enum {
186 	SHCONF_ONE = 1 << 0,
187 };
188 
189 /**
190  * Flags in struct HXoptcb.flags
191  * %HXOPTCB_BY_LONG:	cb was called by invocation of @current->ln
192  * %HXOPTCB_BY_SHORT:	cb was called by invocation of @current->sh
193  */
194 enum {
195 	HXOPTCB_BY_LONG  = 1 << 0,
196 	HXOPTCB_BY_SHORT = 1 << 1,
197 };
198 
199 struct HXoptcb {
200 	const struct HXoption *table, *current;
201 	const char *data;
202 	union {
203 		double data_dbl;
204 		long data_long;
205 	};
206 	unsigned int flags;
207 };
208 
209 /**
210  * @ln:		long option string (without "--"), or %NULL
211  * @sh:		short option character, or '\0'
212  * @type:	type of variable pointed to by .ptr
213  * @ptr:	pointer to variable to set/update
214  * @uptr:	freeform user-supplied pointer;
215  * 		in case of %HXTYPE_SVAL, this is the specific value to set
216  * @cb:		callback function to invoke, or %NULL
217  * @val:	specific value to set if type == HXTYPE_VAL
218  * @help:	help string to display
219  * @htyp:	type string to show in option's help
220  */
221 struct HXoption {
222 	const char *ln;
223 	char sh;
224 	unsigned int type;
225 	void *ptr, *uptr;
226 	void (*cb)(const struct HXoptcb *);
227 	int val;
228 	const char *help, *htyp;
229 };
230 
231 extern int HX_getopt(const struct HXoption *, int *, const char ***,
232 	unsigned int);
233 extern void HX_getopt_help(const struct HXoptcb *, FILE *);
234 extern void HX_getopt_help_cb(const struct HXoptcb *);
235 extern void HX_getopt_usage(const struct HXoptcb *, FILE *);
236 extern void HX_getopt_usage_cb(const struct HXoptcb *);
237 extern int HX_shconfig(const char *, const struct HXoption *);
238 extern struct HXmap *HX_shconfig_map(const char *);
239 extern int HX_shconfig_pv(const char **, const char *,
240 	const struct HXoption *, unsigned int);
241 extern void HX_shconfig_free(const struct HXoption *);
242 
243 #ifdef __cplusplus
244 } /* extern "C" */
245 #endif
246 
247 #ifndef __cplusplus
248 #	define HXOPT_AUTOHELP \
249 		{.ln = "help", .sh = '?', .type = HXTYPE_XHELP, \
250 		.cb = HX_getopt_help_cb, .help = "Show this help message"}, \
251 		{.ln = "usage", .type = HXTYPE_NONE, \
252 		.cb = HX_getopt_usage_cb, \
253 		.help = "Display brief usage message"}
254 #	define HXOPT_TABLEEND {.type = HXTYPE_XSNTMARK}
255 #else
256 #	define HXOPT_AUTOHELP \
257 		{"help", '?', HXTYPE_XHELP, NULL, NULL, HX_getopt_help_cb, \
258 		0, "Show this help message"}, \
259 		{"usage", 0, HXTYPE_NONE, NULL, NULL, HX_getopt_usage_cb, \
260 		0, "Display brief usage message"}
261 #	define HXOPT_TABLEEND {NULL, 0, HXTYPE_XSNTMARK}
262 #endif
263 
264 #endif /* _LIBHX_OPTION_H */
265