summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2006-06-22 11:26:07 +0000
committerBruno Haible <bruno@clisp.org>2009-06-23 12:13:26 +0200
commitb677d519ae61e248c0391a72ee76a0b2d8f4126a (patch)
tree96009d80834b612a07c49cc77c55f667e61205c6
parent93882c1dbe95b7c0b30dbbf8a81cf0d8cf455220 (diff)
downloadexternal_gettext-b677d519ae61e248c0391a72ee76a0b2d8f4126a.zip
external_gettext-b677d519ae61e248c0391a72ee76a0b2d8f4126a.tar.gz
external_gettext-b677d519ae61e248c0391a72ee76a0b2d8f4126a.tar.bz2
Recognize $(...) syntax also inside double-quotes.
-rw-r--r--gettext-tools/src/ChangeLog6
-rw-r--r--gettext-tools/src/x-sh.c313
-rw-r--r--gettext-tools/tests/ChangeLog5
-rw-r--r--gettext-tools/tests/Makefile.am2
4 files changed, 189 insertions, 137 deletions
diff --git a/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog
index 065afdc..7e6b2a2 100644
--- a/gettext-tools/src/ChangeLog
+++ b/gettext-tools/src/ChangeLog
@@ -1,3 +1,9 @@
+2006-06-21 Bruno Haible <bruno@clisp.org>
+
+ * x-sh.c (read_word): Recognize $(...) and $((...)) also inside
+ double-quoted strings.
+ Reported by Michelle Konzack <linux4michelle@freenet.de>.
+
2006-06-04 Bruno Haible <bruno@clisp.org>
* msgl-check.c (check_plural_eval): Declare 'distribution' as volatile,
diff --git a/gettext-tools/src/x-sh.c b/gettext-tools/src/x-sh.c
index 45bef34..8b18d40 100644
--- a/gettext-tools/src/x-sh.c
+++ b/gettext-tools/src/x-sh.c
@@ -503,6 +503,9 @@ is_operator_start (int c)
#define OPENING_BACKQUOTE (2 * (UCHAR_MAX + 1) + '`')
#define CLOSING_BACKQUOTE (3 * (UCHAR_MAX + 1) + '`')
+/* 2 characters of pushback are supported.
+ 2 characters of pushback occur only when the first is an 'x'; in all
+ other cases only one character of pushback is needed. */
static int phase2_pushback[2];
static int phase2_pushback_length;
@@ -835,10 +838,39 @@ read_word (struct word *wp, int looking_for, flag_context_ty context)
if (c == '$')
{
- int c2 = phase2_getc ();
+ int c2;
+
+ /* An unquoted dollar indicates we are not inside '...'. */
+ if (open_singlequote)
+ abort ();
+ /* After reading a dollar, we know that there is no pushed back
+ character from an earlier lookahead. */
+ if (phase2_pushback_length > 0)
+ abort ();
+ /* Therefore we can use phase1 without interfering with phase2.
+ We need to recognize $( outside and inside double-quotes.
+ It would be incorrect to do
+ c2 = phase2_getc ();
+ if (c2 == '(' || c2 == QUOTED ('('))
+ because that would also trigger for $\(. */
+ c2 = phase1_getc ();
if (c2 == '(')
{
- int c3 = phase2_getc ();
+ bool saved_open_doublequote;
+ int c3;
+
+ phase1_ungetc (c2);
+
+ /* The entire inner command or arithmetic expression is read
+ ignoring possible surrounding double-quotes. */
+ saved_open_doublequote = open_doublequote;
+ open_doublequote = false;
+
+ c2 = phase2_getc ();
+ if (c2 != '(')
+ abort ();
+
+ c3 = phase2_getc ();
if (c3 == '(')
{
/* Arithmetic expression. Skip until the matching closing
@@ -862,178 +894,187 @@ read_word (struct word *wp, int looking_for, flag_context_ty context)
phase2_ungetc (c3);
read_command_list (')', context);
}
+
+ open_doublequote = saved_open_doublequote;
}
- else if (c2 == '\'' && !open_singlequote)
+ else
{
- /* Bash builtin for string with ANSI-C escape sequences. */
- saw_opening_singlequote ();
- for (;;)
+ phase1_ungetc (c2);
+ c2 = phase2_getc ();
+
+ if (c2 == '\'' && !open_singlequote)
{
- c = phase2_getc ();
- if (c == EOF)
- break;
- if (c == '\'')
- {
- saw_closing_singlequote ();
- break;
- }
- if (c == '\\')
+ /* Bash builtin for string with ANSI-C escape sequences. */
+ saw_opening_singlequote ();
+ for (;;)
{
c = phase2_getc ();
- switch (c)
+ if (c == EOF)
+ break;
+ if (c == '\'')
{
- default:
- phase2_ungetc (c);
- c = '\\';
- break;
-
- case '\\':
- break;
- case '\'':
- /* Don't call saw_closing_singlequote () here. */
- break;
-
- case 'a':
- c = '\a';
- break;
- case 'b':
- c = '\b';
- break;
- case 'e':
- c = 0x1b; /* ESC */
- break;
- case 'f':
- c = '\f';
- break;
- case 'n':
- c = '\n';
+ saw_closing_singlequote ();
break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case 'v':
- c = '\v';
- break;
-
- case 'x':
+ }
+ if (c == '\\')
+ {
c = phase2_getc ();
- if ((c >= '0' && c <= '9')
- || (c >= 'A' && c <= 'F')
- || (c >= 'a' && c <= 'f'))
+ switch (c)
{
- int n;
-
- if (c >= '0' && c <= '9')
- n = c - '0';
- else if (c >= 'A' && c <= 'F')
- n = 10 + c - 'A';
- else if (c >= 'a' && c <= 'f')
- n = 10 + c - 'a';
- else
- abort ();
-
+ default:
+ phase2_ungetc (c);
+ c = '\\';
+ break;
+
+ case '\\':
+ break;
+ case '\'':
+ /* Don't call saw_closing_singlequote ()
+ here. */
+ break;
+
+ case 'a':
+ c = '\a';
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'e':
+ c = 0x1b; /* ESC */
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+
+ case 'x':
c = phase2_getc ();
if ((c >= '0' && c <= '9')
|| (c >= 'A' && c <= 'F')
|| (c >= 'a' && c <= 'f'))
{
+ int n;
+
if (c >= '0' && c <= '9')
- n = n * 16 + c - '0';
+ n = c - '0';
else if (c >= 'A' && c <= 'F')
- n = n * 16 + 10 + c - 'A';
+ n = 10 + c - 'A';
else if (c >= 'a' && c <= 'f')
- n = n * 16 + 10 + c - 'a';
+ n = 10 + c - 'a';
else
abort ();
- }
- else
- phase2_ungetc (c);
- c = n;
- }
- else
- {
- phase2_ungetc (c);
- phase2_ungetc ('x');
- c = '\\';
- }
- break;
+ c = phase2_getc ();
+ if ((c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'F')
+ || (c >= 'a' && c <= 'f'))
+ {
+ if (c >= '0' && c <= '9')
+ n = n * 16 + c - '0';
+ else if (c >= 'A' && c <= 'F')
+ n = n * 16 + 10 + c - 'A';
+ else if (c >= 'a' && c <= 'f')
+ n = n * 16 + 10 + c - 'a';
+ else
+ abort ();
+ }
+ else
+ phase2_ungetc (c);
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- {
- int n = c - '0';
+ c = n;
+ }
+ else
+ {
+ phase2_ungetc (c);
+ phase2_ungetc ('x');
+ c = '\\';
+ }
+ break;
- c = phase2_getc ();
- if (c >= '0' && c <= '7')
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
{
- n = n * 8 + c - '0';
+ int n = c - '0';
c = phase2_getc ();
if (c >= '0' && c <= '7')
- n = n * 8 + c - '0';
+ {
+ n = n * 8 + c - '0';
+
+ c = phase2_getc ();
+ if (c >= '0' && c <= '7')
+ n = n * 8 + c - '0';
+ else
+ phase2_ungetc (c);
+ }
else
phase2_ungetc (c);
- }
- else
- phase2_ungetc (c);
- c = n;
- }
- break;
+ c = n;
+ }
+ break;
+ }
+ }
+ if (wp->type == t_string)
+ {
+ grow_token (wp->token);
+ wp->token->chars[wp->token->charcount++] =
+ (unsigned char) c;
}
}
- if (wp->type == t_string)
- {
- grow_token (wp->token);
- wp->token->chars[wp->token->charcount++] =
- (unsigned char) c;
- }
+ /* The result is a literal string. Don't change wp->type. */
+ continue;
}
- /* The result is a literal string. Don't change wp->type. */
- continue;
- }
- else if (c2 == '"' && !open_doublequote)
- {
- /* Bash builtin for internationalized string. */
- lex_pos_ty pos;
- struct token string;
-
- saw_opening_singlequote ();
- open_singlequote_terminator = '"';
- pos.file_name = logical_file_name;
- pos.line_number = line_number;
- init_token (&string);
- for (;;)
+ else if (c2 == '"' && !open_doublequote)
{
- c = phase2_getc ();
- if (c == EOF)
- break;
- if (c == '"')
+ /* Bash builtin for internationalized string. */
+ lex_pos_ty pos;
+ struct token string;
+
+ saw_opening_singlequote ();
+ open_singlequote_terminator = '"';
+ pos.file_name = logical_file_name;
+ pos.line_number = line_number;
+ init_token (&string);
+ for (;;)
{
- saw_closing_singlequote ();
- break;
+ c = phase2_getc ();
+ if (c == EOF)
+ break;
+ if (c == '"')
+ {
+ saw_closing_singlequote ();
+ break;
+ }
+ grow_token (&string);
+ string.chars[string.charcount++] = (unsigned char) c;
}
- grow_token (&string);
- string.chars[string.charcount++] = (unsigned char) c;
- }
- remember_a_message (mlp, NULL, string_of_token (&string),
- context, &pos, savable_comment);
- free_token (&string);
+ remember_a_message (mlp, NULL, string_of_token (&string),
+ context, &pos, savable_comment);
+ free_token (&string);
- error_with_progname = false;
- error (0, 0, _("%s:%lu: warning: the syntax $\"...\" is deprecated due to security reasons; use eval_gettext instead"),
- pos.file_name, (unsigned long) pos.line_number);
- error_with_progname = true;
+ error_with_progname = false;
+ error (0, 0, _("%s:%lu: warning: the syntax $\"...\" is deprecated due to security reasons; use eval_gettext instead"),
+ pos.file_name, (unsigned long) pos.line_number);
+ error_with_progname = true;
- /* The result at runtime is not constant. Therefore we
- change wp->type. */
+ /* The result at runtime is not constant. Therefore we
+ change wp->type. */
+ }
+ else
+ phase2_ungetc (c2);
}
- else
- phase2_ungetc (c2);
wp->type = t_other;
continue;
}
diff --git a/gettext-tools/tests/ChangeLog b/gettext-tools/tests/ChangeLog
index fae9dca..2b79cad 100644
--- a/gettext-tools/tests/ChangeLog
+++ b/gettext-tools/tests/ChangeLog
@@ -1,3 +1,8 @@
+2006-06-21 Bruno Haible <bruno@clisp.org>
+
+ * xgettext-sh-5: New file.
+ * Makefile.am (TESTS): Add it.
+
2006-06-17 Bruno Haible <bruno@clisp.org>
* recode-sr-latin-2 (LOCALE_JA_EUCJP): Determine locale name depending
diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am
index 92c162d..31aeb1f 100644
--- a/gettext-tools/tests/Makefile.am
+++ b/gettext-tools/tests/Makefile.am
@@ -84,7 +84,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \
xgettext-properties-1 \
xgettext-python-1 xgettext-python-2 xgettext-python-3 \
xgettext-scheme-1 \
- xgettext-sh-1 xgettext-sh-2 xgettext-sh-3 xgettext-sh-4 \
+ xgettext-sh-1 xgettext-sh-2 xgettext-sh-3 xgettext-sh-4 xgettext-sh-5 \
xgettext-smalltalk-1 \
xgettext-stringtable-1 \
xgettext-tcl-1 xgettext-tcl-2 \