source: grub-pc/trunk/fuentes/grub-core/lib/arg.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 9.5 KB
Line 
1/* arg.c - argument parser */
2/*
3 *  GRUB  --  GRand Unified Bootloader
4 *  Copyright (C) 2003,2004,2005,2007,2008  Free Software Foundation, Inc.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20#include <grub/misc.h>
21#include <grub/mm.h>
22#include <grub/err.h>
23#include <grub/term.h>
24#include <grub/extcmd.h>
25#include <grub/i18n.h>
26
27/* Built-in parser for default options.  */
28static const struct grub_arg_option help_options[] =
29  {
30    {"help", 0, 0,
31     N_("Display this help and exit."), 0, ARG_TYPE_NONE},
32    {"usage", 0, 0,
33     N_("Display the usage of this command and exit."), 0, ARG_TYPE_NONE},
34    {0, 0, 0, 0, 0, 0}
35  };
36
37/* Helper for find_short.  */
38static const struct grub_arg_option *
39fnd_short (const struct grub_arg_option *opt, char c)
40{
41  while (opt->doc)
42    {
43      if (opt->shortarg == c)
44        return opt;
45      opt++;
46    }
47  return 0;
48}
49
50static const struct grub_arg_option *
51find_short (const struct grub_arg_option *options, char c)
52{
53  const struct grub_arg_option *found = 0;
54
55  if (options)
56    found = fnd_short (options, c);
57
58  if (! found)
59    {
60      switch (c)
61        {
62        case 'h':
63          found = help_options;
64          break;
65
66        case 'u':
67          found = (help_options + 1);
68          break;
69
70        default:
71          break;
72        }
73    }
74
75  return found;
76}
77
78/* Helper for find_long.  */
79static const struct grub_arg_option *
80fnd_long (const struct grub_arg_option *opt, const char *s, int len)
81{
82  while (opt->doc)
83    {
84      if (opt->longarg && ! grub_strncmp (opt->longarg, s, len) &&
85          opt->longarg[len] == '\0')
86        return opt;
87      opt++;
88    }
89  return 0;
90}
91
92static const struct grub_arg_option *
93find_long (const struct grub_arg_option *options, const char *s, int len)
94{
95  const struct grub_arg_option *found = 0;
96
97  if (options)
98    found = fnd_long (options, s, len);
99
100  if (! found)
101    found = fnd_long (help_options, s, len);
102
103  return found;
104}
105
106static void
107show_usage (grub_extcmd_t cmd)
108{
109  grub_printf ("%s %s %s\n", _("Usage:"), cmd->cmd->name, _(cmd->cmd->summary));
110}
111
112static void
113showargs (const struct grub_arg_option *opt,
114          int h_is_used, int u_is_used)
115{
116  for (; opt->doc; opt++)
117    {
118      int spacing = 20;
119
120      if (opt->shortarg && grub_isgraph (opt->shortarg))
121        grub_printf ("-%c%c ", opt->shortarg, opt->longarg ? ',':' ');
122      else if (opt == help_options && ! h_is_used)
123        grub_printf ("-h, ");
124      else if (opt == help_options + 1 && ! u_is_used)
125        grub_printf ("-u, ");
126      else
127        grub_printf ("    ");
128
129      if (opt->longarg)
130        {
131          grub_printf ("--%s", opt->longarg);
132          spacing -= grub_strlen (opt->longarg) + 2;
133
134          if (opt->arg)
135            {
136              grub_printf ("=%s", opt->arg);
137              spacing -= grub_strlen (opt->arg) + 1;
138            }
139        }
140
141      if (spacing <= 0)
142        spacing = 3;
143
144      while (spacing--)
145        grub_xputs (" ");
146
147      grub_printf ("%s\n", _(opt->doc));
148    }
149}
150
151void
152grub_arg_show_help (grub_extcmd_t cmd)
153{
154  int h_is_used = 0;
155  int u_is_used = 0;
156  const struct grub_arg_option *opt;
157
158  show_usage (cmd);
159  grub_printf ("%s\n\n", _(cmd->cmd->description));
160
161  for (opt = cmd->options; opt && opt->doc; opt++)
162    switch (opt->shortarg)
163      {
164      case 'h':
165        h_is_used = 1;
166        break;
167
168      case 'u':
169        u_is_used = 1;
170        break;
171      }
172
173  if (cmd->options)
174    showargs (cmd->options, h_is_used, u_is_used);
175  showargs (help_options, h_is_used, u_is_used);
176#if 0
177  grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
178#endif
179}
180
181
182static int
183parse_option (grub_extcmd_t cmd, const struct grub_arg_option *opt,
184              char *arg, struct grub_arg_list *usr)
185{
186  if (opt == help_options)
187    {
188      grub_arg_show_help (cmd);
189      return -1;
190    }
191
192  if (opt == help_options + 1)
193    {
194      show_usage (cmd);
195      return -1;
196    }
197  {
198    int found = opt - cmd->options;
199
200    if (opt->flags & GRUB_ARG_OPTION_REPEATABLE)
201      {
202        usr[found].args[usr[found].set++] = arg;
203        usr[found].args[usr[found].set] = NULL;
204      }
205    else
206      {
207        usr[found].set = 1;
208        usr[found].arg = arg;
209      }
210  }
211
212  return 0;
213}
214
215static inline grub_err_t
216add_arg (char ***argl, int *num, char *s)
217{
218  char **p = *argl;
219  *argl = grub_realloc (*argl, (++(*num) + 1) * sizeof (char *));
220  if (! *argl)
221    {
222      grub_free (p);
223      return grub_errno;
224    }
225  (*argl)[(*num) - 1] = s;
226  (*argl)[(*num)] = NULL;
227  return 0;
228}
229
230
231int
232grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
233                struct grub_arg_list *usr, char ***args, int *argnum)
234{
235  int curarg;
236  int arglen;
237  char **argl = 0;
238  int num = 0;
239
240  for (curarg = 0; curarg < argc; curarg++)
241    {
242      char *arg = argv[curarg];
243      const struct grub_arg_option *opt;
244      char *option = 0;
245
246      /* No option is used.  */
247      if ((num && (cmd->cmd->flags & GRUB_COMMAND_OPTIONS_AT_START))
248          || arg[0] != '-' || grub_strlen (arg) == 1)
249        {
250          if (add_arg (&argl, &num, arg) != 0)
251            goto fail;
252
253          continue;
254        }
255
256      /* One or more short options.  */
257      if (arg[1] != '-')
258        {
259          char *curshort;
260
261          if (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH)
262            {
263              for (curshort = arg + 1; *curshort; curshort++)
264                if (!find_short (cmd->options, *curshort))
265                  break;
266           
267              if (*curshort)
268                {
269                  if (add_arg (&argl, &num, arg) != 0)
270                    goto fail;
271                  continue;
272                }
273            }
274
275          curshort = arg + 1;
276
277          while (1)
278            {
279              opt = find_short (cmd->options, *curshort);
280
281              if (! opt)
282                {
283                  char tmp[3] = { '-', *curshort, 0 };
284                  grub_error (GRUB_ERR_BAD_ARGUMENT,
285                              N_("unknown argument `%s'"), tmp);
286                  goto fail;
287                }
288
289              curshort++;
290
291              /* Parse all arguments here except the last one because
292                 it can have an argument value.  */
293              if (*curshort)
294                {
295                  if (parse_option (cmd, opt, 0, usr) || grub_errno)
296                    goto fail;
297                }
298              else
299                {
300                  if (opt->type != ARG_TYPE_NONE)
301                    {
302                      if (curarg + 1 < argc)
303                        {
304                          char *nextarg = argv[curarg + 1];
305                          if (!(opt->flags & GRUB_ARG_OPTION_OPTIONAL)
306                              || (grub_strlen (nextarg) < 2 || nextarg[0] != '-'))
307                            option = argv[++curarg];
308                        }
309                    }
310                  break;
311                }
312            }
313
314        }
315      else /* The argument starts with "--".  */
316        {
317          /* If the argument "--" is used just pass the other
318             arguments.  */
319          if (grub_strlen (arg) == 2)
320            {
321              for (curarg++; curarg < argc; curarg++)
322                if (add_arg (&argl, &num, argv[curarg]) != 0)
323                  goto fail;
324              break;
325            }
326
327          option = grub_strchr (arg, '=');
328          if (option)
329            {
330              arglen = option - arg - 2;
331              option++;
332            }
333          else
334            arglen = grub_strlen (arg) - 2;
335
336          opt = find_long (cmd->options, arg + 2, arglen);
337
338          if (!option && argv[curarg + 1] && argv[curarg + 1][0] != '-'
339              && opt && opt->type != ARG_TYPE_NONE)
340            option = argv[++curarg];
341
342          if (!opt && (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH))
343            {
344              if (add_arg (&argl, &num, arg) != 0)
345                goto fail;
346              continue;
347            }
348
349          if (! opt)
350            {
351              grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unknown argument `%s'"), arg);
352              goto fail;
353            }
354        }
355
356      if (! (opt->type == ARG_TYPE_NONE
357             || (! option && (opt->flags & GRUB_ARG_OPTION_OPTIONAL))))
358        {
359          if (! option)
360            {
361              grub_error (GRUB_ERR_BAD_ARGUMENT,
362                          N_("missing mandatory option for `%s'"), opt->longarg);
363              goto fail;
364            }
365
366          switch (opt->type)
367            {
368            case ARG_TYPE_NONE:
369              /* This will never happen.  */
370              break;
371
372            case ARG_TYPE_STRING:
373                  /* No need to do anything.  */
374              break;
375
376            case ARG_TYPE_INT:
377              {
378                char *tail;
379
380                grub_strtoull (option, &tail, 0);
381                if (tail == 0 || tail == option || *tail != '\0' || grub_errno)
382                  {
383                    grub_error (GRUB_ERR_BAD_ARGUMENT,
384                                N_("the argument `%s' requires an integer"),
385                                arg);
386
387                    goto fail;
388                  }
389                break;
390              }
391
392            case ARG_TYPE_DEVICE:
393            case ARG_TYPE_DIR:
394            case ARG_TYPE_FILE:
395            case ARG_TYPE_PATHNAME:
396              /* XXX: Not implemented.  */
397              break;
398            }
399          if (parse_option (cmd, opt, option, usr) || grub_errno)
400            goto fail;
401        }
402      else
403        {
404          if (option)
405            {
406              grub_error (GRUB_ERR_BAD_ARGUMENT,
407                          N_("a value was assigned to the argument `%s' while it "
408                             "doesn't require an argument"), arg);
409              goto fail;
410            }
411
412          if (parse_option (cmd, opt, 0, usr) || grub_errno)
413            goto fail;
414        }
415    }
416
417  *args = argl;
418  *argnum = num;
419  return 1;
420
421 fail:
422  return 0;
423}
424
425struct grub_arg_list*
426grub_arg_list_alloc(grub_extcmd_t extcmd, int argc,
427                    char **argv __attribute__((unused)))
428{
429  int i;
430  char **args;
431  grub_size_t argcnt;
432  struct grub_arg_list *list;
433  const struct grub_arg_option *options;
434
435  options = extcmd->options;
436  if (! options)
437    return 0;
438
439  argcnt = 0;
440  for (i = 0; options[i].doc; i++)
441    {
442      if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
443        argcnt += ((grub_size_t) argc + 1) / 2 + 1; /* max possible for any option */
444    }
445
446  list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt);
447  if (! list)
448    return 0;
449
450  args = (char**) (list + i);
451  for (i = 0; options[i].doc; i++)
452    {
453      list[i].set = 0;
454      list[i].arg = 0;
455
456      if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
457        {
458          list[i].args = args;
459          args += (grub_size_t) argc / 2 + 1;
460        }
461    }
462  return list;
463}
Note: See TracBrowser for help on using the repository browser.