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
++)
125 if (opt
->shortarg
&& grub_isgraph (opt
->shortarg
))
126 grub_printf ("-%c%c ", opt
->shortarg
, opt
->longarg
? ',':' ');
127 else if (opt
->shortarg
== SHORT_ARG_HELP
&& ! h_is_used
)
128 grub_printf ("-h, ");
129 else if (opt
->shortarg
== SHORT_ARG_USAGE
&& ! u_is_used
)
130 grub_printf ("-u, ");
136 grub_printf ("--%s", opt
->longarg
);
137 spacing
-= grub_strlen (opt
->longarg
) + 2;
141 grub_printf ("=%s", opt
->arg
);
142 spacing
-= grub_strlen (opt
->arg
) + 1;
146 const char *doc
= opt
->doc
;
149 while (spacing
-- > 0)
152 while (*doc
&& *doc
!= '\n')
153 grub_putchar (*doc
++);
162 switch (opt
->shortarg
)
179 grub_printf ("%s\n\n", cmd
->cmd
->description
);
181 showargs (cmd
->options
);
182 showargs (help_options
);
184 grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT
);
190 parse_option (grub_extcmd_t cmd
, int key
, char *arg
, struct grub_arg_list
*usr
)
195 grub_arg_show_help (cmd
);
198 case SHORT_ARG_USAGE
:
206 const struct grub_arg_option
*opt
= cmd
->options
;
210 if (opt
->shortarg
&& key
== opt
->shortarg
)
223 usr
[found
].arg
= arg
;
231 grub_arg_parse (grub_extcmd_t cmd
, int argc
, char **argv
,
232 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
)
243 argl
= grub_realloc (argl
, (++num
) * sizeof (char *));
251 for (curarg
= 0; curarg
< argc
; curarg
++)
253 char *arg
= argv
[curarg
];
254 struct grub_arg_option
*opt
;
257 /* No option is used. */
258 if (arg
[0] != '-' || grub_strlen (arg
) == 1)
260 if (add_arg (arg
) != 0)
266 /* One or more short options. */
269 char *curshort
= arg
+ 1;
273 opt
= find_short (cmd
->options
, *curshort
);
276 grub_error (GRUB_ERR_BAD_ARGUMENT
,
277 "Unknown argument `-%c'\n", *curshort
);
283 /* Parse all arguments here except the last one because
284 it can have an argument value. */
287 if (parse_option (cmd
, opt
->shortarg
, 0, usr
) || grub_errno
)
292 if (opt
->type
!= ARG_TYPE_NONE
)
294 if (curarg
+ 1 < argc
)
296 char *nextarg
= argv
[curarg
+ 1];
297 if (!(opt
->flags
& GRUB_ARG_OPTION_OPTIONAL
)
298 || (grub_strlen (nextarg
) < 2 || nextarg
[0] != '-'))
299 option
= argv
[++curarg
];
307 else /* The argument starts with "--". */
309 /* If the argument "--" is used just pass the other
311 if (grub_strlen (arg
) == 2)
313 for (curarg
++; curarg
< argc
; curarg
++)
314 if (add_arg (argv
[curarg
]) != 0)
319 option
= grub_strchr (arg
, '=');
321 arglen
= option
- arg
- 2;
324 arglen
= grub_strlen (arg
) - 2;
326 opt
= find_long (cmd
->options
, arg
+ 2, arglen
);
329 grub_error (GRUB_ERR_BAD_ARGUMENT
, "Unknown argument `%s'\n", arg
);
334 if (! (opt
->type
== ARG_TYPE_NONE
335 || (! option
&& (opt
->flags
& GRUB_ARG_OPTION_OPTIONAL
))))
339 grub_error (GRUB_ERR_BAD_ARGUMENT
,
340 "Missing mandatory option for `%s'\n", opt
->longarg
);
347 /* This will never happen. */
350 case ARG_TYPE_STRING
:
351 /* No need to do anything. */
358 grub_strtoul (option
, &tail
, 0);
359 if (tail
== 0 || tail
== option
|| *tail
!= '\0' || grub_errno
)
361 grub_error (GRUB_ERR_BAD_ARGUMENT
,
362 "The argument `%s' requires an integer.",
370 case ARG_TYPE_DEVICE
:
373 case ARG_TYPE_PATHNAME
:
374 /* XXX: Not implemented. */
377 if (parse_option (cmd
, opt
->shortarg
, option
, usr
) || grub_errno
)
384 grub_error (GRUB_ERR_BAD_ARGUMENT
,
385 "A value was assigned to the argument `%s' while it "
386 "doesn't require an argument\n", arg
);
390 if (parse_option (cmd
, opt
->shortarg
, 0, usr
) || grub_errno
)