| /* 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> |
| #include <grub/misc.h> |
| #include <grub/script_sh.h> |
| |
| /* Return nearest power of two that is >= v. */ |
| static unsigned |
| round_up_exp (unsigned v) |
| { |
| COMPILE_TIME_ASSERT (sizeof (v) == 4); |
| |
| v--; |
| v |= v >> 1; |
| v |= v >> 2; |
| v |= v >> 4; |
| v |= v >> 8; |
| v |= v >> 16; |
| |
| v++; |
| v += (v == 0); |
| |
| return v; |
| } |
| |
| void |
| grub_script_argv_free (struct grub_script_argv *argv) |
| { |
| unsigned i; |
| |
| 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; |
| argv->script = 0; |
| } |
| |
| /* Make argv from argc, args pair. */ |
| int |
| grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args) |
| { |
| int i; |
| struct grub_script_argv r = { 0, 0, 0 }; |
| |
| for (i = 0; i < argc; i++) |
| if (grub_script_argv_next (&r) |
| || grub_script_argv_append (&r, args[i], grub_strlen (args[i]))) |
| { |
| grub_script_argv_free (&r); |
| return 1; |
| } |
| *argv = r; |
| return 0; |
| } |
| |
| /* Prepare for next argc. */ |
| int |
| grub_script_argv_next (struct grub_script_argv *argv) |
| { |
| char **p = argv->args; |
| |
| if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0) |
| return 0; |
| |
| p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *))); |
| if (! p) |
| return 1; |
| |
| argv->argc++; |
| argv->args = p; |
| |
| if (argv->argc == 1) |
| argv->args[0] = 0; |
| argv->args[argv->argc] = 0; |
| return 0; |
| } |
| |
| /* Append `s' to the last argument. */ |
| int |
| grub_script_argv_append (struct grub_script_argv *argv, const char *s, |
| grub_size_t slen) |
| { |
| grub_size_t a; |
| char *p = argv->args[argv->argc - 1]; |
| |
| if (! s) |
| return 0; |
| |
| a = p ? grub_strlen (p) : 0; |
| |
| p = grub_realloc (p, round_up_exp ((a + slen + 1) * sizeof (char))); |
| if (! p) |
| return 1; |
| |
| grub_memcpy (p + a, s, slen); |
| p[a+slen] = 0; |
| argv->args[argv->argc - 1] = p; |
| |
| return 0; |
| } |
| |
| /* Split `s' and append words as multiple arguments. */ |
| int |
| grub_script_argv_split_append (struct grub_script_argv *argv, const char *s) |
| { |
| const char *p; |
| int errors = 0; |
| |
| if (! s) |
| return 0; |
| |
| while (*s && grub_isspace (*s)) |
| s++; |
| |
| while (! errors && *s) |
| { |
| p = s; |
| while (*s && ! grub_isspace (*s)) |
| s++; |
| |
| errors += grub_script_argv_append (argv, p, s - p); |
| |
| while (*s && grub_isspace (*s)) |
| s++; |
| |
| if (*s) |
| errors += grub_script_argv_next (argv); |
| } |
| return errors; |
| } |