From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Re: gettext $"..."
Date: Sun, 11 Mar 2012 02:47:28 +0100 [thread overview]
Message-ID: <4F5C0430.90500@gmail.com> (raw)
In-Reply-To: <4F5BFE6A.90301@gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 1493 bytes --]
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
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: gettext.diff --]
[-- Type: text/x-diff; name="gettext.diff", Size: 5527 bytes --]
=== 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 #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 294 bytes --]
next prev parent reply other threads:[~2012-03-11 1:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-11 1:09 gettext $"..." Vladimir 'φ-coder/phcoder' Serbinenko
2012-03-11 1:22 ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-03-11 1:47 ` Vladimir 'φ-coder/phcoder' Serbinenko [this message]
2012-03-11 2:45 ` Vladimir 'φ-coder/phcoder' Serbinenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4F5C0430.90500@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.