On 11.03.2012 02:47, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> Underscore handling.
> On 11.03.2012 02:22, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> Update to fix escaping.
>> $"<string>" as long as <string> doesn't contain $* or $@ in absence of
>> gettext should behave the same as "<string>"
>> On 11.03.2012 02:09, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>>> Hello, all. Following discussion with Jordan Uggla it was found out that
>>> current syntax of $"..." without variable expansion isn't enough for a
>>> meaningful i18n and committing ourselves to it by releasing a version
>>> with it would be counter-productive as later we'll need something better
>>> but won't be able to remove something mostly useless. Since the bash
>>> behaviour is unsafe due to variable expansion in translated strings. But
>>> it's the very feature that is interesting for translation. There is
>>> however a compromise by allowing in translated string only same
>>> variables as in the original.This allows translator to rearrange
>>> variables as he sees fit but in the same time makes it safe (basically
>>> it's printf with reduced syntax and named tokens and without ability to
>>> run over the end). Fortunately only betas were released with $"..."
>>> feature and no project has used it for i18n yet. Attached patch
>>> implements the described behaviour.
>>> Variables $* and $@ can't be used inside $"...".
>>> Can someone have a look, comment on approach and/or provide tests?
>>>
>


-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko

=== modified file 'Makefile.util.def'
--- Makefile.util.def	2012-03-10 20:30:37 +0000
+++ Makefile.util.def	2012-03-11 02:31:15 +0000
@@ -666,6 +666,12 @@
   common = tests/grub_cmd_echo.in;
 };
 
+script = {
+  testcase;
+  name = grub_script_gettext;
+  common = tests/grub_script_gettext.in;
+};
+
 program = {
   testcase;
   name = example_unit_test;

=== modified file 'grub-core/script/execute.c'
--- grub-core/script/execute.c	2012-03-10 12:19:46 +0000
+++ grub-core/script/execute.c	2012-03-11 02:29:54 +0000
@@ -321,6 +321,211 @@
   return grub_env_set (name, val);
 }
 
