1 /* arg.c - argument parser */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2007 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/>.
21 #include <grub/misc.h>
24 #include <grub/normal.h>
25 #include <grub/term.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 "display this help and exit", 0, ARG_TYPE_NONE
},
35 {"usage", SHORT_ARG_USAGE
, 0,
36 "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);
81 find_long_option (char *s
)
83 char *argpos
= grub_strchr (s
, '=');
93 static struct grub_arg_option
*
94 find_long (const struct grub_arg_option
*options
, char *s
)
96 struct grub_arg_option
*found
= 0;
97 auto struct grub_arg_option
*fnd_long (const struct grub_arg_option
*opt
);
99 struct grub_arg_option
*fnd_long (const struct grub_arg_option
*opt
)
103 if (opt
->longarg
&& ! grub_strcmp (opt
->longarg
, s
))
104 return (struct grub_arg_option
*) opt
;
111 found
= fnd_long (options
);
114 found
= fnd_long (help_options
);
120 show_usage (grub_command_t cmd
)
122 grub_printf ("Usage: %s\n", cmd
->summary
);
126 grub_arg_show_help (grub_command_t cmd
)
128 auto void showargs (const struct grub_arg_option
*opt
);
132 auto void showargs (const struct grub_arg_option
*opt
)
134 for (; opt
->doc
; opt
++)
138 if (opt
->shortarg
&& grub_isgraph (opt
->shortarg
))
139 grub_printf ("-%c%c ", opt
->shortarg
, opt
->longarg
? ',':' ');
140 else if (opt
->shortarg
== SHORT_ARG_HELP
&& ! h_is_used
)
141 grub_printf ("-h, ");
142 else if (opt
->shortarg
== SHORT_ARG_USAGE
&& ! u_is_used
)
143 grub_printf ("-u, ");
149 grub_printf ("--%s", opt
->longarg
);
150 spacing
-= grub_strlen (opt
->longarg
) + 2;
154 grub_printf ("=%s", opt
->arg
);
155 spacing
-= grub_strlen (opt
->arg
) + 1;
159 while (spacing
-- > 0)
162 grub_printf ("%s\n", opt
->doc
);
164 switch (opt
->shortarg
)
181 grub_printf ("%s\n\n", cmd
->description
);
183 showargs (cmd
->options
);
184 showargs (help_options
);
186 grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT
);
192 parse_option (grub_command_t cmd
, int key
, char *arg
, struct grub_arg_list
*usr
)
197 grub_arg_show_help (cmd
);
200 case SHORT_ARG_USAGE
:
208 const struct grub_arg_option
*opt
= cmd
->options
;
212 if (opt
->shortarg
&& key
== opt
->shortarg
)
225 usr
[found
].arg
= arg
;
233 grub_arg_parse (grub_command_t cmd
, int argc
, char **argv
,
234 struct grub_arg_list
*usr
, char ***args
, int *argnum
)
241 auto grub_err_t
add_arg (char *s
);
243 grub_err_t
add_arg (char *s
)
245 argl
= grub_realloc (argl
, (++num
) * sizeof (char *));
253 for (curarg
= 0; curarg
< argc
; curarg
++)
255 char *arg
= argv
[curarg
];
256 struct grub_arg_option
*opt
;
259 /* No option is used. */
260 if (arg
[0] != '-' || grub_strlen (arg
) == 1)
262 if (add_arg (arg
) != 0)
268 /* One or more short options. */
271 char *curshort
= arg
+ 1;
275 opt
= find_short (cmd
->options
, *curshort
);
278 grub_error (GRUB_ERR_BAD_ARGUMENT
,
279 "Unknown argument `-%c'\n", *curshort
);
285 /* Parse all arguments here except the last one because
286 it can have an argument value. */
289 if (parse_option (cmd
, opt
->shortarg
, 0, usr
) || grub_errno
)
294 if (opt
->type
!= ARG_TYPE_NONE
)
296 if (curarg
+ 1 < argc
)
298 char *nextarg
= argv
[curarg
+ 1];
299 if (!(opt
->flags
& GRUB_ARG_OPTION_OPTIONAL
)
300 || (grub_strlen (nextarg
) < 2 || nextarg
[0] != '-'))
301 option
= argv
[++curarg
];
309 else /* The argument starts with "--". */
311 /* If the argument "--" is used just pass the other
313 if (grub_strlen (arg
) == 2)
315 for (curarg
++; curarg
< argc
; curarg
++)
316 if (add_arg (argv
[curarg
]) != 0)
321 longarg
= (char *) grub_strdup (arg
);
325 option
= find_long_option (longarg
);
328 opt
= find_long (cmd
->options
, arg
+ 2);
331 grub_error (GRUB_ERR_BAD_ARGUMENT
, "Unknown argument `%s'\n", arg
);
336 if (! (opt
->type
== ARG_TYPE_NONE
337 || (! option
&& (opt
->flags
& GRUB_ARG_OPTION_OPTIONAL
))))
341 grub_error (GRUB_ERR_BAD_ARGUMENT
,
342 "Missing mandatory option for `%s'\n", opt
->longarg
);
349 /* This will never happen. */
352 case ARG_TYPE_STRING
:
353 /* No need to do anything. */
360 grub_strtoul (option
, &tail
, 0);
361 if (tail
== 0 || tail
== option
|| *tail
!= '\0' || grub_errno
)
363 grub_error (GRUB_ERR_BAD_ARGUMENT
,
364 "The argument `%s' requires an integer.",
372 case ARG_TYPE_DEVICE
:
375 case ARG_TYPE_PATHNAME
:
376 /* XXX: Not implemented. */
379 if (parse_option (cmd
, opt
->shortarg
, option
, usr
) || grub_errno
)
386 grub_error (GRUB_ERR_BAD_ARGUMENT
,
387 "A value was assigned to the argument `%s' while it "
388 "doesn't require an argument\n", arg
);
392 if (parse_option (cmd
, opt
->shortarg
, 0, usr
) || grub_errno
)