From f3400e323262b10191148c6c607eb3c46b49746c Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 19 Aug 2019 10:52:36 +0200 Subject: [PATCH] xgettext: Recognize gettext -e invocations in shell parser. Reported by Eugene V. Lyubimkin in . * gettext-runtime/src/escapes.h: New file, extracted from gettext-runtime/src/gettext.c. * gettext-runtime/src/gettext.c: Include escapes.h. (expand_escape): Remove function. (inhibit_added_newline): New variable. (add_newline): Remove variable. (main): Initialize inhibit_added_newline. Invoke expand_escapes instead of expand_escape. * gettext-runtime/src/ngettext.c: Include escapes.h. (expand_escape): Remove function. (main): Invoke expand_escapes instead of expand_escape. * gettext-runtime/src/Makefile.am (gettext_SOURCES, ngettext_SOURCES): Add escapes.h. * gettext-tools/tests/tstgettext.c: Include escapes.h. (expand_escape): Remove function. (inhibit_added_newline): New variable. (add_newline): Remove variable. (main): Initialize inhibit_added_newline. Invoke expand_escapes instead of expand_escape. * gettext-tools/tests/Makefile.am (tstgettext_SOURCES): Add escapes.h. * gettext-tools/src/x-sh.c: Include escapes.h. (read_command): Recognize a '-e' option in the argument list of gettext and ngettext. * gettext-tools/src/Makefile.am (xgettext_SOURCES): Add escapes.h. * gettext-tools/tests/xgettext-sh-1: Test the recognition of gettext -e arguments. * NEWS: Mention the change. --- NEWS | 9 +- gettext-runtime/src/Makefile.am | 6 +- gettext-runtime/src/escapes.h | 133 ++++++++++++++++++++++++++++++ gettext-runtime/src/gettext.c | 122 ++------------------------- gettext-runtime/src/ngettext.c | 108 +----------------------- gettext-tools/src/Makefile.am | 23 +++++- gettext-tools/src/x-sh.c | 41 ++++++++- gettext-tools/tests/Makefile.am | 4 +- gettext-tools/tests/tstgettext.c | 122 ++------------------------- gettext-tools/tests/xgettext-sh-1 | 47 +++++++++++ 10 files changed, 268 insertions(+), 347 deletions(-) create mode 100644 gettext-runtime/src/escapes.h diff --git a/NEWS b/NEWS index a80d9c8ee..32050e96f 100644 --- a/NEWS +++ b/NEWS @@ -2,9 +2,12 @@ Version 0.20.2 - April 2020 * Programming languages support: - Shell: - The programs 'gettext', 'ngettext', when invoked with option -e, now - expand '\\' and octal escape sequences, instead of swallowing them. - (Bug present since the beginning.) + o The programs 'gettext', 'ngettext', when invoked with option -e, now + expand '\\' and octal escape sequences, instead of swallowing them. + (Bug present since the beginning.) + o xgettext now recognizes 'gettext' program invocations with the '-e' + option, such as + gettext -e 'some\nstring\n' - Desktop Entry: The value of the 'Icon' property is no longer extracted into the POT file by xgettext. The documentation explains how to localize icons. diff --git a/gettext-runtime/src/Makefile.am b/gettext-runtime/src/Makefile.am index e3c161ee3..e86003468 100644 --- a/gettext-runtime/src/Makefile.am +++ b/gettext-runtime/src/Makefile.am @@ -1,5 +1,5 @@ ## Makefile for the gettext-runtime/src subdirectory of GNU gettext -## Copyright (C) 1995-1998, 2000-2007, 2009 Free Software Foundation, Inc. +## Copyright (C) 1995-1998, 2000-2007, 2009, 2019 Free Software Foundation, Inc. ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -34,8 +34,8 @@ AM_CPPFLAGS = \ DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ # Source dependencies. -gettext_SOURCES = gettext.c -ngettext_SOURCES = ngettext.c +gettext_SOURCES = gettext.c escapes.h +ngettext_SOURCES = ngettext.c escapes.h envsubst_SOURCES = envsubst.c # Link dependencies. diff --git a/gettext-runtime/src/escapes.h b/gettext-runtime/src/escapes.h new file mode 100644 index 000000000..acda05403 --- /dev/null +++ b/gettext-runtime/src/escapes.h @@ -0,0 +1,133 @@ +/* Expand escape sequences in a string. + Copyright (C) 1995-1997, 2000-2007, 2012, 2018-2019 Free Software + Foundation, Inc. + Written by Ulrich Drepper , May 1995. + + This program 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. + + This program 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 this program. If not, see . */ + +/* Expand some escape sequences found in the argument string. + If backslash_c_seen is != NULL, '\c' sequences are recognized and + have the effect of setting *backslash_c_seen to true. + Returns either the argument string or a freshly allocated string. */ +static const char * +expand_escapes (const char *str, bool *backslash_c_seen) +{ + const char *cp = str; + + /* Find the location of the first escape sequence. + If the string contains no escape sequences, return it right away. */ + for (;;) + { + while (cp[0] != '\0' && cp[0] != '\\') + ++cp; + if (cp[0] == '\0') + /* The argument string contains no escape sequence. */ + return str; + /* Found a backslash. */ + if (cp[1] == '\0') + return str; + if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL) + break; + ++cp; + } + + { + char *retval = XNMALLOC (strlen (str), char); + + memcpy (retval, str, cp - str); + { + char *rp = retval + (cp - str); + + do + { + /* Here cp[0] == '\\'. */ + switch (*++cp) + { + case 'a': /* alert */ + *rp++ = '\a'; + ++cp; + break; + case 'b': /* backspace */ + *rp++ = '\b'; + ++cp; + break; + case 'f': /* form feed */ + *rp++ = '\f'; + ++cp; + break; + case 'n': /* new line */ + *rp++ = '\n'; + ++cp; + break; + case 'r': /* carriage return */ + *rp++ = '\r'; + ++cp; + break; + case 't': /* horizontal tab */ + *rp++ = '\t'; + ++cp; + break; + case 'v': /* vertical tab */ + *rp++ = '\v'; + ++cp; + break; + case '\\': + *rp++ = '\\'; + ++cp; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + { + int ch = *cp++ - '0'; + + if (*cp >= '0' && *cp <= '7') + { + ch *= 8; + ch += *cp++ - '0'; + + if (*cp >= '0' && *cp <= '7') + { + ch *= 8; + ch += *cp++ - '0'; + } + } + *rp++ = ch; + } + break; + case 'c': + if (backslash_c_seen != NULL) + { + *backslash_c_seen = true; + ++cp; + break; + } + /* FALLTHROUGH */ + default: + *rp++ = '\\'; + break; + } + + /* Find the next escape sequence. */ + while (cp[0] != '\0' && cp[0] != '\\') + *rp++ = *cp++; + } + while (cp[0] != '\0'); + + /* Terminate the resulting string. */ + *rp = '\0'; + } + + return retval; + } +} diff --git a/gettext-runtime/src/gettext.c b/gettext-runtime/src/gettext.c index ac50ad4c7..95f4b735e 100644 --- a/gettext-runtime/src/gettext.c +++ b/gettext-runtime/src/gettext.c @@ -34,13 +34,14 @@ #include "basename.h" #include "xalloc.h" #include "propername.h" +#include "escapes.h" #include "gettext.h" #define _(str) gettext (str) -/* If true, add newline after last string. This makes only sense in +/* If false, add newline after last string. This makes only sense in the 'echo' emulation mode. */ -static bool add_newline; +static bool inhibit_added_newline; /* If true, expand escape sequences in strings before looking in the message catalog. */ @@ -63,7 +64,6 @@ static void usage (int status) __attribute__ ((noreturn)) #endif ; -static const char *expand_escape (const char *str); int main (int argc, char *argv[]) @@ -78,7 +78,7 @@ main (int argc, char *argv[]) const char *domain = getenv ("TEXTDOMAIN"); const char *domaindir = getenv ("TEXTDOMAINDIR"); const char *context = NULL; - add_newline = true; + inhibit_added_newline = false; do_expand = false; /* Set program name for message texts. */ @@ -117,7 +117,7 @@ main (int argc, char *argv[]) do_help = true; break; case 'n': - add_newline = false; + inhibit_added_newline = true; break; case 's': do_shell = true; @@ -175,7 +175,7 @@ There is NO WARRANTY, to the extent permitted by law.\n\ /* Expand escape sequences if enabled. */ if (do_expand) - msgid = expand_escape (msgid); + msgid = expand_escapes (msgid, &inhibit_added_newline); /* If no domain name is given we don't translate. */ if (domain == NULL || domain[0] == '\0') @@ -215,7 +215,7 @@ There is NO WARRANTY, to the extent permitted by law.\n\ /* Expand escape sequences if enabled. */ if (do_expand) - msgid = expand_escape (msgid); + msgid = expand_escapes (msgid, &inhibit_added_newline); /* Write out the result. */ fputs ((domain == NULL ? msgid : @@ -232,7 +232,7 @@ There is NO WARRANTY, to the extent permitted by law.\n\ } /* If not otherwise told: add trailing newline. */ - if (add_newline) + if (!inhibit_added_newline) fputc ('\n', stdout); } @@ -307,109 +307,3 @@ or by email to <%s>.\n"), exit (status); } - - -/* Expand some escape sequences found in the argument string. */ -static const char * -expand_escape (const char *str) -{ - char *retval, *rp; - const char *cp = str; - - /* Find the location of the first escape sequence. - If the string contains no escape sequences, return it right away. */ - for (;;) - { - while (cp[0] != '\0' && cp[0] != '\\') - ++cp; - if (cp[0] == '\0') - return str; - /* Found a backslash. */ - if (cp[1] == '\0') - return str; - if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL) - break; - ++cp; - } - - retval = XNMALLOC (strlen (str), char); - - rp = retval + (cp - str); - memcpy (retval, str, cp - str); - - do - { - /* Here cp[0] == '\\'. */ - switch (*++cp) - { - case 'a': /* alert */ - *rp++ = '\a'; - ++cp; - break; - case 'b': /* backspace */ - *rp++ = '\b'; - ++cp; - break; - case 'c': /* suppress trailing newline */ - add_newline = false; - ++cp; - break; - case 'f': /* form feed */ - *rp++ = '\f'; - ++cp; - break; - case 'n': /* new line */ - *rp++ = '\n'; - ++cp; - break; - case 'r': /* carriage return */ - *rp++ = '\r'; - ++cp; - break; - case 't': /* horizontal tab */ - *rp++ = '\t'; - ++cp; - break; - case 'v': /* vertical tab */ - *rp++ = '\v'; - ++cp; - break; - case '\\': - *rp++ = '\\'; - ++cp; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - { - int ch = *cp++ - '0'; - - if (*cp >= '0' && *cp <= '7') - { - ch *= 8; - ch += *cp++ - '0'; - - if (*cp >= '0' && *cp <= '7') - { - ch *= 8; - ch += *cp++ - '0'; - } - } - *rp++ = ch; - } - break; - default: - *rp++ = '\\'; - break; - } - - /* Find the next escape sequence. */ - while (cp[0] != '\0' && cp[0] != '\\') - *rp++ = *cp++; - } - while (cp[0] != '\0'); - - /* Terminate the resulting string. */ - *rp = '\0'; - - return retval; -} diff --git a/gettext-runtime/src/ngettext.c b/gettext-runtime/src/ngettext.c index 685bf7fbb..88a4c5c64 100644 --- a/gettext-runtime/src/ngettext.c +++ b/gettext-runtime/src/ngettext.c @@ -33,6 +33,7 @@ #include "basename.h" #include "xalloc.h" #include "propername.h" +#include "escapes.h" #include "gettext.h" #define _(str) gettext (str) @@ -57,7 +58,6 @@ static void usage (int status) __attribute__ ((noreturn)) #endif ; -static const char *expand_escape (const char *str); int main (int argc, char *argv[]) @@ -180,8 +180,8 @@ There is NO WARRANTY, to the extent permitted by law.\n\ /* Expand escape sequences if enabled. */ if (do_expand) { - msgid = expand_escape (msgid); - msgid_plural = expand_escape (msgid_plural); + msgid = expand_escapes (msgid, NULL); + msgid_plural = expand_escapes (msgid_plural, NULL); } /* If no domain name is given we don't translate, and we use English @@ -270,105 +270,3 @@ or by email to <%s>.\n"), exit (status); } - - -/* Expand some escape sequences found in the argument string. */ -static const char * -expand_escape (const char *str) -{ - char *retval, *rp; - const char *cp = str; - - /* Find the location of the first escape sequence. - If the string contains no escape sequences, return it right away. */ - for (;;) - { - while (cp[0] != '\0' && cp[0] != '\\') - ++cp; - if (cp[0] == '\0') - return str; - /* Found a backslash. */ - if (cp[1] == '\0') - return str; - if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL) - break; - ++cp; - } - - retval = XNMALLOC (strlen (str), char); - - rp = retval + (cp - str); - memcpy (retval, str, cp - str); - - do - { - /* Here cp[0] == '\\'. */ - switch (*++cp) - { - case 'a': /* alert */ - *rp++ = '\a'; - ++cp; - break; - case 'b': /* backspace */ - *rp++ = '\b'; - ++cp; - break; - case 'f': /* form feed */ - *rp++ = '\f'; - ++cp; - break; - case 'n': /* new line */ - *rp++ = '\n'; - ++cp; - break; - case 'r': /* carriage return */ - *rp++ = '\r'; - ++cp; - break; - case 't': /* horizontal tab */ - *rp++ = '\t'; - ++cp; - break; - case 'v': /* vertical tab */ - *rp++ = '\v'; - ++cp; - break; - case '\\': - *rp++ = '\\'; - ++cp; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - { - int ch = *cp++ - '0'; - - if (*cp >= '0' && *cp <= '7') - { - ch *= 8; - ch += *cp++ - '0'; - - if (*cp >= '0' && *cp <= '7') - { - ch *= 8; - ch += *cp++ - '0'; - } - } - *rp++ = ch; - } - break; - default: - *rp++ = '\\'; - break; - } - - /* Find the next escape sequence. */ - while (cp[0] != '\0' && cp[0] != '\\') - *rp++ = *cp++; - } - while (cp[0] != '\0'); - - /* Terminate the resulting string. */ - *rp = '\0'; - - return retval; -} diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am index 1ec1587a5..5b6c361af 100644 --- a/gettext-tools/src/Makefile.am +++ b/gettext-tools/src/Makefile.am @@ -188,9 +188,26 @@ xgettext_SOURCES += \ xg-mixed-string.c \ xg-arglist-context.c xg-arglist-callshape.c xg-arglist-parser.c \ xg-message.c \ - x-c.c x-po.c x-sh.c x-python.c x-lisp.c x-elisp.c x-librep.c x-scheme.c \ - x-smalltalk.c x-java.c x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c \ - x-rst.c x-lua.c x-javascript.c x-vala.c \ + x-c.c \ + x-po.c \ + x-sh.c ../../gettext-runtime/src/escapes.h \ + x-python.c \ + x-lisp.c \ + x-elisp.c \ + x-librep.c \ + x-scheme.c \ + x-smalltalk.c \ + x-java.c \ + x-csharp.c \ + x-awk.c \ + x-ycp.c \ + x-tcl.c \ + x-perl.c \ + x-php.c \ + x-rst.c \ + x-lua.c \ + x-javascript.c \ + x-vala.c \ x-desktop.c if !WOE32DLL msgattrib_SOURCES = msgattrib.c diff --git a/gettext-tools/src/x-sh.c b/gettext-tools/src/x-sh.c index dcfd7895a..2470bf190 100644 --- a/gettext-tools/src/x-sh.c +++ b/gettext-tools/src/x-sh.c @@ -41,6 +41,7 @@ #include "error-progname.h" #include "xalloc.h" #include "hash.h" +#include "../../gettext-runtime/src/escapes.h" #include "gettext.h" #define _(s) gettext(s) @@ -1241,6 +1242,8 @@ read_command (int looking_for, flag_context_ty outer_context) command. */ int arg = 0; /* Current argument number. */ bool arg_of_redirect = false; /* True right after a redirection operator. */ + bool must_expand_arg_strings = false; /* True if need to expand escape + sequences in arguments. */ flag_context_list_iterator_ty context_iter; const struct callshapes *shapes = NULL; struct arglist_parser *argparser = NULL; @@ -1336,6 +1339,11 @@ read_command (int looking_for, flag_context_ty outer_context) && memcmp (argparser->keyword, "gettext", 7) == 0) || (argparser->keyword_len == 8 && memcmp (argparser->keyword, "ngettext", 8) == 0)); + bool accepts_expand = + ((argparser->keyword_len == 7 + && memcmp (argparser->keyword, "gettext", 7) == 0) + || (argparser->keyword_len == 8 + && memcmp (argparser->keyword, "ngettext", 8) == 0)); if (accepts_context && argparser->next_is_msgctxt) { char *s = string_of_word (&inner); @@ -1377,13 +1385,38 @@ read_command (int looking_for, flag_context_ty outer_context) inner.line_number_at_start); matters_for_argparser = false; } + else if (accepts_expand + && inner.token->charcount == 2 + && memcmp (inner.token->chars, "-e", 2) == 0) + { + must_expand_arg_strings = true; + matters_for_argparser = false; + } else { char *s = string_of_word (&inner); - mixed_string_ty *ms = - mixed_string_alloc_simple (s, lc_string, - logical_file_name, - inner.line_number_at_start); + mixed_string_ty *ms; + + /* When '-e' was specified, expand escape sequences in s. */ + if (accepts_expand && must_expand_arg_strings) + { + bool expands_backslash_c = + (argparser->keyword_len == 7 + && memcmp (argparser->keyword, "gettext", 7) == 0); + bool backslash_c = false; + char *expanded = + (char *) + expand_escapes (s, expands_backslash_c ? &backslash_c : NULL); + /* We can ignore the value of expands_backslash_c, because + here we don't support the gettext '-s' option. */ + if (expanded != s) + free (s); + s = expanded; + } + + ms = mixed_string_alloc_simple (s, lc_string, + logical_file_name, + inner.line_number_at_start); free (s); arglist_parser_remember (argparser, arg, ms, inner_context, diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am index b200aa342..77e710007 100644 --- a/gettext-tools/tests/Makefile.am +++ b/gettext-tools/tests/Makefile.am @@ -234,7 +234,9 @@ LDADD = $(LDADD_@USE_INCLUDED_LIBINTL@) @INTL_MACOSX_LIBS@ LDADD_yes = ../intl/libintl.la @LTLIBTHREAD@ LDADD_no = ../intl/libgnuintl.la @LTLIBTHREAD@ @LTLIBINTL@ check_PROGRAMS = tstgettext tstngettext testlocale intl-1-prg intl-3-prg intl-4-prg intl-5-prg intl-setlocale-1-prg intl-setlocale-2-prg intl-thread-1-prg intl-thread-2-prg intl-thread-3-prg intl-version-prg cake fc3 fc4 fc5 gettextpo-1-prg sentence-1-prg -tstgettext_SOURCES = tstgettext.c setlocale.c +tstgettext_SOURCES = \ + tstgettext.c ../../gettext-runtime/src/escapes.h \ + setlocale.c tstgettext_CFLAGS = -DINSTALLDIR=\".\" tstgettext_LDADD = ../gnulib-lib/libgettextlib.la $(LDADD) tstngettext_SOURCES = tstngettext.c setlocale.c diff --git a/gettext-tools/tests/tstgettext.c b/gettext-tools/tests/tstgettext.c index 48fb92a5d..52ba1cea9 100644 --- a/gettext-tools/tests/tstgettext.c +++ b/gettext-tools/tests/tstgettext.c @@ -35,6 +35,7 @@ #include "xalloc.h" #include "propername.h" #include "xsetenv.h" +#include "../../gettext-runtime/src/escapes.h" /* Make sure we use the included libintl, not the system's one. */ #undef _LIBINTL_H @@ -42,9 +43,9 @@ #define _(str) gettext (str) -/* If true, add newline after last string. This makes only sense in +/* If false, add newline after last string. This makes only sense in the 'echo' emulation mode. */ -static bool add_newline; +static bool inhibit_added_newline; /* If true, expand escape sequences in strings before looking in the message catalog. */ @@ -67,7 +68,6 @@ static void usage (int status) __attribute__ ((noreturn)) #endif ; -static const char *expand_escape (const char *str); int main (int argc, char *argv[]) @@ -82,7 +82,7 @@ main (int argc, char *argv[]) bool environ_changed = false; const char *domain = getenv ("TEXTDOMAIN"); const char *domaindir = getenv ("TEXTDOMAINDIR"); - add_newline = true; + inhibit_added_newline = false; do_expand = false; /* Set program name for message texts. */ @@ -118,7 +118,7 @@ main (int argc, char *argv[]) do_help = true; break; case 'n': - add_newline = false; + inhibit_added_newline = true; break; case 's': do_shell = true; @@ -193,7 +193,7 @@ There is NO WARRANTY, to the extent permitted by law.\n\ /* Expand escape sequences if enabled. */ if (do_expand) - msgid = expand_escape (msgid); + msgid = expand_escapes (msgid, &inhibit_added_newline); /* If no domain name is given we don't translate. */ if (domain == NULL || domain[0] == '\0') @@ -230,7 +230,7 @@ There is NO WARRANTY, to the extent permitted by law.\n\ /* Expand escape sequences if enabled. */ if (do_expand) - msgid = expand_escape (msgid); + msgid = expand_escapes (msgid, &inhibit_added_newline); /* Write out the result. */ fputs (domain == NULL ? msgid : dgettext (domain, msgid), @@ -244,7 +244,7 @@ There is NO WARRANTY, to the extent permitted by law.\n\ } /* If not otherwise told: add trailing newline. */ - if (add_newline) + if (!inhibit_added_newline) fputc ('\n', stdout); } @@ -308,109 +308,3 @@ or by email to <%s>.\n"), exit (status); } - - -/* Expand some escape sequences found in the argument string. */ -static const char * -expand_escape (const char *str) -{ - char *retval, *rp; - const char *cp = str; - - /* Find the location of the first escape sequence. - If the string contains no escape sequences, return it right away. */ - for (;;) - { - while (cp[0] != '\0' && cp[0] != '\\') - ++cp; - if (cp[0] == '\0') - return str; - /* Found a backslash. */ - if (cp[1] == '\0') - return str; - if (strchr ("abcfnrtv\\01234567", cp[1]) != NULL) - break; - ++cp; - } - - retval = XNMALLOC (strlen (str), char); - - rp = retval + (cp - str); - memcpy (retval, str, cp - str); - - do - { - /* Here cp[0] == '\\'. */ - switch (*++cp) - { - case 'a': /* alert */ - *rp++ = '\a'; - ++cp; - break; - case 'b': /* backspace */ - *rp++ = '\b'; - ++cp; - break; - case 'c': /* suppress trailing newline */ - add_newline = false; - ++cp; - break; - case 'f': /* form feed */ - *rp++ = '\f'; - ++cp; - break; - case 'n': /* new line */ - *rp++ = '\n'; - ++cp; - break; - case 'r': /* carriage return */ - *rp++ = '\r'; - ++cp; - break; - case 't': /* horizontal tab */ - *rp++ = '\t'; - ++cp; - break; - case 'v': /* vertical tab */ - *rp++ = '\v'; - ++cp; - break; - case '\\': - *rp++ = '\\'; - ++cp; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - { - int ch = *cp++ - '0'; - - if (*cp >= '0' && *cp <= '7') - { - ch *= 8; - ch += *cp++ - '0'; - - if (*cp >= '0' && *cp <= '7') - { - ch *= 8; - ch += *cp++ - '0'; - } - } - *rp++ = ch; - } - break; - default: - *rp++ = '\\'; - break; - } - - /* Find the next escape sequence. */ - while (cp[0] != '\0' && cp[0] != '\\') - *rp++ = *cp++; - } - while (cp[0] != '\0'); - - /* Terminate the resulting string. */ - *rp = '\0'; - - return retval; -} diff --git a/gettext-tools/tests/xgettext-sh-1 b/gettext-tools/tests/xgettext-sh-1 index 4ace9a360..b7de75449 100755 --- a/gettext-tools/tests/xgettext-sh-1 +++ b/gettext-tools/tests/xgettext-sh-1 @@ -4,6 +4,20 @@ # Test of Shell support. cat <<\EOF > xg-sh-1.sh +# Test escape sequences expansion. + +gettext -e 'escape_0_\n' +gettext -e 'escape_1_\a' +gettext -e 'escape_2_\b' +gettext -e 'escape_3_\f' +gettext -e 'escape_4_\r' +gettext -e 'escape_5_\t' +gettext -e 'escape_6_\v' +gettext -e 'escape_7_\\\\z' +gettext -e 'escape_10_\40' +gettext -e 'escape_11_\044' +gettext -e 'escape_12_\140' + # Test backslash before normal alphabetic character. gettext depth_0_none_0_x @@ -472,6 +486,39 @@ ${XGETTEXT} --omit-header --no-location --keyword=ngettext:1 \ LC_ALL=C tr -d '\r' < xg-sh-1.tmp.po > xg-sh-1.po || Exit 1 cat <<\EOF > xg-sh-1.ok +msgid "escape_0_\n" +msgstr "" + +msgid "escape_1_\a" +msgstr "" + +msgid "escape_2_\b" +msgstr "" + +msgid "escape_3_\f" +msgstr "" + +msgid "escape_4_\r" +msgstr "" + +msgid "escape_5_\t" +msgstr "" + +msgid "escape_6_\v" +msgstr "" + +msgid "escape_7_\\\\z" +msgstr "" + +msgid "escape_10_ " +msgstr "" + +msgid "escape_11_$" +msgstr "" + +msgid "escape_12_`" +msgstr "" + msgid "depth_0_none_0_x" msgstr "" -- 2.47.2