1 /* opt.h -- general-purpose command line option parser
2    Copyright (C) 2016-2021 Free Software Foundation, Inc.
3 
4    GNU Mailutils is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 3, or (at
7    your option) any later version.
8 
9    GNU Mailutils is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #ifndef _MAILUTILS_OPT_H
19 #define _MAILUTILS_OPT_H
20 #include <stdio.h>
21 #include <mailutils/types.h>
22 #include <mailutils/list.h>
23 #include <mailutils/util.h>
24 #include <mailutils/cctype.h>
25 
26 extern char *mu_program_name;
27 extern char *mu_full_program_name;
28 
29 void mu_set_program_name (char const *arg);
30 
31 #define MU_OPTION_DEFAULT        0
32 #define MU_OPTION_ARG_OPTIONAL   0x01
33 #define MU_OPTION_HIDDEN         0x02
34 #define MU_OPTION_ALIAS          0x04
35 #define MU_OPTION_IMMEDIATE      0x08
36 
37 struct mu_parseopt;
38 
39 struct mu_option
40 {
41   char *opt_long;         /* Long option name */
42   int opt_short;          /* Short option character */
43   char *opt_arg;          /* Argument name */
44   int opt_flags;          /* Flags (see above) */
45   char *opt_doc;          /* Human-readable documentation */
46   mu_c_type_t opt_type;   /* Option type */
47   void *opt_ptr;          /* Data pointer */
48   void (*opt_set) (struct mu_parseopt *, struct mu_option *, char const *);
49                           /* Function to set the option */
50   char const *opt_default;/* Default value */
51 };
52 
53 #define MU_OPTION_GROUP(text) { NULL, 0, NULL, 0, text }
54 #define MU_OPTION_END { NULL, 0, NULL, 0, NULL }
55 
56 #define MU_OPTION_IS_END(opt)					\
57   (!(opt)->opt_long && !(opt)->opt_short && !(opt)->opt_doc)
58 
59 #define MU_OPTION_IS_OPTION(opt) \
60   ((opt)->opt_short || (opt)->opt_long)
61 #define MU_OPTION_IS_GROUP_HEADER(opt)			\
62   (!MU_OPTION_IS_OPTION(opt) && (opt)->opt_doc)
63 #define MU_OPTION_IS_VALID_SHORT_OPTION(opt) \
64   ((opt)->opt_short > 0 && (opt)->opt_short < 127 && \
65    (mu_isalnum ((opt)->opt_short) || ((opt)->opt_short == '?')))
66 #define MU_OPTION_IS_VALID_LONG_OPTION(opt) \
67   ((opt)->opt_long != NULL)
68 
69 typedef struct mu_option_cache *mu_option_cache_ptr_t;
70 
71 struct mu_option_cache
72 {
73   struct mu_option *cache_opt;
74   char const *cache_arg;
75 };
76 
77 #define MU_PARSEOPT_DEFAULT        0
78 /* Don't ignore the first element of ARGV.  By default it is the program
79    name */
80 #define MU_PARSEOPT_ARGV0          0x00000001
81 /* Ignore command line errors. */
82 #define MU_PARSEOPT_IGNORE_ERRORS  0x00000002
83 /* Don't order arguments so that options come first. */
84 #define MU_PARSEOPT_IN_ORDER       0x00000004
85 /* Don't provide standard options: -h, --help, --usage, --version */
86 #define MU_PARSEOPT_NO_STDOPT      0x00000008
87 /* Don't exit on errors */
88 #define MU_PARSEOPT_NO_ERREXIT     0x00000010
89 /* Apply all options immediately */
90 #define MU_PARSEOPT_IMMEDIATE      0x00000020
91 
92 /* Don't sort options */
93 #define MU_PARSEOPT_NO_SORT        0x00001000
94 
95 #define MU_PARSEOPT_PROG_NAME      0x00002000
96 #define MU_PARSEOPT_PROG_DOC       0x00004000
97 #define MU_PARSEOPT_PROG_ARGS      0x00008000
98 #define MU_PARSEOPT_BUG_ADDRESS    0x00010000
99 #define MU_PARSEOPT_PACKAGE_NAME   0x00020000
100 #define MU_PARSEOPT_PACKAGE_URL    0x00040000
101 #define MU_PARSEOPT_EXTRA_INFO     0x00080000
102 #define MU_PARSEOPT_EXIT_ERROR     0x00100000
103 #define MU_PARSEOPT_HELP_HOOK      0x00200000
104 #define MU_PARSEOPT_DATA           0x00400000
105 #define MU_PARSEOPT_VERSION_HOOK   0x00800000
106 #define MU_PARSEOPT_PROG_DOC_HOOK  0x01000000
107 /* Long options start with single dash.  Disables recognition of traditional
108    short options */
109 #define MU_PARSEOPT_SINGLE_DASH    0x02000000
110 /* Negation prefix is set */
111 #define MU_PARSEOPT_NEGATION       0x04000000
112 /* po_special_args is set */
113 #define MU_PARSEOPT_SPECIAL_ARGS   0x08000000
114 
115 /* Reuse mu_parseopt struct initialized previously */
116 #define MU_PARSEOPT_REUSE          0x80000000
117 /* Mask for immutable flag bits */
118 #define MU_PARSEOPT_IMMUTABLE_MASK 0xFFFFF000
119 
120 struct mu_parseopt
121 {
122   /* Input data: */
123   int po_argc;                     /* Number of argiments */
124   char **po_argv;                  /* Array of arguments */
125   size_t po_optc;                  /* Number of elements in optv */
126   struct mu_option **po_optv;      /* Array of ptrs to option structures */
127   int po_flags;
128 
129   char *po_negation;               /* Negation prefix for boolean options */
130   void *po_data;                   /* Call-specific data */
131 
132   int po_exit_error;               /* Exit on error with this code */
133 
134   /* Informational: */
135   char const *po_prog_name;
136   char const *po_prog_doc;
137   char const **po_prog_args;
138   char const *po_special_args;     /* Special option-like arguments */
139   char const *po_bug_address;
140   char const *po_package_name;
141   char const *po_package_url;
142   char const *po_extra_info;
143 
144   void (*po_prog_doc_hook) (struct mu_parseopt *po, mu_stream_t stream);
145   void (*po_help_hook) (struct mu_parseopt *po, mu_stream_t stream);
146   void (*po_version_hook) (struct mu_parseopt *po, mu_stream_t stream);
147 
148   /* Output data */
149   int po_ind;                      /* Index of the next option */
150   int po_opterr;                   /* Index of the element in po_argv that
151 				      caused last error, or -1 if no errors */
152   mu_list_t po_optlist;
153 
154   /* Auxiliary data */
155   char *po_cur;                    /* Points to the next character */
156   int po_chr;                      /* Single-char option */
157 
158   char *po_long_opt_start;         /* Character sequence that starts
159 				      long option */
160 
161   /* The following two keep the position of the first non-optional argument
162      and the number of contiguous non-optional arguments after it.
163      Obviously, the following holds true:
164 
165          arg_start + arg_count == opt_ind
166 
167      If permutation is not allowed (MU_OPTION_PARSE_IN_ORDER flag is set),
168      arg_count is always 0.
169   */
170   int po_arg_start;
171   int po_arg_count;
172 
173   unsigned po_permuted:1;           /* Whether the arguments were permuted */
174 
175   size_t po_longcnt;                /* Number of long options */
176   size_t *po_longidx;               /* Indices of long options in po_optv */
177 };
178 
179 
180 int mu_parseopt (struct mu_parseopt *p,
181 		 int argc, char **argv, struct mu_option **optv,
182 		 int flags);
183 void mu_parseopt_error (struct mu_parseopt *po, char const *fmt, ...);
184 
185 int mu_parseopt_apply (struct mu_parseopt *p);
186 void mu_parseopt_free (struct mu_parseopt *p);
187 
188 int mu_parseopt_help_stream_create (mu_stream_t *retstr,
189 				    struct mu_parseopt *po,
190 				    mu_stream_t outstr);
191 unsigned mu_parseopt_getcolumn (const char *name);
192 
193 void mu_option_describe_options (mu_stream_t str, struct mu_parseopt *p);
194 void mu_program_help (struct mu_parseopt *p, mu_stream_t str);
195 void mu_program_usage (struct mu_parseopt *p, int optsummary, mu_stream_t str);
196 void mu_program_version (struct mu_parseopt *po, mu_stream_t str);
197 
198 void mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt,
199 			  char const *arg);
200 
201 int mu_option_possible_negation (struct mu_parseopt *po, struct mu_option *opt);
202 
203 #endif
204