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 '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 01:46:49 +0000
@@ -321,6 +321,197 @@
   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;
+
+  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 +597,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); }
 }
 

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