1
2/*
3 *  \file autoopts.h
4 *
5 *  This file defines all the global structures and special values
6 *  used in the automated option processing library.
7 *
8 * @group autoopts
9 * @{
10 */
11/*
12 *  This file is part of AutoOpts, a companion to AutoGen.
13 *  AutoOpts is free software.
14 *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
15 *
16 *  AutoOpts is available under any one of two licenses.  The license
17 *  in use must be one of these two and the choice is under the control
18 *  of the user of the license.
19 *
20 *   The GNU Lesser General Public License, version 3 or later
21 *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
22 *
23 *   The Modified Berkeley Software Distribution License
24 *      See the file "COPYING.mbsd"
25 *
26 *  These files have the following sha256 sums:
27 *
28 *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
29 *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
30 *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
31 */
32
33#ifndef AUTOGEN_AUTOOPTS_H
34#define AUTOGEN_AUTOOPTS_H
35#include <stdnoreturn.h>
36
37#define AO_NAME_LIMIT           127
38#define AO_NAME_SIZE            ((size_t)(AO_NAME_LIMIT + 1))
39
40#ifndef AG_PATH_MAX
41#  ifdef PATH_MAX
42#    define AG_PATH_MAX         ((size_t)PATH_MAX)
43#  else
44#    ifdef __gnu_hurd__
45#      define size_t unsigned long
46#    endif
47#    define AG_PATH_MAX         ((size_t)4096)
48#  endif
49#else
50#  if defined(PATH_MAX) && (PATH_MAX > MAXPATHLEN)
51#     undef  AG_PATH_MAX
52#     define AG_PATH_MAX        ((size_t)PATH_MAX)
53#  endif
54#endif
55
56#undef  EXPORT
57#define EXPORT
58
59#ifndef NUL
60#define NUL                     '\0'
61#endif
62#define BEL                     '\a'
63#define BS                      '\b'
64#define HT                      '\t'
65#define LF                      '\n'
66#define VT                      '\v'
67#define FF                      '\f'
68#define CR                      '\r'
69
70#if defined(_WIN32) && !defined(__CYGWIN__)
71# define DIRCH                  '\\'
72#else
73# define DIRCH                  '/'
74#endif
75
76#ifndef EX_USAGE
77   /**
78    *  Command line usage problem
79    */
80#  define EX_USAGE              64
81#endif
82#ifndef EX_DATAERR
83   /**
84    *  The input data was incorrect in some way.
85    */
86#  define EX_DATAERR            64
87#endif
88#ifndef EX_NOINPUT
89   /**
90    *  option state was requested from a file that cannot be loaded.
91    */
92#  define EX_NOINPUT            66
93#endif
94#ifndef EX_SOFTWARE
95   /**
96    *  AutoOpts Software failure.
97    */
98#  define EX_SOFTWARE           70
99#endif
100#ifndef EX_OSERR
101   /**
102    *  Command line usage problem
103    */
104#  define EX_OSERR              71
105#endif
106
107#define NL '\n'
108#ifndef C
109/**
110 *  Coercive cast.  Compel an address to be interpreted as the type
111 *  of the first argument.  No complaints, just do it.
112 */
113#define C(_t,_p)  ((_t)VOIDP(_p))
114#endif
115
116/* The __attribute__((__warn_unused_result__)) feature
117   is available in gcc versions 3.4 and newer,
118   while the typeof feature has been available since 2.7 at least.  */
119# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
120#  define ignore_val(x) ((void) (x))
121# else
122#  define ignore_val(x) (({ __typeof__ (x) __x = (x); (void) __x; }))
123# endif
124
125/*
126 *  Convert the number to a list usable in a printf call
127 */
128#define NUM_TO_VER(n)           ((n) >> 12), ((n) >> 7) & 0x001F, (n) & 0x007F
129
130#define NAMED_OPTS(po) \
131        (((po)->fOptSet & (OPTPROC_SHORTOPT | OPTPROC_LONGOPT)) == 0)
132
133#define SKIP_OPT(p)  (((p)->fOptState & OPTST_IMMUTABLE_MASK) != 0)
134
135typedef int tDirection;
136/**
137 * handling option presets.  Start with command line and work through
138 * config settings in reverse order.
139 */
140#define DIRECTION_PRESET        -1
141/**
142 * handling normal options.  Start with first config file, then environment
143 * variables and finally the command line.
144 */
145#define DIRECTION_PROCESS       1
146/**
147 * An initialzation phase or an option being loaded from program sources.
148 */
149#define DIRECTION_CALLED        0
150
151#define PROCESSING(d)           ((d)>0)
152#define PRESETTING(d)           ((d)<0)
153#define CALLED(d)               ((d)==0)
154
155/**
156 *  When loading a line (or block) of text as an option, the value can
157 *  be processed in any of several modes.
158 */
159typedef enum {
160    /**
161     *  If the value looks like a quoted string, then process it.  Double
162     *  quoted strings are processed the way strings are in "C" programs,
163     *  except they are treated as regular characters if the following
164     *  character is not a well-established escape sequence.  Single quoted
165     *  strings (quoted with apostrophies) are handled the way strings are
166     *  handled in shell scripts, *except* that backslash escapes are
167     *  honored before backslash escapes and apostrophies.
168     */
169    OPTION_LOAD_COOKED,
170
171    /**
172     * Even if the value begins with quote characters, do not do quote
173     * processing.  Strip leading and trailing white space.
174     */
175    OPTION_LOAD_UNCOOKED,
176
177    /**
178     * Keep every part of the value between the delimiters.
179     */
180    OPTION_LOAD_KEEP
181} tOptionLoadMode;
182
183static tOptionLoadMode option_load_mode;
184
185/**
186 *  The pager state is used by optionPagedUsage() procedure.
187 *  When it runs, it sets itself up to be called again on exit.
188 *  If, however, a routine needs a child process to do some work
189 *  before it is done, then 'pagerState' must be set to
190 *  'PAGER_STATE_CHILD' so that optionPagedUsage() will not try
191 *  to run the pager program before its time.
192 */
193typedef enum {
194    PAGER_STATE_INITIAL, //@< initial option paging state
195
196    /**
197     * temp file created and optionPagedUsage is scheduled to run at exit
198     */
199    PAGER_STATE_READY,
200
201    /**
202     *  This is a child process used in creating shell script usage.
203     */
204    PAGER_STATE_CHILD
205} tePagerState;
206
207typedef enum {
208    ENV_ALL,
209    ENV_IMM,
210    ENV_NON_IMM
211} teEnvPresetType;
212
213typedef enum {
214    TOPT_UNDEFINED = 0,
215    TOPT_SHORT,
216    TOPT_LONG,
217    TOPT_DEFAULT
218} teOptType;
219
220typedef struct {
221    tOptDesc *          pOD;
222    char const *        pzOptArg;
223    opt_state_mask_t    flags;
224    teOptType           optType;
225} tOptState;
226#define OPTSTATE_INITIALIZER(st) \
227    { NULL, NULL, OPTST_ ## st, TOPT_UNDEFINED }
228
229#define TEXTTO_TABLE \
230        _TT_(LONGUSAGE) \
231        _TT_(USAGE) \
232        _TT_(VERSION)
233#define _TT_(n) \
234        TT_ ## n ,
235
236typedef enum { TEXTTO_TABLE COUNT_TT } teTextTo;
237
238#undef _TT_
239
240/**
241 * option argument types.  Used to create usage information for
242 * particular options.
243 */
244typedef struct {
245    char const * pzStr;
246    char const * pzReq;
247    char const * pzNum;
248    char const * pzFile;
249    char const * pzKey;
250    char const * pzKeyL;
251    char const * pzBool;
252    char const * pzNest;
253    char const * pzOpt;
254    char const * pzNo;
255    char const * pzBrk;
256    char const * pzNoF;
257    char const * pzSpc;
258    char const * pzOptFmt;
259    char const * pzTime;
260} arg_types_t;
261
262#define AGALOC(_c, _w)        ao_malloc((size_t)_c)
263#define AGREALOC(_p, _c, _w)  ao_realloc(VOIDP(_p), (size_t)_c)
264#define AGFREE(_p)            free(VOIDP(_p))
265#define AGDUPSTR(_p, _s, _w)  (_p = ao_strdup(_s))
266
267static void *
268ao_malloc(size_t sz);
269
270static void *
271ao_realloc(void *p, size_t sz);
272
273#define ao_free(_p) free(VOIDP(_p))
274
275static char *
276ao_strdup(char const * str);
277
278/**
279 *  DO option handling?
280 *
281 *  Options are examined at two times:  at immediate handling time and at
282 *  normal handling time.  If an option is disabled, the timing may be
283 *  different from the handling of the undisabled option.  The OPTST_DIABLED
284 *  bit indicates the state of the currently discovered option.
285 *  So, here's how it works:
286 *
287 *  A) handling at "immediate" time, either 1 or 2:
288 *
289 *  1.  OPTST_DISABLED is not set:
290 *      IMM           must be set
291 *      DISABLE_IMM   don't care
292 *      TWICE         don't care
293 *      DISABLE_TWICE don't care
294 *      0 -and-  1 x x x
295 *
296 *  2.  OPTST_DISABLED is set:
297 *      IMM           don't care
298 *      DISABLE_IMM   must be set
299 *      TWICE         don't care
300 *      DISABLE_TWICE don't care
301 *      1 -and-  x 1 x x
302 */
303#define DO_IMMEDIATELY(_flg) \
304    (  (((_flg) & (OPTST_DISABLED|OPTST_IMM)) == OPTST_IMM) \
305    || (   ((_flg) & (OPTST_DISABLED|OPTST_DISABLE_IMM))    \
306        == (OPTST_DISABLED|OPTST_DISABLE_IMM)  ))
307
308/**
309 *  B) handling at "regular" time because it was not immediate
310 *
311 *  1.  OPTST_DISABLED is not set:
312 *      IMM           must *NOT* be set
313 *      DISABLE_IMM   don't care
314 *      TWICE         don't care
315 *      DISABLE_TWICE don't care
316 *      0 -and-  0 x x x
317 *
318 *  2.  OPTST_DISABLED is set:
319 *      IMM           don't care
320 *      DISABLE_IMM   don't care
321 *      TWICE         must be set
322 *      DISABLE_TWICE don't care
323 *      1 -and-  x x 1 x
324 */
325#define DO_NORMALLY(_flg) ( \
326       (((_flg) & (OPTST_DISABLED|OPTST_IMM))            == 0)  \
327    || (((_flg) & (OPTST_DISABLED|OPTST_DISABLE_IMM))    ==     \
328                  OPTST_DISABLED)  )
329
330/**
331 *  C)  handling at "regular" time because it is to be handled twice.
332 *      The immediate bit was already tested and found to be set:
333 *
334 *  3.  OPTST_DISABLED is not set:
335 *      IMM           is set (but don't care)
336 *      DISABLE_IMM   don't care
337 *      TWICE         must be set
338 *      DISABLE_TWICE don't care
339 *      0 -and-  ? x 1 x
340 *
341 *  4.  OPTST_DISABLED is set:
342 *      IMM           don't care
343 *      DISABLE_IMM   is set (but don't care)
344 *      TWICE         don't care
345 *      DISABLE_TWICE must be set
346 *      1 -and-  x ? x 1
347 */
348#define DO_SECOND_TIME(_flg) ( \
349       (((_flg) & (OPTST_DISABLED|OPTST_TWICE))          ==     \
350                  OPTST_TWICE)                                  \
351    || (((_flg) & (OPTST_DISABLED|OPTST_DISABLE_TWICE))  ==     \
352                  (OPTST_DISABLED|OPTST_DISABLE_TWICE)  ))
353
354/*
355 *  text_mmap structure.  Only active on platforms with mmap(2).
356 */
357#ifdef HAVE_SYS_MMAN_H
358#  include <sys/mman.h>
359#else
360#  ifndef  PROT_READ
361#   define PROT_READ            0x01
362#  endif
363#  ifndef  PROT_WRITE
364#   define PROT_WRITE           0x02
365#  endif
366#  ifndef  MAP_SHARED
367#   define MAP_SHARED           0x01
368#  endif
369#  ifndef  MAP_PRIVATE
370#   define MAP_PRIVATE          0x02
371#  endif
372#endif
373
374#ifndef MAP_FAILED
375#  define  MAP_FAILED           VOIDP(-1)
376#endif
377
378#ifndef  _SC_PAGESIZE
379# ifdef  _SC_PAGE_SIZE
380#  define _SC_PAGESIZE          _SC_PAGE_SIZE
381# endif
382#endif
383
384#ifndef HAVE_STRCHR
385extern char * strchr(char const * s, int c);
386extern char * strrchr(char const * s, int c);
387#endif
388
389/**
390 * INQUERY_CALL() tests whether the option handling function has been
391 * called by an inquery (help text needed, or option being reset),
392 * or called by a set-the-option operation.
393 */
394#define INQUERY_CALL(_o, _d) (                  \
395    ((_o) <= OPTPROC_EMIT_LIMIT)                \
396    || ((_d) == NULL)                           \
397    || (((_d)->fOptState & OPTST_RESET) != 0) )
398
399/**
400 *  Define and initialize all the user visible strings.
401 *  We do not do translations.  If translations are to be done, then
402 *  the client will provide a callback for that purpose.
403 */
404#undef DO_TRANSLATIONS
405#include "autoopts/usage-txt.h"
406
407/**
408 *  File pointer for usage output
409 */
410FILE * option_usage_fp;
411/**
412 *  If provided in the option structure
413 */
414static char const * program_pkgdatadir;
415/**
416 * privately exported functions
417 */
418extern tOptProc optionPrintVersion, optionPagedUsage, optionLoadOpt;
419
420#ifdef AUTOOPTS_INTERNAL
421
422#ifndef PKGDATADIR
423#  define PKGDATADIR ""
424#endif
425#define APOSTROPHE '\''
426
427#define OPTPROC_L_N_S  (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)
428#if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H)
429# include <libintl.h>
430#endif
431
432typedef struct {
433    size_t          fnm_len;
434    uint32_t        fnm_mask;
435    char const *    fnm_name;
436} ao_flag_names_t;
437
438/**
439 * Automated Options Usage Flags.
440 * NB: no entry may be a prefix of another entry
441 */
442#define AOFLAG_TABLE                            \
443    _aof_(gnu,             OPTPROC_GNUUSAGE )   \
444    _aof_(autoopts,        ~OPTPROC_GNUUSAGE)   \
445    _aof_(no_misuse_usage, OPTPROC_MISUSE   )   \
446    _aof_(misuse_usage,    ~OPTPROC_MISUSE  )   \
447    _aof_(compute,         OPTPROC_COMPUTE  )
448
449#define _aof_(_n, _f)   AOUF_ ## _n ## _ID,
450typedef enum { AOFLAG_TABLE AOUF_COUNT } ao_flag_id_t;
451#undef  _aof_
452
453#define _aof_(_n, _f)   AOUF_ ## _n = (1 << AOUF_ ## _n ## _ID),
454typedef enum { AOFLAG_TABLE } ao_flags_t;
455#undef  _aof_
456
457static char const   zNil[] = "";
458static arg_types_t  argTypes             = { NULL };
459static char         line_fmt_buf[32];
460static bool         displayEnum          = false;
461static char const   pkgdatadir_default[] = PKGDATADIR;
462static char const * program_pkgdatadir   = pkgdatadir_default;
463static tOptionLoadMode option_load_mode  = OPTION_LOAD_UNCOOKED;
464static tePagerState pagerState           = PAGER_STATE_INITIAL;
465
466static lo_noreturn void option_exits(int exit_code);
467static lo_noreturn void fserr_exit(char const * prog, char const * op,
468                                   char const * fname);
469static             void fserr_warn(char const * prog, char const * op,
470                                   char const * fname);
471static lo_noreturn void ao_bug(char const * msg);
472
473       FILE *       option_usage_fp      = NULL;
474
475static char const * pz_enum_err_fmt;
476
477tOptions * optionParseShellOptions = NULL;
478
479static char const * shell_prog = NULL;
480static char * script_leader    = NULL;
481static char * script_trailer   = NULL;
482static char * script_text      = NULL;
483static bool   print_exit       = false;
484#endif /* AUTOOPTS_INTERNAL */
485
486#endif /* AUTOGEN_AUTOOPTS_H */
487/**
488 * @}
489 * Local Variables:
490 * mode: C
491 * c-file-style: "stroustrup"
492 * indent-tabs-mode: nil
493 * End:
494 * end of autoopts/autoopts.h */
495