argv.c 3.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* argv.c - methods for constructing argument vector */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2010  Free Software Foundation, Inc.
 *
 *  GRUB is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <grub/mm.h>
21
#include <grub/misc.h>
22 23
#include <grub/script_sh.h>

BVK Chaitanya's avatar
BVK Chaitanya committed
24
/* Return nearest power of two that is >= v.  */
25 26 27
static unsigned
round_up_exp (unsigned v)
{
28 29
  COMPILE_TIME_ASSERT (sizeof (v) == 4);

30 31 32 33 34 35
  v--;
  v |= v >> 1;
  v |= v >> 2;
  v |= v >> 4;
  v |= v >> 8;
  v |= v >> 16;
36

37 38 39 40 41
  v++;
  v += (v == 0);

  return v;
}
42 43 44 45

void
grub_script_argv_free (struct grub_script_argv *argv)
{
46
  unsigned i;
47 48 49 50 51 52 53 54 55 56 57

  if (argv->args)
    {
      for (i = 0; i < argv->argc; i++)
	grub_free (argv->args[i]);

      grub_free (argv->args);
    }

  argv->argc = 0;
  argv->args = 0;
58
  argv->script = 0;
59 60
}

61 62 63 64 65
/* Make argv from argc, args pair.  */
int
grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args)
{
  int i;
BVK Chaitanya's avatar
BVK Chaitanya committed
66
  struct grub_script_argv r = { 0, 0, 0 };
67 68

  for (i = 0; i < argc; i++)
69 70
    if (grub_script_argv_next (&r)
	|| grub_script_argv_append (&r, args[i], grub_strlen (args[i])))
71 72 73 74 75 76 77 78
      {
	grub_script_argv_free (&r);
	return 1;
      }
  *argv = r;
  return 0;
}

79 80 81 82 83 84
/* Prepare for next argc.  */
int
grub_script_argv_next (struct grub_script_argv *argv)
{
  char **p = argv->args;

85
  if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0)
86 87
    return 0;

88
  p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *)));
89 90 91 92 93
  if (! p)
    return 1;

  argv->argc++;
  argv->args = p;
94 95 96

  if (argv->argc == 1)
    argv->args[0] = 0;
97 98 99 100
  argv->args[argv->argc] = 0;
  return 0;
}

BVK Chaitanya's avatar
BVK Chaitanya committed
101 102
/* Append `s' to the last argument.  */
int
103 104
grub_script_argv_append (struct grub_script_argv *argv, const char *s,
			 grub_size_t slen)
105
{
106
  grub_size_t a;
107 108 109 110 111 112 113
  char *p = argv->args[argv->argc - 1];

  if (! s)
    return 0;

  a = p ? grub_strlen (p) : 0;

114
  p = grub_realloc (p, round_up_exp ((a + slen + 1) * sizeof (char)));
115 116 117
  if (! p)
    return 1;

118 119
  grub_memcpy (p + a, s, slen);
  p[a+slen] = 0;
120
  argv->args[argv->argc - 1] = p;
BVK Chaitanya's avatar
BVK Chaitanya committed
121

122 123 124 125 126
  return 0;
}

/* Split `s' and append words as multiple arguments.  */
int
127
grub_script_argv_split_append (struct grub_script_argv *argv, const char *s)
128
{
129
  const char *p;
130 131 132 133 134
  int errors = 0;

  if (! s)
    return 0;

135 136 137
  while (*s && grub_isspace (*s))
    s++;

138 139 140 141 142 143
  while (! errors && *s)
    {
      p = s;
      while (*s && ! grub_isspace (*s))
	s++;

144
      errors += grub_script_argv_append (argv, p, s - p);
145 146 147 148 149 150 151 152 153

      while (*s && grub_isspace (*s))
	s++;

      if (*s)
	errors += grub_script_argv_next (argv);
    }
  return errors;
}