+static int
+parse_string (const char *str,
+	      int (*hook) (const char *var, grub_size_t varlen),
+	      char **put)
+{
+  const char *ptr;
+  int escaped = 0;
+  const char *optr;
+
+  for (ptr = str; ptr && *ptr; )
+    switch (*ptr)
+      {
+      case '\\':
+	escaped = !escaped;
+	if (!escaped && put)
+	  *((*put)++) = '\\';
+	ptr++;
+	break;
+      case '$':
+	if (escaped)
+	  {
+	    escaped = 0;
+	    if (put)
+	      *((*put)++) = *ptr;
+	    ptr++;
+	    break;
+	  }
+
+	ptr++;
+	switch (*ptr)
+	  {
+	  case '{':
+	    {
+	      optr = ptr + 1;
+	      ptr = grub_strchr (optr, '}');
+	      if (!ptr)
+		break;
+	      if (hook (optr, ptr - optr))
+		return 1;
+	      ptr++;
+	      break;
+	    }
+	  case '0' ... '9':
+	    optr = ptr;
+	    while (*ptr >= '0' && *ptr <= '9')
+	      ptr++;
+	    if (hook (optr, ptr - optr))
+	      return 1;
+	    break;
+	  case 'a' ... 'z':
+	  case 'A' ... 'Z':
+	  case '_':
+	    optr = ptr;
+	    while ((*ptr >= '0' && *ptr <= '9')
+		   || (*ptr >= 'a' && *ptr <= 'z')
+		   || (*ptr >= 'A' && *ptr <= 'Z')
+		   || *ptr == '_')
+	      ptr++;
+	    if (hook (optr, ptr - optr))
+	      return 1;
+	    break;
+	  case '?':
+	  case '#':
+	    if (hook (ptr, 1))
+	      return 1;
+	    ptr++;
+	    break;
+	  }
+	break;
+      default:
+	if (escaped && put)
+	  *((*put)++) = '\\';
+	escaped = 0;
+	if (put)
+	  *((*put)++) = *ptr;
+	ptr++;
+	break;
+      }
+  return 0;
+}
+
+static int
+gettext_append (struct grub_script_argv *result, const char *orig_str)
+{
+  const char *template;
+  char *res = 0, *ptr;
+  char **allowed_strings;
+  grub_size_t nallowed_strings = 0;
+  grub_size_t additional_len = 1;
+  int rval = 1;
+  const char *iptr;
+
+  auto int save_allow (const char *str, grub_size_t len);
+  int save_allow (const char *str, grub_size_t len)
+  {
+    allowed_strings[nallowed_strings++] = grub_strndup (str, len);
+    if (!allowed_strings[nallowed_strings - 1])
+      return 1;
+    return 0;
+  }
+
+  auto int getlen (const char *str, grub_size_t len);
+  int getlen (const char *str, grub_size_t len)
+  {
+    const char *var;
+    grub_size_t i;
+
+    for (i = 0; i < nallowed_strings; i++)
+      if (grub_strncmp (allowed_strings[i], str, len) == 0
+	  && allowed_strings[i][len] == 0)
+	break;
+    if (i == nallowed_strings)
+      return 0;
+
+    /* Enough for any number.  */
+    if (len == 1 && str[0] == '#')
+      {
+	additional_len += 30;
+	return 0;
+      }
+    var = grub_env_get (allowed_strings[i]);
+    if (var)
+      additional_len += grub_strlen (var);
+    return 0;
+  }
+
+  auto int putvar (const char *str, grub_size_t len);
+  int putvar (const char *str, grub_size_t len)
+  {
+    const char *var;
+    grub_size_t i;
+
+    for (i = 0; i < nallowed_strings; i++)
+      if (grub_strncmp (allowed_strings[i], str, len) == 0
+	  && allowed_strings[i][len] == 0)
+       	{
+	  break;
+	}
+    if (i == nallowed_strings)
+      return 0;
+
+    /* Enough for any number.  */
+    if (len == 1 && str[0] == '#')
+      {
+	grub_snprintf (ptr, 30, "%u", scope->argv.argc);
+	ptr += grub_strlen (ptr);
+	return 0;
+      }
+    var = grub_env_get (allowed_strings[i]);
+    if (var)
+      ptr = grub_stpcpy (ptr, var);
+    return 0;
+  }
+
+  grub_size_t dollar_cnt = 0;
+
+  for (iptr = orig_str; *iptr; iptr++)
+    if (*iptr == '$')
+      dollar_cnt++;
+  allowed_strings = grub_malloc (sizeof (allowed_strings[0]) * dollar_cnt);
+
+  if (parse_string (orig_str, save_allow, 0))
+    goto fail;
+
+  template = _(orig_str);
+
+  if (parse_string (template, getlen, 0))
+    goto fail;
+
+  res = grub_malloc (grub_strlen (template) + additional_len);
+  if (!res)
+    goto fail;
+  ptr = res;
+
+  if (parse_string (template, putvar, &ptr))
+    goto fail;
+
+  *ptr = 0;
+  if (grub_wildcard_translator)
+    {
+      char *escaped = 0;
+      escaped = grub_wildcard_translator->escape (res);
+      if (grub_script_argv_append (result, escaped, grub_strlen (escaped)))
+	{
+	  grub_free (escaped);
+	  goto fail;
+	}
+      grub_free (escaped);
+    }
+  else
+    if (grub_script_argv_append (result, res, ptr - res))
+      goto fail;
+
+  rval = 0;
+ fail:
+  grub_free (res);
+  {
+    grub_size_t i;
+    for (i = 0; i < nallowed_strings; i++)
+      grub_free (allowed_strings[i]);
+  }
+  grub_free (allowed_strings);
+  return rval;
+}
+
 /* Convert arguments in ARGLIST into ARGV form.  */
 static int
 grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
@@ -406,8 +611,7 @@
 
 	    case GRUB_SCRIPT_ARG_TYPE_GETTEXT:
 	      {
-		const char *t = _(arg->str);
-		if (grub_script_argv_append (&result, t, grub_strlen (t)))
+		if (gettext_append (&result, arg->str))
 		  goto fail;
 	      }
 	      break;

=== modified file 'grub-core/script/yylex.l'
--- grub-core/script/yylex.l	2012-02-26 18:02:46 +0000
+++ grub-core/script/yylex.l	2012-03-11 01:16:17 +0000
@@ -289,7 +289,7 @@
 }
 
 <I18NQUOTE>{
-  \\\\          { COPY ("\\", 1); }
+  \\\\          { COPY ("\\\\", 2); }
   \\\"          { COPY ("\"", 1); }
   \\\n          { /* ignore */ }
   [^\"\\\n]+    { COPY (yytext, yyleng); }
@@ -297,6 +297,7 @@
                   yy_pop_state (yyscanner);
                   ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
                 }
+  \\          { COPY ("\\", 1); }
   (.|\n)        { COPY (yytext, yyleng); }
 }
 

=== added file 'tests/grub_script_gettext.in'
--- tests/grub_script_gettext.in	1970-01-01 00:00:00 +0000
+++ tests/grub_script_gettext.in	2012-03-11 02:25:41 +0000
@@ -0,0 +1,36 @@
+#! @builddir@/grub-shell-tester
+#
+# Copyright (C) 2010,2012  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/>.
+
+echo $"foo"
+echo $"foo   bar"
+
+echo -n $"foo"
+
+echo -e $"foo\nbar"
+
+echo -n -e $"foo\nbar"
+
+x=5
+echo $"$x"
+echo $"\x\\y\$x$x\\$xx${x}x\"$x\""
+
+if test -n "$grubshell"; then insmod regexp; fi
+
+echo $"*"
+
+foo="*"
+echo $"$foo"

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to