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>
26 /* Built-in parser for default options. */
27 #define SHORT_ARG_HELP -100
28 #define SHORT_ARG_USAGE -101
30 static const struct grub_arg_option help_options
[] =
32 {"help", SHORT_ARG_HELP
, 0,
33 "display this help and exit", 0, ARG_TYPE_NONE
},
34 {"usage", SHORT_ARG_USAGE
, 0,
35 "display the usage of this command and exit", 0, ARG_TYPE_NONE
},
39 static struct grub_arg_option
*
40 find_short (const struct grub_arg_option
*options
, char c
)
42 struct grub_arg_option
*found
= 0;
43 auto struct grub_arg_option
*fnd_short (const struct grub_arg_option
*opt
);
45 struct grub_arg_option
*fnd_short (const struct grub_arg_option
*opt
)
49 if (opt
->shortarg
== c
)
50 return (struct grub_arg_option
*) opt
;
57 found
= fnd_short (options
);
64 found
= (struct grub_arg_option
*) help_options
;
68 found
= (struct grub_arg_option
*) (help_options
+ 1);
79 static struct grub_arg_option
*
80 find_long (const struct grub_arg_option
*options
, const char *s
, int len
)
82 struct grub_arg_option
*found
= 0;
83 auto struct grub_arg_option
*fnd_long (const struct grub_arg_option
*opt
);
85 struct grub_arg_option
*fnd_long (const struct grub_arg_option
*opt
)
89 if (opt
->longarg
&& ! grub_strncmp (opt
->longarg
, s
, len
) &&
90 opt
->longarg
[len
] == '\0')
91 return (struct grub_arg_option
*) opt
;
98 found
= fnd_long (options
);
101 found
= fnd_long (help_options
);
107 show_usage (grub_extcmd_t cmd
)
109 grub_printf ("Usage: %s\n", cmd
->cmd
->summary
);
113 grub_arg_show_help (grub_extcmd_t cmd
)
115 auto void showargs (const struct grub_arg_option
*opt
);
119 auto void showargs (const struct grub_arg_option
*opt
)
121 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;
150 while (spacing
-- > 0)
153 while (*doc
&& *doc
!= '\n')
154 grub_putchar (*doc
++);
163 switch (opt
->shortarg
)
180 grub_printf ("%s\n\n", cmd
->cmd
->description
);
182 showargs (cmd
->options
);
183 showargs (help_options
);
185 grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT
);
191 parse_option (grub_extcmd_t cmd
, int key
, char *arg
, struct grub_arg_list
*usr
)
196 grub_arg_show_help (cmd
);
199 case SHORT_ARG_USAGE
:
207 const struct grub_arg_option
*opt
= cmd
->options
;
211 if (opt
->shortarg
&& key
== opt
->shortarg
)
224 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
)
240 auto grub_err_t
add_arg (char *s
);
242 grub_err_t
add_arg (char *s
)
244 argl
= grub_realloc (argl
, (++num
) * sizeof (char *));
252 for (curarg
= 0; curarg
< argc
; curarg
++)
254 char *arg
= argv
[curarg
];
255 struct grub_arg_option
*opt
;
258 /* No option is used. */
259 if (arg
[0] != '-' || grub_strlen (arg
) == 1)
261 if (add_arg (arg
) != 0)
267 /* One or more short options. */
270 char *curshort
= arg
+ 1;
274 opt
= find_short (cmd
->options
, *curshort
);
277 grub_error (GRUB_ERR_BAD_ARGUMENT
,
278 "Unknown argument `-%c'\n", *curshort
);
284 /* Parse all arguments here except the last one because
285 it can have an argument value. */
288 if (parse_option (cmd
, opt
->shortarg
, 0, usr
) || grub_errno
)
293 if (opt
->type
!= ARG_TYPE_NONE
)
295 if (curarg
+ 1 < argc
)
297 char *nextarg
= argv
[curarg
+ 1];
298 if (!(opt
->flags
& GRUB_ARG_OPTION_OPTIONAL
)
299 || (grub_strlen (nextarg
) < 2 || nextarg
[0] != '-'))
300 option
= argv
[++curarg
];
308 else /* The argument starts with "--". */
310 /* If the argument "--" is used just pass the other
312 if (grub_strlen (arg
) == 2)
314 for (curarg
++; curarg
< argc
; curarg
++)
315 if (add_arg (argv
[curarg
]) != 0)
320 option
= grub_strchr (arg
, '=');
322 arglen
= option
- arg
- 2;
325 arglen
= grub_strlen (arg
) - 2;
327 opt
= find_long (cmd
->options
, arg
+ 2, arglen
);
330 grub_error (GRUB_ERR_BAD_ARGUMENT
, "Unknown argument `%s'\n", arg
);
335 if (! (opt
->type
== ARG_TYPE_NONE
336 || (! option
&& (opt
->flags
& GRUB_ARG_OPTION_OPTIONAL
))))
340 grub_error (GRUB_ERR_BAD_ARGUMENT
,
341 "Missing mandatory option for `%s'\n", opt
->longarg
);
348 /* This will never happen. */
351 case ARG_TYPE_STRING
:
352 /* No need to do anything. */
359 grub_strtoul (option
, &tail
, 0);
360 if (tail
== 0 || tail
== option
|| *tail
!= '\0' || grub_errno
)
362 grub_error (GRUB_ERR_BAD_ARGUMENT
,
363 "The argument `%s' requires an integer.",
371 case ARG_TYPE_DEVICE
:
374 case ARG_TYPE_PATHNAME
:
375 /* XXX: Not implemented. */
378 if (parse_option (cmd
, opt
->shortarg
, option
, usr
) || grub_errno
)
385 grub_error (GRUB_ERR_BAD_ARGUMENT
,
386 "A value was assigned to the argument `%s' while it "
387 "doesn't require an argument\n", arg
);
391 if (parse_option (cmd
, opt
->shortarg
, 0, usr
) || grub_errno
)