Commit 87ef8884 87ef8884693eb0cdcdafa2365c86709f33e3a375 by Sergey Poznyakoff

Add generic library for option parsing.

* configure.ac: Build libmailutils/opt
* include/mailutils/Makefile.am: Add opt.h
* include/mailutils/opt.h: New file.
* include/mailutils/util.h (mu_c_type_t): New datatype.
(mu_str_to_c): New proto.
* libmailutils/Makefile.am: Add opt to subdirs.

* libmailutils/opt/Makefile.am: New file.
* libmailutils/opt/help.c: New file.
* libmailutils/opt/opt.c: New file.
* libmailutils/opt/progname.c: New file.

* libmailutils/string/Makefile.am: Add new files.
* libmailutils/string/str_to_c.c: New file.
* libmailutils/string/to_sn.c: New file.
* libmailutils/string/to_un.c: New file.

* libmailutils/tests/.gitignore: Update.
* libmailutils/tests/Makefile.am: Update.
* libmailutils/tests/parseopt.c: New file.
1 parent 8b8f29eb
...@@ -1519,6 +1519,7 @@ AC_CONFIG_FILES([ ...@@ -1519,6 +1519,7 @@ AC_CONFIG_FILES([
1519 libmailutils/mailer/Makefile 1519 libmailutils/mailer/Makefile
1520 libmailutils/mime/Makefile 1520 libmailutils/mime/Makefile
1521 libmailutils/msgset/Makefile 1521 libmailutils/msgset/Makefile
1522 libmailutils/opt/Makefile
1522 libmailutils/property/Makefile 1523 libmailutils/property/Makefile
1523 libmailutils/server/Makefile 1524 libmailutils/server/Makefile
1524 libmailutils/string/Makefile 1525 libmailutils/string/Makefile
......
...@@ -79,6 +79,7 @@ pkginclude_HEADERS = \ ...@@ -79,6 +79,7 @@ pkginclude_HEADERS = \
79 nntp.h\ 79 nntp.h\
80 observer.h\ 80 observer.h\
81 opool.h\ 81 opool.h\
82 opt.h\
82 pam.h\ 83 pam.h\
83 parse822.h\ 84 parse822.h\
84 pop3.h\ 85 pop3.h\
......
1 /* opt.h -- general-purpose command line option parser
2 Copyright (C) 2016 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_progname;
27 extern char *mu_absprogname;
28
29 void mu_set_progname (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 };
51
52 #define MU_OPTION_GROUP(text) { NULL, 0, NULL, 0, text }
53 #define MU_OPTION_END { NULL, 0, NULL, 0, NULL }
54
55 #define MU_OPTION_IS_END(opt) \
56 (!(opt)->opt_long && !(opt)->opt_short && !(opt)->opt_doc)
57
58 #define MU_OPTION_IS_OPTION(opt) \
59 ((opt)->opt_short || (opt)->opt_long)
60 #define MU_OPTION_IS_GROUP_HEADER(opt) \
61 (!MU_OPTION_IS_OPTION(opt) && (opt)->opt_doc)
62 #define MU_OPTION_IS_VALID_SHORT_OPTION(opt) \
63 ((opt)->opt_short > 0 && (opt)->opt_short < 127 && \
64 mu_isalnum ((opt)->opt_short))
65 #define MU_OPTION_IS_VALID_LONG_OPTION(opt) \
66 ((opt)->opt_long != NULL)
67
68 typedef struct mu_option_cache *mu_option_cache_ptr_t;
69
70 struct mu_option_cache
71 {
72 struct mu_option *cache_opt;
73 char *cache_arg;
74 };
75
76 #define MU_PARSEOPT_DEFAULT 0
77 /* Don't ignore the first element of ARGV. By default it is the program
78 name */
79 #define MU_PARSEOPT_ARGV0 0x00000001
80 /* Ignore command line errors. */
81 #define MU_PARSEOPT_IGNORE_ERRORS 0x00000002
82 /* Don't order arguments so that options come first. */
83 #define MU_PARSEOPT_IN_ORDER 0x00000004
84 /* Don't provide standard options: -h, --help, --usage, --version */
85 #define MU_PARSEOPT_NO_STDOPT 0x00000008
86 /* Don't exit on errors */
87 #define MU_PARSEOPT_NO_ERREXIT 0x00000010
88 /* Apply all options immediately */
89 #define MU_PARSEOPT_IMMEDIATE 0x00000020
90
91 /* Don't sort options */
92 #define MU_PARSEOPT_NO_SORT 0x00001000
93
94 #define MU_PARSEOPT_PROG_NAME 0x00002000
95 #define MU_PARSEOPT_PROG_DOC 0x00004000
96 #define MU_PARSEOPT_PROG_ARGS 0x00008000
97 #define MU_PARSEOPT_BUG_ADDRESS 0x00010000
98 #define MU_PARSEOPT_PACKAGE_NAME 0x00020000
99 #define MU_PARSEOPT_PACKAGE_URL 0x00040000
100 #define MU_PARSEOPT_DATA 0x00080000
101 #define MU_PARSEOPT_HELP_HOOK 0x00100000
102
103 /* Reuse mu_parseopt struct initialized previously */
104 #define MU_PARSEOPT_REUSE 0x80000000
105 /* Mask for immutable flag bits */
106 #define MU_PARSEOPT_IMMUTABLE_MASK 0xFFFFF000
107
108
109 struct mu_parseopt
110 {
111 /* Input data: */
112 int po_argc; /* Number of argiments */
113 char **po_argv; /* Array of arguments */
114 size_t po_optc; /* Number of elements in optv */
115 struct mu_option **po_optv; /* Array of ptrs to option structures */
116 int po_flags;
117
118 char *po_data; /* Call-specific data */
119
120 /* Informational: */
121 char const *po_prog_name;
122 char const *po_prog_doc;
123 char const *po_prog_args;
124 char const *po_bug_address;
125 char const *po_package_name;
126 char const *po_package_url;
127
128 void (*po_help_hook) (FILE *stream); /* FIXME: should take mu_Stream_t ?*/
129
130 /* Output data */
131 int po_ind; /* Index of the next option */
132 int po_opterr; /* Index of the element in po_argv that
133 caused last error, or -1 if no errors */
134 mu_list_t po_optlist;
135
136 /* Auxiliary data */
137 char *po_cur; /* Points to the next character */
138 int po_chr; /* Single-char option */
139
140 /* The following two keep the position of the first non-optional argument
141 and the number of contiguous non-optional arguments after it.
142 Obviously, the following holds true:
143
144 arg_start + arg_count == opt_ind
145
146 If permutation is not allowed (MU_OPTION_PARSE_IN_ORDER flag is set),
147 arg_count is always 0.
148 */
149 int po_arg_start;
150 int po_arg_count;
151
152 };
153
154 int mu_parseopt (struct mu_parseopt *p,
155 int argc, char **argv, struct mu_option **optv,
156 int flags);
157
158 int mu_parseopt_apply (struct mu_parseopt *p);
159 void mu_parseopt_free (struct mu_parseopt *p);
160
161 void mu_option_describe_options (struct mu_option **optbuf, size_t optcnt);
162 void mu_program_help (struct mu_parseopt *p);
163 void mu_program_usage (struct mu_parseopt *p);
164
165 void mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt,
166 char const *arg);
167
168 #endif
...@@ -152,6 +152,35 @@ int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt, ...@@ -152,6 +152,35 @@ int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt,
152 char **passptr); 152 char **passptr);
153 153
154 /* ----------------------- */ 154 /* ----------------------- */
155 /* String conversions. */
156 /* ----------------------- */
157
158 enum mu_c_type
159 {
160 mu_c_string,
161 mu_c_short,
162 mu_c_ushort,
163 mu_c_int,
164 mu_c_uint,
165 mu_c_long,
166 mu_c_ulong,
167 mu_c_size,
168 mu_c_off,
169 mu_c_time,
170 mu_c_bool,
171 mu_c_ipv4,
172 mu_c_cidr,
173 mu_c_host,
174 mu_c_incr, /* C int value, incremented each time mu_str_to_c is
175 invoked */
176 };
177
178 typedef enum mu_c_type mu_c_type_t;
179
180 int mu_str_to_c (char const *string, mu_c_type_t type, void *tgt,
181 char **errmsg);
182
183 /* ----------------------- */
155 /* Assorted functions. */ 184 /* Assorted functions. */
156 /* ----------------------- */ 185 /* ----------------------- */
157 int mu_getmaxfd (void); 186 int mu_getmaxfd (void);
...@@ -208,7 +237,6 @@ int mu_file_safety_compose (int *res, const char *name, int defval); ...@@ -208,7 +237,6 @@ int mu_file_safety_compose (int *res, const char *name, int defval);
208 int mu_file_mode_to_safety_criteria (int mode); 237 int mu_file_mode_to_safety_criteria (int mode);
209 int mu_safety_criteria_to_file_mode (int crit); 238 int mu_safety_criteria_to_file_mode (int crit);
210 239
211
212 #ifdef __cplusplus 240 #ifdef __cplusplus
213 } 241 }
214 #endif 242 #endif
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
18 18
19 SUBDIRS = \ 19 SUBDIRS = \
20 auth base address list sockaddr cidr cfg diag\ 20 auth base address list sockaddr cidr cfg diag\
21 filter mailbox mailer mime msgset server string stream stdstream\ 21 filter mailbox mailer mime msgset opt server string stream stdstream\
22 property url imapio datetime . tests 22 property url imapio datetime . tests
23 23
24 lib_LTLIBRARIES = libmailutils.la 24 lib_LTLIBRARIES = libmailutils.la
...@@ -42,6 +42,7 @@ libmailutils_la_LIBADD = \ ...@@ -42,6 +42,7 @@ libmailutils_la_LIBADD = \
42 mailer/libmailer.la\ 42 mailer/libmailer.la\
43 mime/libmime.la\ 43 mime/libmime.la\
44 msgset/libmsgset.la\ 44 msgset/libmsgset.la\
45 opt/libopt.la\
45 property/libproperty.la\ 46 property/libproperty.la\
46 server/libserver.la\ 47 server/libserver.la\
47 string/libstring.la\ 48 string/libstring.la\
......
1 # GNU Mailutils -- a suite of utilities for electronic mail
2 # Copyright (C) 2016 Free Software Foundation, Inc.
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 3 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General
15 # Public License along with this library. If not, see
16 # <http://www.gnu.org/licenses/>.
17
18 noinst_LTLIBRARIES = libopt.la
19
20 libopt_la_SOURCES = \
21 opt.c\
22 help.c\
23 progname.c
24
25 AM_CPPFLAGS = \
26 @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
1 /* help.c -- general-purpose command line option parser
2 Copyright (C) 2016 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 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <mailutils/alloc.h>
23 #include <mailutils/opt.h>
24 #include <mailutils/cctype.h>
25 #include <mailutils/nls.h>
26
27 #define LMARGIN 2
28 #define DESCRCOLUMN 30
29 #define RMARGIN 79
30 #define GROUPCOLUMN 2
31 #define USAGECOLUMN 13
32
33 static void
34 indent (size_t start, size_t col)
35 {
36 for (; start < col; start++)
37 putchar (' ');
38 }
39
40 static void
41 print_option_descr (const char *descr, size_t lmargin, size_t rmargin)
42 {
43 while (*descr)
44 {
45 size_t s = 0;
46 size_t i;
47 size_t width = rmargin - lmargin;
48
49 for (i = 0; ; i++)
50 {
51 if (descr[i] == 0 || descr[i] == ' ' || descr[i] == '\t')
52 {
53 if (i > width)
54 break;
55 s = i;
56 if (descr[i] == 0)
57 break;
58 }
59 }
60 fwrite (descr, 1, s, stdout);
61 fputc ('\n', stdout);
62 descr += s;
63 if (*descr)
64 {
65 indent (0, lmargin);
66 descr++;
67 }
68 }
69 }
70
71
72 static size_t
73 print_option (struct mu_option **optbuf, size_t optcnt, size_t num,
74 int *argsused)
75 {
76 struct mu_option *opt = optbuf[num];
77 size_t next, i;
78 int delim;
79 int w;
80
81 if (MU_OPTION_IS_GROUP_HEADER (opt))
82 {
83 if (num)
84 putchar ('\n');
85 indent (0, GROUPCOLUMN);
86 print_option_descr (gettext (opt->opt_doc), GROUPCOLUMN, RMARGIN);
87 putchar ('\n');
88 return num + 1;
89 }
90
91 /* count aliases */
92 for (next = num + 1;
93 next < optcnt && optbuf[next]->opt_flags & MU_OPTION_ALIAS;
94 next++);
95
96 if (opt->opt_flags & MU_OPTION_HIDDEN)
97 return next;
98
99 w = 0;
100 for (i = num; i < next; i++)
101 {
102 if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]))
103 {
104 if (w == 0)
105 {
106 indent (0, LMARGIN);
107 w = LMARGIN;
108 }
109 else
110 w += printf (", ");
111 w += printf ("-%c", optbuf[i]->opt_short);
112 delim = ' ';
113 }
114 }
115
116 for (i = num; i < next; i++)
117 {
118 if (MU_OPTION_IS_VALID_LONG_OPTION (optbuf[i]))
119 {
120 if (w == 0)
121 {
122 indent (0, LMARGIN);
123 w = LMARGIN;
124 }
125 else
126 w += printf (", ");
127 w += printf ("--%s", optbuf[i]->opt_long);
128 delim = '=';
129 }
130 }
131
132 if (opt->opt_arg)
133 {
134 *argsused = 1;
135 w += printf ("%c%s", delim, gettext (opt->opt_arg));
136 }
137 if (w >= DESCRCOLUMN)
138 {
139 putchar ('\n');
140 w = 0;
141 }
142 indent (w, DESCRCOLUMN);
143 print_option_descr (gettext (opt->opt_doc), DESCRCOLUMN, RMARGIN);
144
145 return next;
146 }
147
148 void
149 mu_option_describe_options (struct mu_option **optbuf, size_t optcnt)
150 {
151 unsigned i;
152 int argsused = 0;
153
154 for (i = 0; i < optcnt; )
155 i = print_option (optbuf, optcnt, i, &argsused);
156 putchar ('\n');
157
158 if (argsused)
159 {
160 print_option_descr (_("Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options."), 0, RMARGIN);
161 putchar ('\n');
162 }
163 }
164
165 void
166 mu_program_help (struct mu_parseopt *po)
167 {
168 printf ("%s", _("Usage:"));
169 if (po->po_prog_name)
170 printf (" %s", po->po_prog_name);
171 printf (" [%s]...", _("OPTION"));
172 if (po->po_prog_args)
173 printf (" %s", gettext (po->po_prog_args));
174 putchar ('\n');
175
176 if (po->po_prog_doc)
177 print_option_descr (gettext (po->po_prog_doc), 0, RMARGIN);
178 putchar ('\n');
179
180 mu_option_describe_options (po->po_optv, po->po_optc);
181
182 if (po->po_help_hook)
183 po->po_help_hook (stdout);
184
185 if (po->po_bug_address)
186 /* TRANSLATORS: The placeholder indicates the bug-reporting address
187 for this package. Please add _another line_ saying
188 "Report translation bugs to <...>\n" with the address for translation
189 bugs (typically your translation team's web or email address). */
190 printf (_("Report bugs to %s.\n"), po->po_bug_address);
191
192 if (po->po_package_name && po->po_package_url)
193 printf (_("%s home page: <%s>\n"),
194 po->po_package_name, po->po_package_url);
195 }
196
197 static struct mu_option **option_tab;
198
199 static int
200 cmpidx_short (const void *a, const void *b)
201 {
202 unsigned const *ai = (unsigned const *)a;
203 unsigned const *bi = (unsigned const *)b;
204
205 return option_tab[*ai]->opt_short - option_tab[*bi]->opt_short;
206 }
207
208 static int
209 cmpidx_long (const void *a, const void *b)
210 {
211 unsigned const *ai = (unsigned const *)a;
212 unsigned const *bi = (unsigned const *)b;
213 struct mu_option const *ap = option_tab[*ai];
214 struct mu_option const *bp = option_tab[*bi];
215 return strcmp (ap->opt_long, bp->opt_long);
216 }
217
218 void
219 mu_program_usage (struct mu_parseopt *po)
220 {
221 unsigned i;
222 unsigned n;
223 char buf[RMARGIN+1];
224 unsigned *idxbuf;
225 unsigned nidx;
226
227 struct mu_option **optbuf = po->po_optv;
228 size_t optcnt = po->po_optc;
229
230 #define FLUSH \
231 do \
232 { \
233 buf[n] = 0; \
234 printf ("%s\n", buf); \
235 n = USAGECOLUMN; \
236 memset (buf, ' ', n); \
237 } \
238 while (0)
239 #define ADDC(c) \
240 do \
241 { \
242 if (n == RMARGIN) FLUSH; \
243 buf[n++] = c; \
244 } \
245 while (0)
246
247 option_tab = optbuf;
248
249 idxbuf = mu_calloc (optcnt, sizeof (idxbuf[0]));
250
251 n = snprintf (buf, sizeof buf, "%s %s ", _("Usage:"), mu_progname);
252
253 /* Print a list of short options without arguments. */
254 for (i = nidx = 0; i < optcnt; i++)
255 if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]) && !optbuf[i]->opt_arg)
256 idxbuf[nidx++] = i;
257
258 if (nidx)
259 {
260 qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short);
261
262 ADDC ('[');
263 ADDC ('-');
264 for (i = 0; i < nidx; i++)
265 {
266 ADDC (optbuf[idxbuf[i]]->opt_short);
267 }
268 ADDC (']');
269 }
270
271 /* Print a list of short options with arguments. */
272 for (i = nidx = 0; i < optcnt; i++)
273 {
274 if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]) && optbuf[i]->opt_arg)
275 idxbuf[nidx++] = i;
276 }
277
278 if (nidx)
279 {
280 qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short);
281
282 for (i = 0; i < nidx; i++)
283 {
284 struct mu_option *opt = optbuf[idxbuf[i]];
285 const char *arg = gettext (opt->opt_arg);
286 size_t len = 5 + strlen (arg) + 1;
287
288 if (n + len > RMARGIN) FLUSH;
289 buf[n++] = ' ';
290 buf[n++] = '[';
291 buf[n++] = '-';
292 buf[n++] = opt->opt_short;
293 buf[n++] = ' ';
294 strcpy (&buf[n], arg);
295 n += strlen (arg);
296 buf[n++] = ']';
297 }
298 }
299
300 /* Print a list of long options */
301 for (i = nidx = 0; i < optcnt; i++)
302 {
303 if (MU_OPTION_IS_VALID_LONG_OPTION (optbuf[i]))
304 idxbuf[nidx++] = i;
305 }
306
307 if (nidx)
308 {
309 qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_long);
310
311 for (i = 0; i < nidx; i++)
312 {
313 struct mu_option *opt = optbuf[idxbuf[i]];
314 const char *arg = opt->opt_arg ? gettext (opt->opt_arg) : NULL;
315 size_t len = 3 + strlen (opt->opt_long)
316 + (arg ? 1 + strlen (arg) : 0);
317 if (n + len > RMARGIN) FLUSH;
318 buf[n++] = ' ';
319 buf[n++] = '[';
320 buf[n++] = '-';
321 buf[n++] = '-';
322 strcpy (&buf[n], opt->opt_long);
323 n += strlen (opt->opt_long);
324 if (opt->opt_arg)
325 {
326 buf[n++] = '=';
327 strcpy (&buf[n], arg);
328 n += strlen (arg);
329 }
330 buf[n++] = ']';
331 }
332 }
333
334 FLUSH;
335 free (idxbuf);
336 }
337
1 /* opt.c -- general-purpose command line option parser
2 Copyright (C) 2016 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 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <mailutils/alloc.h>
24 #include <mailutils/opt.h>
25 #include <mailutils/nls.h>
26 #include <mailutils/errno.h>
27
28 #define EXIT_SUCCESS 0
29 #define EXIT_ERROR 1
30
31 /* Compare pointers to two option structs */
32 static int
33 optcmp (const void *a, const void *b)
34 {
35 struct mu_option const *ap = *(struct mu_option const **)a;
36 struct mu_option const *bp = *(struct mu_option const **)b;
37
38 while (ap->opt_flags & MU_OPTION_ALIAS)
39 ap--;
40 while (bp->opt_flags & MU_OPTION_ALIAS)
41 bp--;
42
43 if (MU_OPTION_IS_VALID_SHORT_OPTION (ap)
44 && MU_OPTION_IS_VALID_SHORT_OPTION (bp))
45 return ap->opt_short - bp->opt_short;
46 if (MU_OPTION_IS_VALID_LONG_OPTION (ap)
47 && MU_OPTION_IS_VALID_LONG_OPTION (bp))
48 return strcmp (ap->opt_long, bp->opt_long);
49 if (MU_OPTION_IS_VALID_LONG_OPTION (ap))
50 return 1;
51 return -1;
52 }
53
54 /* Sort a group of options in OPTBUF, starting at index START (first
55 option slot after a group header (if any). The group spans up to
56 next group header or end of options */
57 static size_t
58 sort_group (struct mu_option **optbuf, size_t start)
59 {
60 size_t i;
61
62 for (i = start; optbuf[i] && !MU_OPTION_IS_GROUP_HEADER (optbuf[i]); i++)
63 ;
64
65 qsort (&optbuf[start], i - start, sizeof (optbuf[0]), optcmp);
66 return i;
67 }
68
69 /* Print help summary and exit. */
70 static void
71 fn_help (struct mu_parseopt *po, struct mu_option *opt, char const *unused)
72 {
73 mu_program_help (po);
74 exit (EXIT_SUCCESS);
75 }
76
77 /* Print usage summary and exit. */
78 static void
79 fn_usage (struct mu_parseopt *po, struct mu_option *opt, char const *unused)
80 {
81 mu_program_usage (po);
82 exit (EXIT_SUCCESS);
83 }
84
85 /* Default options */
86 struct mu_option mu_default_options[] = {
87 MU_OPTION_GROUP(""),
88 { "help", 'h', NULL, MU_OPTION_IMMEDIATE, N_("give this help list"),
89 mu_c_string, NULL, fn_help },
90 { "version", 'V', NULL, MU_OPTION_IMMEDIATE, N_("print program version"),
91 mu_c_string, NULL, /* FIXME: fn_version */ },
92 { "usage", 0, NULL, MU_OPTION_IMMEDIATE, N_("give a short usage message"),
93 mu_c_string, NULL, fn_usage
94 },
95 MU_OPTION_END
96 };
97
98 /* Output error message */
99 static void
100 parse_error (struct mu_parseopt *po, char const *fmt, ...)
101 {
102 va_list ap;
103
104 if (po->po_flags & MU_PARSEOPT_IGNORE_ERRORS)
105 return;
106
107 if (po->po_prog_name)
108 fprintf (stderr, "%s: ", po->po_prog_name);
109 va_start (ap, fmt);
110 vfprintf (stderr, fmt, ap);
111 va_end (ap);
112 fputc ('\n', stderr);
113 }
114
115 static void
116 mu_option_cache_destroy (void *ptr)
117 {
118 struct mu_option_cache *cache = ptr;
119 free (cache->cache_arg);
120 free (cache);
121 }
122
123 static int parseopt_apply (void *item, void *data);
124
125 /* If OPT is an immediate option, evaluate it right away. Otherwise,
126 add option OPT with argument ARG to the cache in PO. */
127 void
128 add_option_cache (struct mu_parseopt *po, struct mu_option *opt,
129 char const *arg)
130 {
131 struct mu_option_cache *cache = mu_alloc (sizeof (*cache));
132 cache->cache_opt = opt;
133 cache->cache_arg = arg ? mu_strdup (arg) : NULL;
134
135 if (opt->opt_flags & MU_OPTION_IMMEDIATE)
136 {
137 parseopt_apply (cache, po);
138 mu_option_cache_destroy (cache);
139 }
140 else
141 {
142 mu_list_append (po->po_optlist, cache);
143 }
144 }
145
146 /* Find first option for which I is an alias */
147 struct mu_option *
148 option_unalias (struct mu_parseopt *po, int i)
149 {
150 while (i > 0 && po->po_optv[i]->opt_flags & MU_OPTION_ALIAS)
151 --i;
152 return po->po_optv[i];
153 }
154
155 /* Find a descriptor of short option CHR */
156 struct mu_option *
157 find_short_option (struct mu_parseopt *po, int chr)
158 {
159 size_t i;
160
161 for (i = 0; i < po->po_optc; i++)
162 {
163 if (MU_OPTION_IS_VALID_SHORT_OPTION (po->po_optv[i])
164 && po->po_optv[i]->opt_short == chr)
165 return option_unalias (po, i);
166 }
167 parse_error (po, _("unrecognized option '-%c'"), chr);
168 return NULL;
169 }
170
171 /* Find a descriptor of long option OPTSTR. If it has argument, return
172 it in *ARGPTR. */
173 struct mu_option *
174 find_long_option (struct mu_parseopt *po, char const *optstr,
175 char **argptr)
176 {
177 size_t i;
178 size_t optlen;
179 size_t ind;
180 int found = 0;
181
182 optlen = strcspn (optstr, "=");
183
184 for (i = 0; i < po->po_optc; i++)
185 {
186 if (MU_OPTION_IS_VALID_LONG_OPTION (po->po_optv[i])
187 && optlen <= strlen (po->po_optv[i]->opt_long)
188 && memcmp (po->po_optv[i]->opt_long, optstr, optlen) == 0)
189 {
190 switch (found)
191 {
192 case 0:
193 ind = i;
194 found++;
195 break;
196
197 case 1:
198 if (po->po_flags & MU_PARSEOPT_IGNORE_ERRORS)
199 return NULL;
200 parse_error (po,
201 _("option '--%*.*s' is ambiguous; possibilities:"),
202 optlen, optlen, optstr);
203 fprintf (stderr, "--%s\n", po->po_optv[ind]->opt_long);
204 found++;
205
206 case 2:
207 fprintf (stderr, "--%s\n", po->po_optv[i]->opt_long);
208 }
209 }
210 }
211
212 switch (found)
213 {
214 case 0:
215 parse_error (po, _("unrecognized option '--%s'"), optstr);
216 break;
217
218 case 1:
219 if (optstr[optlen])
220 ++optlen;
221 *argptr = (char *)(optstr + optlen);
222 return option_unalias (po, ind);
223
224 case 2:
225 break;
226 }
227
228 return NULL;
229 }
230
231
232 /* Consume next option from PO. On success, update PO members as
233 described below and return 0. On end of options, return 1.
234
235 If the consumed option is a short option, then
236
237 po_chr keeps its option character, and
238 po_cur points to the next option character to be processed
239
240 Otherwise, if the consumed option is a long one, then
241
242 po_chr is 0
243 po_cur points to the first character after --
244 */
245 static int
246 next_opt (struct mu_parseopt *po)
247 {
248 if (!*po->po_cur)
249 {
250 if (!(po->po_flags & MU_PARSEOPT_IN_ORDER) && po->po_arg_count)
251 {
252 /* Array to save arguments in */
253 char *save[2];
254 /* Number of arguments processed (at most two) */
255 int n = po->po_ind - (po->po_arg_start + po->po_arg_count);
256
257 if (n > 2)
258 abort ();
259
260 /* Store the processed elements away */
261 save[0] = po->po_argv[po->po_arg_start + po->po_arg_count];
262 if (n == 2)
263 save[1] = po->po_argv[po->po_arg_start + po->po_arg_count + 1];
264
265 /* Shift the array */
266 memmove (po->po_argv + po->po_arg_start + n,
267 po->po_argv + po->po_arg_start,
268 po->po_arg_count * sizeof (po->po_argv[0]));
269
270 /* Place stored elements in the vacating slots */
271 po->po_argv[po->po_arg_start] = save[0];
272 if (n == 2)
273 po->po_argv[po->po_arg_start + 1] = save[1];
274
275 /* Fix up start index */
276 po->po_arg_start += n;
277 }
278
279 if (po->po_ind == po->po_argc)
280 return 1;
281
282 while (1)
283 {
284 po->po_cur = po->po_argv[po->po_ind++];
285 if (!po->po_cur)
286 return 1;
287 if (po->po_cur[0] == '-' && po->po_cur[1])
288 break;
289 if (!(po->po_flags & MU_PARSEOPT_IN_ORDER))
290 {
291 po->po_arg_count++;
292 continue;
293 }
294 else
295 return 1;
296 }
297
298 if (*++po->po_cur == '-')
299 {
300 if (*++po->po_cur == 0)
301 /* End of options */
302 return 1;
303
304 /* It's a long option */
305 po->po_chr = 0;
306 return 0;
307 }
308 }
309
310 po->po_chr = *po->po_cur++;
311
312 return 0;
313 }
314
315 /* Parse options */
316 static int
317 parse (struct mu_parseopt *po)
318 {
319 int rc;
320
321 rc = mu_list_create (&po->po_optlist);
322 if (rc)
323 return rc;
324 mu_list_set_destroy_item (po->po_optlist, mu_option_cache_destroy);
325
326 po->po_ind = 0;
327 if (!(po->po_flags & MU_PARSEOPT_ARGV0))
328 {
329 po->po_ind++;
330 if (!(po->po_flags & MU_PARSEOPT_PROG_NAME))
331 {
332 char *p = strrchr (po->po_argv[0], '/');
333 if (p)
334 po->po_prog_name = p + 1;
335 else
336 po->po_prog_name = (char*) po->po_argv[0];
337 }
338 }
339 else if (!(po->po_flags & MU_PARSEOPT_PROG_NAME))
340 po->po_prog_name = NULL;
341
342 po->po_arg_start = po->po_ind;
343 po->po_arg_count = 0;
344
345 po->po_cur = "";
346
347 po->po_opterr = -1;
348
349 while (next_opt (po) == 0)
350 {
351 struct mu_option *opt;
352 char *long_opt;
353
354 if (po->po_chr)
355 {
356 opt = find_short_option (po, po->po_chr);
357 long_opt = NULL;
358 }
359 else
360 {
361 long_opt = po->po_cur;
362 opt = find_long_option (po, long_opt, &po->po_cur);
363 }
364
365 if (opt)
366 {
367 char *arg = NULL;
368
369 if (opt->opt_arg)
370 {
371 if (po->po_cur[0])
372 {
373 arg = po->po_cur;
374 po->po_cur = "";
375 }
376 else if (opt->opt_flags & MU_OPTION_ARG_OPTIONAL)
377 /* ignore it */;
378 else if (po->po_ind < po->po_argc)
379 arg = po->po_argv[po->po_ind++];
380 else
381 {
382 if (long_opt)
383 parse_error (po,
384 _("option '--%s' requires an argument"),
385 long_opt);
386 else
387 parse_error (po,
388 _("option '-%c' requires an argument"),
389 po->po_chr);
390 po->po_opterr = po->po_ind;
391 if (po->po_flags & MU_PARSEOPT_NO_ERREXIT)
392 {
393 if (!(po->po_flags & MU_PARSEOPT_IN_ORDER))
394 po->po_arg_count++;
395 continue;
396 }
397 exit (EXIT_ERROR);
398 }
399 }
400 else
401 {
402 if (long_opt
403 && po->po_cur[0]
404 && !(po->po_flags & MU_OPTION_ARG_OPTIONAL))
405 {
406 parse_error (po,
407 _("option '--%s' doesn't allow an argument"),
408 long_opt);
409 po->po_opterr = po->po_ind;
410 if (po->po_flags & MU_PARSEOPT_NO_ERREXIT)
411 {
412 if (!(po->po_flags & MU_PARSEOPT_IN_ORDER))
413 po->po_arg_count++;
414 continue;
415 }
416 exit (EXIT_ERROR);
417 }
418 arg = NULL;
419 }
420
421 add_option_cache (po, opt, arg);
422 }
423 else
424 {
425 po->po_opterr = po->po_ind;
426 if (po->po_flags & MU_PARSEOPT_NO_ERREXIT)
427 {
428 if (!(po->po_flags & MU_PARSEOPT_IN_ORDER))
429 po->po_arg_count++;
430 continue;
431 }
432 exit (EXIT_ERROR);
433 }
434 }
435
436 if (po->po_arg_count)
437 po->po_ind = po->po_arg_start;
438 return 0;
439 }
440
441 /* Initialize structure mu_parseopt with given options and flags. */
442 static int
443 parseopt_init (struct mu_parseopt *po, struct mu_option **options,
444 int flags)
445 {
446 struct mu_option *opt;
447 size_t i, j;
448
449 memset (po, 0, sizeof *po);
450 po->po_argc = 0;
451 po->po_argv = NULL;
452 po->po_optc = 0;
453 po->po_flags = flags;
454
455 /* Fix up flags */
456 if (flags & MU_PARSEOPT_IGNORE_ERRORS)
457 flags |= MU_PARSEOPT_NO_ERREXIT;
458
459 if (!(flags & MU_PARSEOPT_PROG_DOC))
460 po->po_prog_doc = NULL;
461 if (!(flags & MU_PARSEOPT_PROG_ARGS))
462 po->po_prog_args = NULL;
463 if (!(flags & MU_PARSEOPT_BUG_ADDRESS))
464 po->po_bug_address = NULL;
465 if (!(flags & MU_PARSEOPT_PACKAGE_NAME))
466 po->po_package_name = NULL;
467 if (!(flags & MU_PARSEOPT_PACKAGE_URL))
468 po->po_package_url = NULL;
469 if (!(flags & MU_PARSEOPT_PACKAGE_URL))
470 po->po_data = NULL;
471 if (!(flags & MU_PARSEOPT_HELP_HOOK))
472 po->po_help_hook = NULL;
473
474 /* Count the options */
475 po->po_optc = 0;
476 for (i = 0; options[i]; i++)
477 for (opt = options[i]; !MU_OPTION_IS_END (opt); opt++)
478 ++po->po_optc;
479
480 if (!(flags & MU_PARSEOPT_NO_STDOPT))
481 for (i = 0; !MU_OPTION_IS_END (&mu_default_options[i]); i++)
482 ++po->po_optc;
483
484 /* Allocate the working buffer of option pointers */
485 po->po_optv = mu_calloc (po->po_optc + 1, sizeof (*po->po_optv));
486 if (!po->po_optv)
487 return -1;
488
489 /* Fill in the array */
490 j = 0;
491 for (i = 0; options[i]; i++)
492 for (opt = options[i]; !MU_OPTION_IS_END (opt); opt++, j++)
493 {
494 if (!opt->opt_set)
495 opt->opt_set = mu_option_set_value;
496 po->po_optv[j] = opt;
497 }
498
499 if (!(flags & MU_PARSEOPT_NO_STDOPT))
500 for (i = 0; !MU_OPTION_IS_END (&mu_default_options[i]); i++, j++)
501 po->po_optv[j] = &mu_default_options[i];
502
503 po->po_optv[j] = NULL;
504
505 /* Ensure sane start of options. This is necessary, in particular,
506 because optcmp backs up until it finds an element with cleared
507 MU_OPTION_ALIAS bit. */
508 po->po_optv[0]->opt_flags &= MU_OPTION_ALIAS;
509 if (!(flags & MU_PARSEOPT_NO_SORT))
510 {
511 /* Sort the options */
512 size_t start;
513
514 for (start = 0; start < po->po_optc; )
515 {
516 if (MU_OPTION_IS_GROUP_HEADER (po->po_optv[start]))
517 start = sort_group (po->po_optv, start + 1);
518 else
519 start = sort_group (po->po_optv, start);
520 }
521 }
522 return 0;
523 }
524
525 /* Parse command line from ARGC/ARGV. Valid options are given in
526 OPTIONS. FLAGS control the parsing. */
527 int
528 mu_parseopt (struct mu_parseopt *po,
529 int argc, char **argv, struct mu_option **options,
530 int flags)
531 {
532 int rc;
533
534 if (flags & MU_PARSEOPT_REUSE)
535 {
536 mu_list_clear (po->po_optlist);
537 po->po_flags = (po->po_flags & MU_PARSEOPT_IMMUTABLE_MASK)
538 | (flags & ~MU_PARSEOPT_IMMUTABLE_MASK);
539 }
540 else
541 {
542 rc = parseopt_init (po, options, flags);
543 if (rc)
544 return rc;
545 }
546 po->po_argc = argc;
547 po->po_argv = argv;
548
549 rc = parse (po);
550
551 if (rc == 0)
552 {
553 if (po->po_opterr >= 0)
554 rc = -1;
555 else
556 {
557 if (po->po_flags & MU_PARSEOPT_IMMEDIATE)
558 rc = mu_parseopt_apply (po);
559 }
560 }
561
562 return rc;
563 }
564
565 void
566 mu_parseopt_free (struct mu_parseopt *popt)
567 {
568 free (popt->po_optv);
569 mu_list_destroy (&popt->po_optlist);
570 }
571
572 static int
573 parseopt_apply (void *item, void *data)
574 {
575 struct mu_option_cache *cp = item;
576 struct mu_parseopt *popt = data;
577 cp->cache_opt->opt_set (popt, cp->cache_opt, cp->cache_arg);
578 return 0;
579 }
580
581 int
582 mu_parseopt_apply (struct mu_parseopt *popt)
583 {
584 return mu_list_foreach (popt->po_optlist, parseopt_apply, popt);
585 }
586
587 void
588 mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt,
589 char const *arg)
590 {
591 if (opt->opt_ptr)
592 {
593 char *errmsg;
594 int rc;
595
596 if (arg == NULL)
597 {
598 if (opt->opt_arg == NULL)
599 arg = "1";
600 else
601 {
602 *(void**)opt->opt_ptr = NULL;
603 return;
604 }
605 }
606 rc = mu_str_to_c (arg, opt->opt_type, opt->opt_ptr, &errmsg);
607 if (rc)
608 {
609 char const *errtext;
610 if (errmsg)
611 errtext = errmsg;
612 else
613 errtext = mu_strerror (rc);
614
615 if (opt->opt_long)
616 parse_error (po, "--%s: %s", opt->opt_long, errtext);
617 else
618 parse_error (po, "-%c: %s", opt->opt_short, errtext);
619 free (errmsg);
620
621 if (!(po->po_flags & MU_PARSEOPT_NO_ERREXIT))
622 exit (EXIT_ERROR);
623 }
624 }
625 }
1 /* help.c -- general-purpose command line option parser
2 Copyright (C) 2016 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 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <mailutils/alloc.h>
23 #include <mailutils/opt.h>
24
25 char *mu_progname;
26 char *mu_absprogname;
27
28 void
29 mu_set_progname (char const *arg)
30 {
31 char *p;
32
33 free (mu_absprogname);
34 mu_absprogname = mu_strdup (arg);
35
36 p = strrchr (arg, '/');
37 if (p)
38 ++p;
39 else
40 p = (char*) arg;
41 free (mu_progname);
42 mu_progname = mu_strdup (p);
43 }
...@@ -25,6 +25,7 @@ libstring_la_SOURCES = \ ...@@ -25,6 +25,7 @@ libstring_la_SOURCES = \
25 cstrupper.c\ 25 cstrupper.c\
26 hexstr.c\ 26 hexstr.c\
27 stpcpy.c\ 27 stpcpy.c\
28 str_to_c.c\
28 strltrim.c\ 29 strltrim.c\
29 strskip.c\ 30 strskip.c\
30 stripws.c\ 31 stripws.c\
...@@ -40,4 +41,6 @@ libstring_la_SOURCES = \ ...@@ -40,4 +41,6 @@ libstring_la_SOURCES = \
40 wordsplit.c\ 41 wordsplit.c\
41 xdecode.c 42 xdecode.c
42 43
43 AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils 44 EXTRA_DIST=to_sn.c to_un.c
45
46 AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils -I${srcdir}
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2016 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stdlib.h>
23 #include <inttypes.h>
24 #include <limits.h>
25 #include <string.h>
26 #include <mailutils/cidr.h>
27 #include <mailutils/error.h>
28 #include <mailutils/errno.h>
29 #include <mailutils/util.h>
30 #include <mailutils/alloc.h>
31 #include <mailutils/cctype.h>
32 #include <mailutils/io.h>
33 #include <mailutils/nls.h>
34
35 typedef int (*str_to_c_t) (void *tgt, char const *string, char **errmsg);
36
37 static int
38 to_string (void *tgt, char const *string, char **errmsg)
39 {
40 char **cptr = tgt;
41 if (string)
42 {
43 *cptr = mu_strdup (string);
44 if (!*cptr)
45 return errno;
46 }
47 else
48 *cptr = NULL;
49 return 0;
50 }
51
52 #define STR_TO_FUN to_short
53 #define STR_TO_TYPE signed short
54 #define STR_TO_MIN SHRT_MIN
55 #define STR_TO_MAX SHRT_MAX
56 #include "to_sn.c"
57
58 #define STR_TO_FUN to_ushort
59 #define STR_TO_TYPE unsigned short
60 #define STR_TO_MAX USHRT_MAX
61 #include "to_un.c"
62
63 #define STR_TO_FUN to_int
64 #define STR_TO_TYPE signed int
65 #define STR_TO_MIN INT_MIN
66 #define STR_TO_MAX INT_MAX
67 #include "to_sn.c"
68
69 #define STR_TO_FUN to_uint
70 #define STR_TO_TYPE unsigned int
71 #define STR_TO_MAX UINT_MAX
72 #include "to_un.c"
73
74 #define STR_TO_FUN to_long
75 #define STR_TO_TYPE signed long
76 #define STR_TO_MIN LONG_MIN
77 #define STR_TO_MAX LONG_MAX
78 #include "to_sn.c"
79
80 #define STR_TO_FUN to_ulong
81 #define STR_TO_TYPE unsigned long
82 #define STR_TO_MAX ULONG_MAX
83 #include "to_un.c"
84
85 #define STR_TO_FUN to_size_t
86 #define STR_TO_TYPE size_t
87 #define STR_TO_MAX ((size_t)-1)
88 #include "to_un.c"
89
90 static int
91 time_multiplier (const char *str, unsigned *m, unsigned *plen)
92 {
93 static struct timetab
94 {
95 char *name;
96 unsigned mul;
97 } tab[] = {
98 { "seconds", 1 },
99 { "minutes", 60 },
100 { "hours", 60*60 },
101 { "days", 24*60*60 },
102 { "weeks", 7*24*60*60 },
103 { "months", 31*7*24*60*60 },
104 { NULL }
105 };
106 struct timetab *p;
107 int slen;
108
109 for (slen = 0; str[slen]; slen++)
110 if (mu_isspace (str[slen]))
111 break;
112
113 for (p = tab; p->name; p++)
114 {
115 if (p->name[0] == mu_tolower (str[0]))
116 {
117 int nlen = strlen (p->name);
118
119 if (nlen > slen)
120 nlen = slen;
121
122 if (strncasecmp (p->name, str, nlen) == 0) {
123 *m = p->mul;
124 if (plen)
125 *plen = nlen;
126 return 0;
127 }
128 }
129 }
130 return 1;
131 }
132
133 static int
134 to_time_t (void *tgt, char const *string, char **errmsg)
135 {
136 time_t *ptr = tgt;
137 int rc = 0;
138 time_t interval = 0;
139
140 while (*string)
141 {
142 char *p;
143 unsigned long n;
144 unsigned mul, len;
145
146 while (*string && mu_isspace (*string))
147 string++;
148
149 if (!mu_isdigit (*string) && time_multiplier (string, &mul, &len) == 0)
150 {
151 n = 1;
152 string += len;
153 }
154 else
155 {
156 n = strtoul (string, &p, 10);
157 if (*p && !mu_isspace (*p))
158 {
159 string = p;
160 rc = 1;
161 break;
162 }
163
164 while (*p && mu_isspace (*p))
165 p++;
166
167 string = p;
168 if (*string)
169 {
170 if ((rc = time_multiplier (string, &mul, &len)))
171 break;
172 string += len;
173 }
174 else
175 mul = 1;
176 }
177 interval += n * mul;
178 }
179
180 if (rc)
181 {
182 mu_asprintf (errmsg, _("invalid time specification near %s"), string);
183 return EINVAL;
184 }
185
186 *ptr = interval;
187 return 0;
188 }
189
190 static int
191 to_bool (void *tgt, char const *string, char **errmsg)
192 {
193 int *ptr = tgt;
194
195 if (strcmp (string, "yes") == 0
196 || strcmp (string, "on") == 0
197 || strcmp (string, "t") == 0
198 || strcmp (string, "true") == 0
199 || strcmp (string, "1") == 0)
200 *ptr = 1;
201 else if (strcmp (string, "no") == 0
202 || strcmp (string, "off") == 0
203 || strcmp (string, "nil") == 0
204 || strcmp (string, "false") == 0
205 || strcmp (string, "0") == 0)
206 *ptr = 0;
207 else
208 return EINVAL;
209
210 return 0;
211 }
212
213 #if 0
214 static int
215 to_ipv4 (void *tgt, char const *string, char **errmsg)
216 {
217 struct in_addr *ptr = tgt;
218 struct in_addr addr;
219
220 if (inet_aton (string, &addr) == 0)
221 {
222 mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, _("not an IPv4"));
223 mu_cfg_error_count++;
224 return 1;
225 }
226 addr.s_addr = ntohl (addr.s_addr);
227
228 *ptr = addr;
229 return 0;
230 }
231 #endif
232
233 static int
234 to_cidr (void *tgt, char const *string, char **errmsg)
235 {
236 struct mu_cidr *ptr = tgt;
237 return mu_cidr_from_string (ptr, string);
238 }
239
240 static int
241 to_incr (void *tgt, char const *string, char **errmsg)
242 {
243 ++*(int*)tgt;
244 return 0;
245 }
246
247 static str_to_c_t str_to_c[] = {
248 [mu_c_string] = to_string,
249 [mu_c_short] = to_short,
250 [mu_c_ushort] = to_ushort,
251 [mu_c_int] = to_int,
252 [mu_c_uint] = to_uint,
253 [mu_c_long] = to_long,
254 [mu_c_ulong] = to_ulong,
255 [mu_c_size] = to_size_t,
256 /* FIXME [mu_c_off] = { to_off, generic_dealloc }, */
257 [mu_c_time] = to_time_t,
258 [mu_c_bool] = to_bool,
259 /* FIXME [mu_c_ipv4] = to_ipv4, */
260 [mu_c_cidr] = to_cidr,
261 /* FIXME [mu_c_host] = { to_host, generic_dealloc } */
262 [mu_c_incr] = to_incr
263 };
264
265 int
266 mu_str_to_c (char const *string, enum mu_c_type type, void *tgt, char **errmsg)
267 {
268 *errmsg = NULL;
269 if ((size_t)type >= sizeof (str_to_c) / sizeof (str_to_c[0]))
270 return EINVAL;
271 if (!str_to_c[type])
272 return ENOSYS;
273 return str_to_c[type] (tgt, string, errmsg);
274 }
1 #ifndef STR_TO_FUN
2 # error "STR_TO_FUN not defined"
3 #endif
4 #ifndef STR_TO_TYPE
5 # error "STR_TO_TYPE not defined"
6 #endif
7 #ifndef STR_TO_MIN
8 # error "STR_TO_MIN not defined"
9 #endif
10 #ifndef STR_TO_MAX
11 # error "STR_TO_MAX not defined"
12 #endif
13
14 static int
15 STR_TO_FUN (void *tgt, char const *string, char **errmsg)
16 {
17 STR_TO_TYPE *ptr = tgt;
18 intmax_t v;
19 char *p;
20
21 errno = 0;
22 v = strtoimax (string, &p, 10);
23 if (errno)
24 return errno;
25 if (*p)
26 return EINVAL;
27 if (STR_TO_MIN <= v && v <= STR_TO_MAX)
28 {
29 *ptr = (STR_TO_TYPE) v;
30 return 0;
31 }
32 return ERANGE;
33 }
34 #undef STR_TO_FUN
35 #undef STR_TO_TYPE
36 #undef STR_TO_MIN
37 #undef STR_TO_MAX
1 #ifndef STR_TO_FUN
2 # error "STR_TO_FUN not defined"
3 #endif
4 #ifndef STR_TO_TYPE
5 # error "STR_TO_TYPE not defined"
6 #endif
7 #ifndef STR_TO_MAX
8 # error "STR_TO_MAX not defined"
9 #endif
10
11 static int
12 STR_TO_FUN (void *tgt, char const *string, char **errmsg)
13 {
14 STR_TO_TYPE *ptr = tgt;
15 uintmax_t v;
16 char *p;
17
18 errno = 0;
19 v = strtoumax (string, &p, 10);
20 if (errno)
21 return errno;
22 if (*p)
23 return EINVAL;
24 if (v <= STR_TO_MAX)
25 {
26 *ptr = (STR_TO_TYPE) v;
27 return 0;
28 }
29 return ERANGE;
30 }
31
32 #undef STR_TO_FUN
33 #undef STR_TO_TYPE
34 #undef STR_TO_MAX
...@@ -20,6 +20,7 @@ mailcap ...@@ -20,6 +20,7 @@ mailcap
20 mimehdr 20 mimehdr
21 modtofsaf 21 modtofsaf
22 msgset 22 msgset
23 parseopt
23 prop 24 prop
24 scantime 25 scantime
25 strftime 26 strftime
......
...@@ -56,6 +56,7 @@ noinst_PROGRAMS = \ ...@@ -56,6 +56,7 @@ noinst_PROGRAMS = \
56 modtofsaf\ 56 modtofsaf\
57 msgset\ 57 msgset\
58 modmesg\ 58 modmesg\
59 parseopt\
59 prop\ 60 prop\
60 scantime\ 61 scantime\
61 strftime\ 62 strftime\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2016 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU 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 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <mailutils/mailutils.h>
21 #include <mailutils/opt.h>
22
23 char *file_name;
24 char *find_value;
25 char *opt_value = "initial";
26 int jobs = 0;
27 int x_option;
28 int a_option;
29 int d_option;
30
31 struct mu_option group_a[] = {
32 MU_OPTION_GROUP("Group A"),
33 { "file", 'f', "FILE", MU_OPTION_DEFAULT,
34 "set file name",
35 mu_c_string, &file_name
36 },
37 { "find", 'F', "VALUE", MU_OPTION_DEFAULT,
38 "find VALUE",
39 mu_c_string, &find_value },
40 { "optional", 'o', "FILE", MU_OPTION_ARG_OPTIONAL,
41 "optional argument",
42 mu_c_string, &opt_value },
43 { NULL, 'x', NULL, MU_OPTION_DEFAULT,
44 "short-only option",
45 mu_c_incr, &x_option },
46 { "all", 'a', NULL, MU_OPTION_DEFAULT,
47 "no arguments to this one",
48 mu_c_bool, &a_option },
49 MU_OPTION_END
50 };
51
52 struct mu_option group_b[] = {
53 MU_OPTION_GROUP("Group B"),
54 { "debug", 'd', NULL, MU_OPTION_DEFAULT,
55 "another option",
56 mu_c_incr, &d_option },
57 { "verbose", 'v', NULL, MU_OPTION_ALIAS },
58 { "jobs", 'j', "N", MU_OPTION_DEFAULT,
59 "sets numeric value",
60 mu_c_int, &jobs },
61 MU_OPTION_END
62 };
63
64 struct mu_option *optv[] = { group_a, group_b, NULL };
65
66 #define S(s) ((s)?(s):"(null)")
67
68 int
69 main (int argc, char *argv[])
70 {
71 struct mu_parseopt po;
72 int rc;
73 int i;
74
75 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
76
77 rc = mu_parseopt (&po, argc, argv, optv, MU_PARSEOPT_DEFAULT);
78 printf ("rc=%d\n", rc);
79 mu_parseopt_apply (&po);
80
81 argc -= po.po_ind;
82 argv += po.po_ind;
83
84 mu_parseopt_free (&po);
85
86 printf ("file_name=%s\n", S(file_name));
87 printf ("find_value=%s\n", S(find_value));
88 printf ("opt_value=%s\n", S(opt_value));
89 printf ("x_option=%d\n", x_option);
90 printf ("a_option=%d\n", a_option);
91 printf ("d_option=%d\n", d_option);
92 printf ("jobs=%d\n", jobs);
93
94 printf ("argv:\n");
95 for (i = 0; i < argc; i++)
96 {
97 printf ("%d: %s\n", i, argv[i]);
98 }
99
100 return 0;
101 }