From 262b2d73c73f0f9b4b2e9d0a9a32c1ea36ab118b Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Tue, 3 Aug 2010 16:33:36 +0530 Subject: [PATCH 1/3] regexp sets matches to $match* --- commands/regexp.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/commands/regexp.c b/commands/regexp.c index e8e8243b5..2e84c3b0d 100644 --- a/commands/regexp.c +++ b/commands/regexp.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -29,28 +31,50 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { int argn = 0; - int matches = 0; regex_t regex; int ret; grub_size_t s; char *comperr; grub_err_t err; + regmatch_t *matches = 0; if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected"); - ret = regcomp (®ex, args[0], RE_SYNTAX_GNU_AWK); + ret = regcomp (®ex, args[0], REG_EXTENDED); if (ret) goto fail; - ret = regexec (®ex, args[1], 0, 0, 0); + matches = grub_zalloc (sizeof (*matches) * (regex.re_nsub + 1)); + if (! matches) + goto fail; + + ret = regexec (®ex, args[1], regex.re_nsub + 1, matches, 0); if (!ret) { + int i; + char ch; + char buf[5 + sizeof (size_t) * 3]; + + for (i = 0; i <= regex.re_nsub && matches[i].rm_so != -1; i++) + { + ch = args[1][matches[i].rm_eo]; + args[1][matches[i].rm_eo] = '\0'; + + grub_snprintf (buf, sizeof (buf), "%s%u", "match", i); + if (grub_env_set (buf, args[1] + matches[i].rm_so)) + break; + + args[1][matches[i].rm_eo] = ch; + } + regfree (®ex); + grub_free (matches); return GRUB_ERR_NONE; } fail: + grub_free (matches); s = regerror (ret, ®ex, 0, 0); comperr = grub_malloc (s); if (!comperr) From 1355b096f6613d8aed2bf878b02ad26fee8ca3ab Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 4 Aug 2010 11:08:26 +0530 Subject: [PATCH 2/3] regexp can take variable names to update with matches --- commands/regexp.c | 92 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/commands/regexp.c b/commands/regexp.c index 2e84c3b0d..8edf818a3 100644 --- a/commands/regexp.c +++ b/commands/regexp.c @@ -22,13 +22,69 @@ #include #include #include -#include +#include #include #include +static const struct grub_arg_option options[] = + { + { "set", 's', GRUB_ARG_OPTION_REPEATABLE, + N_("Variable names to update with matches."), + N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING }, + { 0, 0, 0, 0, 0, 0 } + }; + static grub_err_t -grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), - int argc, char **args) +set_matches (char **varnames, char *str, grub_size_t nmatches, + regmatch_t *matches) +{ + int i; + char ch; + char *p; + char *q; + grub_err_t err; + unsigned long j; + + auto void setvar (char *v, regmatch_t *m); + void setvar (char *v, regmatch_t *m) + { + ch = str[m->rm_eo]; + str[m->rm_eo] = '\0'; + err = grub_env_set (v, str + m->rm_so); + str[m->rm_eo] = ch; + } + + for (i = 0; varnames && varnames[i]; i++) + { + if (! (p = grub_strchr (varnames[i], ':'))) + { + /* varname w/o index defaults to 1 */ + if (nmatches < 2 || matches[1].rm_so == -1) + grub_env_unset (varnames[i]); + else + setvar (varnames[i], &matches[1]); + } + else + { + j = grub_strtoul (varnames[i], &q, 10); + if (q != p) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid variable name format %s", varnames[i]); + + if (nmatches <= j || matches[j].rm_so == -1) + grub_env_unset (p + 1); + else + setvar (p + 1, &matches[j]); + } + + if (err != GRUB_ERR_NONE) + return err; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_regexp (grub_extcmd_context_t ctxt, int argc, char **args) { int argn = 0; regex_t regex; @@ -52,25 +108,11 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), ret = regexec (®ex, args[1], regex.re_nsub + 1, matches, 0); if (!ret) { - int i; - char ch; - char buf[5 + sizeof (size_t) * 3]; - - for (i = 0; i <= regex.re_nsub && matches[i].rm_so != -1; i++) - { - ch = args[1][matches[i].rm_eo]; - args[1][matches[i].rm_eo] = '\0'; - - grub_snprintf (buf, sizeof (buf), "%s%u", "match", i); - if (grub_env_set (buf, args[1] + matches[i].rm_so)) - break; - - args[1][matches[i].rm_eo] = ch; - } - + err = set_matches (ctxt->state[0].args, args[1], + regex.re_nsub + 1, matches); regfree (®ex); grub_free (matches); - return GRUB_ERR_NONE; + return err; } fail: @@ -89,16 +131,16 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), return err; } -static grub_command_t cmd; +static grub_extcmd_t cmd; GRUB_MOD_INIT(regexp) { - cmd = grub_register_command ("regexp", grub_cmd_regexp, - N_("REGEXP STRING"), - N_("Test if REGEXP matches STRING.")); + cmd = grub_register_extcmd ("regexp", grub_cmd_regexp, + GRUB_COMMAND_FLAG_BOTH, N_("REGEXP STRING"), + N_("Test if REGEXP matches STRING."), options); } GRUB_MOD_FINI(regexp) { - grub_unregister_command (cmd); + grub_unregister_extcmd (cmd); } From cd838e22c2ed09788abc79e3a0056b30af90025c Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 4 Aug 2010 19:21:18 +0530 Subject: [PATCH 3/3] added a testcase --- conf/tests.rmk | 4 ++++ tests/regexp_vars.in | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/regexp_vars.in diff --git a/conf/tests.rmk b/conf/tests.rmk index 9144e5528..f7ec76366 100644 --- a/conf/tests.rmk +++ b/conf/tests.rmk @@ -74,6 +74,9 @@ grub_script_comments_SOURCES = tests/grub_script_comments.in check_SCRIPTS += grub_script_functions grub_script_functions_SOURCES = tests/grub_script_functions.in +check_SCRIPTS += regexp_vars +regexp_vars_SOURCES = tests/regexp_vars.in + # List of tests to execute on "make check" # SCRIPTED_TESTS = example_scripted_test # SCRIPTED_TESTS += example_grub_script_test @@ -91,6 +94,7 @@ SCRIPTED_TESTS += grub_script_final_semicolon SCRIPTED_TESTS += grub_script_dollar SCRIPTED_TESTS += grub_script_comments SCRIPTED_TESTS += grub_script_functions +SCRIPTED_TESTS += regexp_vars # dependencies between tests and testing-tools $(SCRIPTED_TESTS): grub-shell grub-shell-tester diff --git a/tests/regexp_vars.in b/tests/regexp_vars.in new file mode 100644 index 000000000..43b479fec --- /dev/null +++ b/tests/regexp_vars.in @@ -0,0 +1,41 @@ +#! /bin/bash -e + +# Run GRUB script in a Qemu instance +# 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 . + +cmd='regexp -s version "vm-(.*)" vm-1.2.3; echo $version' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != 1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 1:version "vm-(.*)" vm-1.2.3; echo $version' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != 1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 0:match "vm-(.*)" vm-1.2.3; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != vm-1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 2:match "vm-(.*)" vm-1.2.3; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test -n "$v"; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s match "\\\((.*)\\\)" (hd0,msdos1); echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != "hd0,msdos1"; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s match "hd([0-9]+)" hd0; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != "0"; then echo "error: $cmd" >&2; exit 1; fi