| /* regexp.c -- The regexp command. */ |
| /* |
| * GRUB -- GRand Unified Bootloader |
| * Copyright (C) 2005,2007 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/dl.h> |
| #include <grub/misc.h> |
| #include <grub/mm.h> |
| #include <grub/err.h> |
| #include <grub/env.h> |
| #include <grub/extcmd.h> |
| #include <grub/i18n.h> |
| #include <grub/script_sh.h> |
| #include <regex.h> |
| |
| GRUB_MOD_LICENSE ("GPLv3+"); |
| |
| static const struct grub_arg_option options[] = |
| { |
| { "set", 's', GRUB_ARG_OPTION_REPEATABLE, |
| /* TRANSLATORS: in regexp you can mark some |
| groups with parentheses. These groups are |
| then numbered and you can save some of |
| them in variables. In other programs |
| those components aree often referenced with |
| back slash, e.g. \1. Compare |
| sed -e 's,\([a-z][a-z]*\),lowercase=\1,g' |
| The whole matching component is saved in VARNAME, not its number. |
| */ |
| N_("Store matched component NUMBER in VARNAME."), |
| N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING }, |
| { 0, 0, 0, 0, 0, 0 } |
| }; |
| |
| static grub_err_t |
| setvar (char *str, char *v, regmatch_t *m) |
| { |
| char ch; |
| grub_err_t err; |
| ch = str[m->rm_eo]; |
| str[m->rm_eo] = '\0'; |
| err = grub_env_set (v, str + m->rm_so); |
| str[m->rm_eo] = ch; |
| return err; |
| } |
| |
| static grub_err_t |
| set_matches (char **varnames, char *str, grub_size_t nmatches, |
| regmatch_t *matches) |
| { |
| int i; |
| char *p; |
| char *q; |
| grub_err_t err; |
| unsigned long j; |
| |
| for (i = 0; varnames && varnames[i]; i++) |
| { |
| err = GRUB_ERR_NONE; |
| p = grub_strchr (varnames[i], ':'); |
| if (! p) |
| { |
| /* varname w/o index defaults to 1 */ |
| if (nmatches < 2 || matches[1].rm_so == -1) |
| grub_env_unset (varnames[i]); |
| else |
| err = setvar (str, 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 |
| err = setvar (str, 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) |
| { |
| 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, N_("two arguments expected")); |
| |
| ret = regcomp (®ex, args[0], REG_EXTENDED); |
| if (ret) |
| goto fail; |
| |
| 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) |
| { |
| err = set_matches (ctxt->state[0].args, args[1], |
| regex.re_nsub + 1, matches); |
| regfree (®ex); |
| grub_free (matches); |
| return err; |
| } |
| |
| fail: |
| grub_free (matches); |
| s = regerror (ret, ®ex, 0, 0); |
| comperr = grub_malloc (s); |
| if (!comperr) |
| { |
| regfree (®ex); |
| return grub_errno; |
| } |
| regerror (ret, ®ex, comperr, s); |
| err = grub_error (GRUB_ERR_TEST_FAILURE, "%s", comperr); |
| regfree (®ex); |
| grub_free (comperr); |
| return err; |
| } |
| |
| static grub_extcmd_t cmd; |
| |
| GRUB_MOD_INIT(regexp) |
| { |
| cmd = grub_register_extcmd ("regexp", grub_cmd_regexp, 0, |
| /* TRANSLATORS: This are two arguments. So it's |
| two separate units to translate and pay |
| attention not to reverse them. */ |
| N_("REGEXP STRING"), |
| N_("Test if REGEXP matches STRING."), options); |
| |
| /* Setup GRUB script wildcard translator. */ |
| grub_wildcard_translator = &grub_filename_translator; |
| } |
| |
| GRUB_MOD_FINI(regexp) |
| { |
| grub_unregister_extcmd (cmd); |
| grub_wildcard_translator = 0; |
| } |