~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to normal/arg.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

Show diffs side-by-side

added added

removed removed

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