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 /* 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 }