]> git.proxmox.com Git - grub2.git/blame - normal/arg.c
2004-04-04 Yoshinori K. Okuji <okuji@enbug.org>
[grub2.git] / normal / arg.c
CommitLineData
db1771cf 1/* arg.c - argument parser */
2/*
4b13b216 3 * GRUB -- GRand Unified Bootloader
db1771cf 4 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
5 *
4b13b216 6 * GRUB is free software; you can redistribute it and/or modify
db1771cf 7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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.
15 *
16 * You should have received a copy of the GNU General Public License
4b13b216 17 * along with GRUB; if not, write to the Free Software
db1771cf 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
4b13b216 21#include "grub/arg.h"
22#include "grub/misc.h"
23#include "grub/mm.h"
24#include "grub/err.h"
25#include "grub/normal.h"
db1771cf 26
27/* Build in parser for default options. */
4b13b216 28static const struct grub_arg_option help_options[] =
db1771cf 29 {
30 {"help", 'h', 0, "Display help", 0, ARG_TYPE_NONE},
31 {"usage", 'u', 0, "Show how to use this command", 0, ARG_TYPE_NONE},
32 {0, 0, 0, 0, 0, 0}
33 };
34
4b13b216 35static struct grub_arg_option *
36find_short (const struct grub_arg_option *options, char c)
db1771cf 37{
4b13b216 38 struct grub_arg_option *found = 0;
39 auto struct grub_arg_option *fnd_short (const struct grub_arg_option *opt);
db1771cf 40
4b13b216 41 struct grub_arg_option *fnd_short (const struct grub_arg_option *opt)
db1771cf 42 {
43 while (opt->doc)
44 {
45 if (opt->shortarg == c)
4b13b216 46 return (struct grub_arg_option *) opt;
db1771cf 47 opt++;
48 }
49 return 0;
50 }
51
52 if (options)
53 found = fnd_short (options);
54 if (! found)
55 found = fnd_short (help_options);
56
57 return found;
58}
59
60static char *
61find_long_option (char *s)
62{
4b13b216 63 char *argpos = grub_strchr (s, '=');
db1771cf 64
65 if (argpos)
66 {
67 *argpos = '\0';
68 return ++argpos;
69 }
70 return 0;
71}
72
4b13b216 73static struct grub_arg_option *
74find_long (const struct grub_arg_option *options, char *s)
db1771cf 75{
4b13b216 76 struct grub_arg_option *found = 0;
77 auto struct grub_arg_option *fnd_long (const struct grub_arg_option *opt);
db1771cf 78
4b13b216 79 struct grub_arg_option *fnd_long (const struct grub_arg_option *opt)
db1771cf 80 {
81 while (opt->doc)
82 {
4b13b216 83 if (opt->longarg && !grub_strcmp (opt->longarg, s))
84 return (struct grub_arg_option *) opt;
db1771cf 85 opt++;
86 }
87 return 0;
88 }
89
90 if (options)
91 found = fnd_long (options);
92 if (!found)
93 found = fnd_long (help_options);
94
95 return found;
96}
97
98static void
4b13b216 99show_usage (grub_command_t cmd)
db1771cf 100{
4b13b216 101 grub_printf ("Usage: %s\n", cmd->summary);
db1771cf 102}
103
104static void
4b13b216 105show_help (grub_command_t cmd)
db1771cf 106{
4b13b216 107 static void showargs (const struct grub_arg_option *opt)
db1771cf 108 {
109 for (; opt->doc; opt++)
110 {
4b13b216 111 if (opt->shortarg && grub_isgraph (opt->shortarg))
112 grub_printf ("-%c%c ", opt->shortarg, opt->longarg ? ',':' ');
db1771cf 113 else
4b13b216 114 grub_printf (" ");
db1771cf 115 if (opt->longarg)
116 {
4b13b216 117 grub_printf ("--%s", opt->longarg);
db1771cf 118 if (opt->arg)
4b13b216 119 grub_printf ("=%s", opt->arg);
db1771cf 120 }
121 else
4b13b216 122 grub_printf ("\t");
db1771cf 123
4b13b216 124 grub_printf ("\t\t%s\n", opt->doc);
db1771cf 125 }
126 }
127
128 show_usage (cmd);
4b13b216 129 grub_printf ("%s\n\n", cmd->description);
db1771cf 130 if (cmd->options)
131 showargs (cmd->options);
132 showargs (help_options);
4b13b216 133 grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
db1771cf 134}
135
136
137static int
4b13b216 138parse_option (grub_command_t cmd, int key, char *arg, struct grub_arg_list *usr)
db1771cf 139{
140 switch (key)
141 {
142 case 'h':
143 show_help (cmd);
144 return -1;
145
146 case 'u':
147 show_usage (cmd);
148 return -1;
149
150 default:
151 {
152 int found = -1;
153 int i = 0;
4b13b216 154 const struct grub_arg_option *opt = cmd->options;
db1771cf 155
156 while (opt->doc)
157 {
158 if (opt->shortarg && key == opt->shortarg)
159 {
160 found = i;
161 break;
162 }
163 opt++;
164 i++;
165 }
166
167 if (found == -1)
168 return -1;
169
170 usr[found].set = 1;
171 usr[found].arg = arg;
172 }
173 }
174
175 return 0;
176}
177
178int
4b13b216 179grub_arg_parse (grub_command_t cmd, int argc, char **argv,
180 struct grub_arg_list *usr, char ***args, int *argnum)
db1771cf 181{
182 int curarg;
183 char *longarg = 0;
184 int complete = 0;
185 char **argl = 0;
186 int num = 0;
4b13b216 187 auto grub_err_t add_arg (char *s);
db1771cf 188
4b13b216 189 grub_err_t add_arg (char *s)
db1771cf 190 {
4b13b216 191 argl = grub_realloc (argl, (++num) * sizeof (char *));
db1771cf 192 if (! args)
4b13b216 193 return grub_errno;
db1771cf 194 argl[num - 1] = s;
195 return 0;
196 }
197
198
199 for (curarg = 0; curarg < argc; curarg++)
200 {
201 char *arg = argv[curarg];
4b13b216 202 struct grub_arg_option *opt;
db1771cf 203 char *option = 0;
204
205 /* No option is used. */
4b13b216 206 if (arg[0] != '-' || grub_strlen (arg) == 1)
db1771cf 207 {
208 if (add_arg (arg) != 0)
209 goto fail;
210
211 continue;
212 }
213
214 /* One or more short options. */
215 if (arg[1] != '-')
216 {
217 char *curshort = arg + 1;
218
219 while (1)
220 {
221 opt = find_short (cmd->options, *curshort);
222 if (!opt)
223 {
4b13b216 224 grub_error (GRUB_ERR_BAD_ARGUMENT,
db1771cf 225 "Unknown argument `-%c'\n", *curshort);
226 goto fail;
227 }
228
229 curshort++;
230
231 /* Parse all arguments here except the last one because
232 it can have an argument value. */
233 if (*curshort)
234 {
4b13b216 235 if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
db1771cf 236 goto fail;
237 }
238 else
239 {
240 if (opt->type != ARG_TYPE_NONE)
241 {
242 if (curarg + 1 < argc)
243 {
244 char *nextarg = argv[curarg + 1];
4b13b216 245 if (!(opt->flags & GRUB_ARG_OPTION_OPTIONAL)
246 || (grub_strlen (nextarg) < 2 || nextarg[0] != '-'))
db1771cf 247 option = argv[++curarg];
248 }
249 }
250 break;
251 }
252 }
253
254 }
255 else /* The argument starts with "--". */
256 {
257 /* If the argument "--" is used just pass the other
258 arguments. */
4b13b216 259 if (grub_strlen (arg) == 2)
db1771cf 260 {
261 for (curarg++; curarg < argc; curarg++)
262 if (add_arg (arg) != 0)
263 goto fail;
264 break;
265 }
266
4b13b216 267 longarg = (char *) grub_strdup (arg);
db1771cf 268 if (! longarg)
269 goto fail;
270
271 option = find_long_option (longarg);
272 arg = longarg;
273
274 opt = find_long (cmd->options, arg + 2);
275 if (!opt)
276 {
4b13b216 277 grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown argument `%s'\n", arg);
db1771cf 278 goto fail;
279 }
280 }
281
282 if (! (opt->type == ARG_TYPE_NONE
4b13b216 283 || (!option && (opt->flags & GRUB_ARG_OPTION_OPTIONAL))))
db1771cf 284 {
285 if (!option)
286 {
4b13b216 287 grub_error (GRUB_ERR_BAD_ARGUMENT,
db1771cf 288 "Missing mandatory option for `%s'\n", opt->longarg);
289 goto fail;
290 }
291
292 switch (opt->type)
293 {
294 case ARG_TYPE_NONE:
295 /* This will never happen. */
296 break;
297
298 case ARG_TYPE_STRING:
299 /* No need to do anything. */
300 break;
301
302 case ARG_TYPE_INT:
303 {
304 char *tail;
305
4b13b216 306 grub_strtoul (option, &tail, 0);
307 if (tail == 0 || tail == option || *tail != '\0' || grub_errno)
db1771cf 308 {
4b13b216 309 grub_error (GRUB_ERR_BAD_ARGUMENT,
db1771cf 310 "The argument `%s' requires an integer.",
311 arg);
312
313 goto fail;
314 }
315 break;
316 }
317
318 case ARG_TYPE_DEVICE:
319 case ARG_TYPE_DIR:
320 case ARG_TYPE_FILE:
321 case ARG_TYPE_PATHNAME:
322 /* XXX: Not implemented. */
323 break;
324 }
4b13b216 325 if (parse_option (cmd, opt->shortarg, option, usr) || grub_errno)
db1771cf 326 goto fail;
327 }
328 else
329 {
330 if (option)
331 {
4b13b216 332 grub_error (GRUB_ERR_BAD_ARGUMENT,
db1771cf 333 "A value was assigned to the argument `%s' while it "
334 "doesn't require an argument\n", arg);
335 goto fail;
336 }
337
4b13b216 338 if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
db1771cf 339 goto fail;
340 }
4b13b216 341 grub_free (longarg);
db1771cf 342 longarg = 0;
343 }
344
345 complete = 1;
346
347 *args = argl;
348 *argnum = num;
349
350 fail:
4b13b216 351 grub_free (longarg);
db1771cf 352
353 return complete;
354}