2009-01-10 Robert Millan <rmh@aybabtu.com>
[grub2/phcoder.git] / normal / arg.c
blob602f7eaff2a73b19f209893a904238c55e072c8c
1 /* arg.c - argument parser */
2 /*
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/arg.h>
21 #include <grub/misc.h>
22 #include <grub/mm.h>
23 #include <grub/err.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},
37 {0, 0, 0, 0, 0, 0}
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)
48 while (opt->doc)
50 if (opt->shortarg == c)
51 return (struct grub_arg_option *) opt;
52 opt++;
54 return 0;
57 if (options)
58 found = fnd_short (options);
60 if (! found)
62 switch (c)
64 case 'h':
65 found = (struct grub_arg_option *) help_options;
66 break;
68 case 'u':
69 found = (struct grub_arg_option *) (help_options + 1);
70 break;
72 default:
73 break;
77 return found;
80 static char *
81 find_long_option (char *s)
83 char *argpos = grub_strchr (s, '=');
85 if (argpos)
87 *argpos = '\0';
88 return ++argpos;
90 return 0;
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)
101 while (opt->doc)
103 if (opt->longarg && ! grub_strcmp (opt->longarg, s))
104 return (struct grub_arg_option *) opt;
105 opt++;
107 return 0;
110 if (options)
111 found = fnd_long (options);
113 if (! found)
114 found = fnd_long (help_options);
116 return found;
119 static void
120 show_usage (grub_command_t cmd)
122 grub_printf ("Usage: %s\n", cmd->summary);
125 void
126 grub_arg_show_help (grub_command_t cmd)
128 auto void showargs (const struct grub_arg_option *opt);
129 int h_is_used = 0;
130 int u_is_used = 0;
132 auto void showargs (const struct grub_arg_option *opt)
134 for (; opt->doc; opt++)
136 int spacing = 20;
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, ");
144 else
145 grub_printf (" ");
147 if (opt->longarg)
149 grub_printf ("--%s", opt->longarg);
150 spacing -= grub_strlen (opt->longarg) + 2;
152 if (opt->arg)
154 grub_printf ("=%s", opt->arg);
155 spacing -= grub_strlen (opt->arg) + 1;
159 while (spacing-- > 0)
160 grub_putchar (' ');
162 grub_printf ("%s\n", opt->doc);
164 switch (opt->shortarg)
166 case 'h':
167 h_is_used = 1;
168 break;
170 case 'u':
171 u_is_used = 1;
172 break;
174 default:
175 break;
180 show_usage (cmd);
181 grub_printf ("%s\n\n", cmd->description);
182 if (cmd->options)
183 showargs (cmd->options);
184 showargs (help_options);
185 #if 0
186 grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
187 #endif
191 static int
192 parse_option (grub_command_t cmd, int key, char *arg, struct grub_arg_list *usr)
194 switch (key)
196 case SHORT_ARG_HELP:
197 grub_arg_show_help (cmd);
198 return -1;
200 case SHORT_ARG_USAGE:
201 show_usage (cmd);
202 return -1;
204 default:
206 int found = -1;
207 int i = 0;
208 const struct grub_arg_option *opt = cmd->options;
210 while (opt->doc)
212 if (opt->shortarg && key == opt->shortarg)
214 found = i;
215 break;
217 opt++;
218 i++;
221 if (found == -1)
222 return -1;
224 usr[found].set = 1;
225 usr[found].arg = arg;
229 return 0;
233 grub_arg_parse (grub_command_t cmd, int argc, char **argv,
234 struct grub_arg_list *usr, char ***args, int *argnum)
236 int curarg;
237 char *longarg = 0;
238 int complete = 0;
239 char **argl = 0;
240 int num = 0;
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 *));
246 if (! argl)
247 return grub_errno;
248 argl[num - 1] = s;
249 return 0;
253 for (curarg = 0; curarg < argc; curarg++)
255 char *arg = argv[curarg];
256 struct grub_arg_option *opt;
257 char *option = 0;
259 /* No option is used. */
260 if (arg[0] != '-' || grub_strlen (arg) == 1)
262 if (add_arg (arg) != 0)
263 goto fail;
265 continue;
268 /* One or more short options. */
269 if (arg[1] != '-')
271 char *curshort = arg + 1;
273 while (1)
275 opt = find_short (cmd->options, *curshort);
276 if (! opt)
278 grub_error (GRUB_ERR_BAD_ARGUMENT,
279 "Unknown argument `-%c'\n", *curshort);
280 goto fail;
283 curshort++;
285 /* Parse all arguments here except the last one because
286 it can have an argument value. */
287 if (*curshort)
289 if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
290 goto fail;
292 else
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];
304 break;
309 else /* The argument starts with "--". */
311 /* If the argument "--" is used just pass the other
312 arguments. */
313 if (grub_strlen (arg) == 2)
315 for (curarg++; curarg < argc; curarg++)
316 if (add_arg (argv[curarg]) != 0)
317 goto fail;
318 break;
321 longarg = (char *) grub_strdup (arg);
322 if (! longarg)
323 goto fail;
325 option = find_long_option (longarg);
326 arg = longarg;
328 opt = find_long (cmd->options, arg + 2);
329 if (! opt)
331 grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown argument `%s'\n", arg);
332 goto fail;
336 if (! (opt->type == ARG_TYPE_NONE
337 || (! option && (opt->flags & GRUB_ARG_OPTION_OPTIONAL))))
339 if (! option)
341 grub_error (GRUB_ERR_BAD_ARGUMENT,
342 "Missing mandatory option for `%s'\n", opt->longarg);
343 goto fail;
346 switch (opt->type)
348 case ARG_TYPE_NONE:
349 /* This will never happen. */
350 break;
352 case ARG_TYPE_STRING:
353 /* No need to do anything. */
354 break;
356 case ARG_TYPE_INT:
358 char *tail;
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.",
365 arg);
367 goto fail;
369 break;
372 case ARG_TYPE_DEVICE:
373 case ARG_TYPE_DIR:
374 case ARG_TYPE_FILE:
375 case ARG_TYPE_PATHNAME:
376 /* XXX: Not implemented. */
377 break;
379 if (parse_option (cmd, opt->shortarg, option, usr) || grub_errno)
380 goto fail;
382 else
384 if (option)
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);
389 goto fail;
392 if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
393 goto fail;
395 grub_free (longarg);
396 longarg = 0;
399 complete = 1;
401 *args = argl;
402 *argnum = num;
404 fail:
405 grub_free (longarg);
407 return complete;