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