1
/* arg.c - argument parser */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
6
* GRUB is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* GRUB is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20
#include <grub/misc.h>
23
#include <grub/term.h>
24
#include <grub/extcmd.h>
25
#include <grub/i18n.h>
27
/* Built-in parser for default options. */
28
#define SHORT_ARG_HELP -100
29
#define SHORT_ARG_USAGE -101
31
static const struct grub_arg_option help_options[] =
33
{"help", SHORT_ARG_HELP, 0,
34
N_("Display this help and exit."), 0, ARG_TYPE_NONE},
35
{"usage", SHORT_ARG_USAGE, 0,
36
N_("Display the usage of this command and exit."), 0, ARG_TYPE_NONE},
40
static struct grub_arg_option *
41
find_short (const struct grub_arg_option *options, char c)
43
struct grub_arg_option *found = 0;
44
auto struct grub_arg_option *fnd_short (const struct grub_arg_option *opt);
46
struct grub_arg_option *fnd_short (const struct grub_arg_option *opt)
50
if (opt->shortarg == c)
51
return (struct grub_arg_option *) opt;
58
found = fnd_short (options);
65
found = (struct grub_arg_option *) help_options;
69
found = (struct grub_arg_option *) (help_options + 1);
80
static struct grub_arg_option *
81
find_long (const struct grub_arg_option *options, const char *s, int len)
83
struct grub_arg_option *found = 0;
84
auto struct grub_arg_option *fnd_long (const struct grub_arg_option *opt);
86
struct grub_arg_option *fnd_long (const struct grub_arg_option *opt)
90
if (opt->longarg && ! grub_strncmp (opt->longarg, s, len) &&
91
opt->longarg[len] == '\0')
92
return (struct grub_arg_option *) opt;
99
found = fnd_long (options);
102
found = fnd_long (help_options);
108
show_usage (grub_extcmd_t cmd)
110
grub_printf ("%s %s %s\n", _("Usage:"), cmd->cmd->name, _(cmd->cmd->summary));
114
grub_arg_show_help (grub_extcmd_t cmd)
116
auto void showargs (const struct grub_arg_option *opt);
120
auto void showargs (const struct grub_arg_option *opt)
122
for (; opt->doc; opt++)
126
if (opt->shortarg && grub_isgraph (opt->shortarg))
127
grub_printf ("-%c%c ", opt->shortarg, opt->longarg ? ',':' ');
128
else if (opt->shortarg == SHORT_ARG_HELP && ! h_is_used)
129
grub_printf ("-h, ");
130
else if (opt->shortarg == SHORT_ARG_USAGE && ! u_is_used)
131
grub_printf ("-u, ");
137
grub_printf ("--%s", opt->longarg);
138
spacing -= grub_strlen (opt->longarg) + 2;
142
grub_printf ("=%s", opt->arg);
143
spacing -= grub_strlen (opt->arg) + 1;
153
grub_printf ("%s\n", _(opt->doc));
155
switch (opt->shortarg)
172
grub_printf ("%s\n\n", _(cmd->cmd->description));
174
showargs (cmd->options);
175
showargs (help_options);
177
grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
183
parse_option (grub_extcmd_t cmd, int key, char *arg, struct grub_arg_list *usr)
188
grub_arg_show_help (cmd);
191
case SHORT_ARG_USAGE:
199
const struct grub_arg_option *opt = cmd->options;
203
if (opt->shortarg && key == opt->shortarg)
215
if (opt->flags & GRUB_ARG_OPTION_REPEATABLE)
217
usr[found].args[usr[found].set++] = arg;
218
usr[found].args[usr[found].set] = NULL;
223
usr[found].arg = arg;
232
grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
233
struct grub_arg_list *usr, char ***args, int *argnum)
239
auto grub_err_t add_arg (char *s);
241
grub_err_t add_arg (char *s)
244
argl = grub_realloc (argl, (++num + 1) * sizeof (char *));
256
for (curarg = 0; curarg < argc; curarg++)
258
char *arg = argv[curarg];
259
struct grub_arg_option *opt;
262
/* No option is used. */
263
if ((num && (cmd->cmd->flags & GRUB_COMMAND_OPTIONS_AT_START))
264
|| arg[0] != '-' || grub_strlen (arg) == 1)
266
if (add_arg (arg) != 0)
272
/* One or more short options. */
277
if (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH)
279
for (curshort = arg + 1; *curshort; curshort++)
280
if (!find_short (cmd->options, *curshort))
285
if (add_arg (arg) != 0)
295
opt = find_short (cmd->options, *curshort);
299
grub_error (GRUB_ERR_BAD_ARGUMENT,
300
"unknown argument `-%c'", *curshort);
306
/* Parse all arguments here except the last one because
307
it can have an argument value. */
310
if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
315
if (opt->type != ARG_TYPE_NONE)
317
if (curarg + 1 < argc)
319
char *nextarg = argv[curarg + 1];
320
if (!(opt->flags & GRUB_ARG_OPTION_OPTIONAL)
321
|| (grub_strlen (nextarg) < 2 || nextarg[0] != '-'))
322
option = argv[++curarg];
330
else /* The argument starts with "--". */
332
/* If the argument "--" is used just pass the other
334
if (grub_strlen (arg) == 2)
336
for (curarg++; curarg < argc; curarg++)
337
if (add_arg (argv[curarg]) != 0)
342
option = grub_strchr (arg, '=');
345
arglen = option - arg - 2;
349
arglen = grub_strlen (arg) - 2;
351
opt = find_long (cmd->options, arg + 2, arglen);
353
if (!option && argv[curarg + 1] && argv[curarg + 1][0] != '-'
354
&& opt->type != ARG_TYPE_NONE)
355
option = argv[++curarg];
357
if (!opt && (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH))
359
if (add_arg (arg) != 0)
366
grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown argument `%s'", arg);
371
if (! (opt->type == ARG_TYPE_NONE
372
|| (! option && (opt->flags & GRUB_ARG_OPTION_OPTIONAL))))
376
grub_error (GRUB_ERR_BAD_ARGUMENT,
377
"missing mandatory option for `%s'", opt->longarg);
384
/* This will never happen. */
387
case ARG_TYPE_STRING:
388
/* No need to do anything. */
395
grub_strtoull (option, &tail, 0);
396
if (tail == 0 || tail == option || *tail != '\0' || grub_errno)
398
grub_error (GRUB_ERR_BAD_ARGUMENT,
399
"the argument `%s' requires an integer",
407
case ARG_TYPE_DEVICE:
410
case ARG_TYPE_PATHNAME:
411
/* XXX: Not implemented. */
414
if (parse_option (cmd, opt->shortarg, option, usr) || grub_errno)
421
grub_error (GRUB_ERR_BAD_ARGUMENT,
422
"a value was assigned to the argument `%s' while it "
423
"doesn't require an argument", arg);
427
if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
440
struct grub_arg_list*
441
grub_arg_list_alloc(grub_extcmd_t extcmd, int argc,
442
char **argv __attribute__((unused)))
447
struct grub_arg_list *list;
448
const struct grub_arg_option *options;
450
options = extcmd->options;
455
for (i = 0; options[i].doc; i++)
457
if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
458
argcnt += (argc + 1) / 2 + 1; /* max possible for any option */
461
list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt);
465
args = (char**) (list + i);
466
for (i = 0; options[i].doc; i++)
471
if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
474
args += argc / 2 + 1;