1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009 Free Software Foundation, Inc.
4 This program 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 of the License, or
7 (at your option) any later version.
9 This program 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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <libpspp/argv-parser.h>
23 #include <libpspp/assertion.h>
24 #include <libpspp/str.h>
28 struct argv_option_plus
30 struct argv_option base;
31 void (*cb) (int id, void *aux);
37 struct argv_option_plus *options;
38 size_t n_options, allocated_options;
41 /* Creates and returns a new argv_parser that initially is not
42 configured to parse any command-line options. */
44 argv_parser_create (void)
46 struct argv_parser *ap = xzalloc (sizeof *ap);
52 argv_parser_destroy (struct argv_parser *ap)
61 /* Adds the N options in OPTIONS to AP. When argv_parser_run is
62 later called for AP, each of the options in OPTIONS will be
63 handled by passing the option's 'id' member to CB along with
64 AUX. For an option that has an argument, the 'optarg' global
65 variable will be set to point to it before calling CB;
66 otherwise 'optarg' will be set to NULL. */
68 argv_parser_add_options (struct argv_parser *ap,
69 const struct argv_option *options, size_t n,
70 void (*cb) (int id, void *aux), void *aux)
72 const struct argv_option *src;
73 for (src = options; src < &options[n]; src++)
75 struct argv_option_plus *dst;
77 if (ap->n_options >= ap->allocated_options)
78 ap->options = x2nrealloc (ap->options, &ap->allocated_options,
81 assert (src->long_name != NULL || src->short_name != 0);
82 dst = &ap->options[ap->n_options++];
89 /* Parses all ARGC command-line arguments in ARGV according to
90 the options configured in AP with argv_parser_add_options.
91 Returns true if all the command-line arguments were parsed
92 successfully, false if there was an error. Upon failure
93 return, if the external variable 'opterr' is nonzero (which is
94 the default), an error message will also be printed. Upon
95 successful return, external variable 'optind' will be set to
96 the index of the first non-option argument. */
98 argv_parser_run (struct argv_parser *ap, int argc, char **argv)
100 enum { LONGOPT_VAL_BASE = UCHAR_MAX + 1 };
101 const struct argv_option_plus *shortopt_ptrs[UCHAR_MAX + 1];
102 struct string shortopts;
103 struct option *longopts;
108 memset (shortopt_ptrs, 0, sizeof shortopt_ptrs);
109 ds_init_empty (&shortopts);
110 longopts = xmalloc ((ap->n_options + 1) * sizeof *longopts);
112 for (i = 0; i < ap->n_options; i++)
114 const struct argv_option_plus *aop = &ap->options[i];
116 if (aop->base.long_name != NULL)
118 struct option *o = &longopts[n_longopts++];
119 o->name = aop->base.long_name;
120 o->has_arg = aop->base.has_arg;
122 o->val = i + LONGOPT_VAL_BASE;
125 if (aop->base.short_name != 0)
127 unsigned char c = aop->base.short_name;
128 if (shortopt_ptrs[c] == NULL)
130 shortopt_ptrs[c] = aop;
131 ds_put_char (&shortopts, aop->base.short_name);
132 if (aop->base.has_arg != no_argument)
133 ds_put_char (&shortopts, ':');
134 if (aop->base.has_arg == optional_argument)
135 ds_put_char (&shortopts, ':');
140 fprintf (stderr, "option -%c multiply defined",
141 aop->base.short_name);
147 memset (&longopts[n_longopts], 0, sizeof *longopts);
152 int c = getopt_long (argc, argv, ds_cstr (&shortopts),
153 longopts, &indexptr);
165 else if (c >= LONGOPT_VAL_BASE && c < LONGOPT_VAL_BASE + n_longopts)
167 struct argv_option_plus *aop = &ap->options[c - LONGOPT_VAL_BASE];
168 aop->cb (aop->base.id, aop->aux);
170 else if (c >= SCHAR_MIN && c <= UCHAR_MAX)
172 const struct argv_option_plus *aop = shortopt_ptrs[(unsigned char) c];
173 aop->cb (aop->base.id, aop->aux);
180 ds_destroy (&shortopts);