Mercurial > hg > octave-lyh > gnulib-hg
changeset 9700:f6f2dedca815
Quotearg part 4: add tests, fix c-maybe colon quoting.
* lib/quotearg.h: Improve documentation.
* lib/quotearg.c (quotearg_buffer_restyled): Don't add extra
escapes when adding outer quotes. When quoting trigraphs, use
valid C notation. When quoting NUL, omit extra characters if next
character is not digit. Alter prototype.
(quotearg_buffer, quotearg_alloc_mem, quotearg_n_options): Adjust
callers.
* modules/quotearg-tests: New module.
* tests/test-quotearg.c: New test.
Signed-off-by: Eric Blake <ebb9@byu.net>
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Tue, 12 Feb 2008 11:42:29 -0700 |
parents | cdc5f14da027 |
children | 69f562691d3c |
files | ChangeLog lib/quotearg.c lib/quotearg.h modules/quotearg-tests tests/test-quotearg.c |
diffstat | 5 files changed, 438 insertions(+), 37 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-02-12 Eric Blake <ebb9@byu.net> + + Quotearg part 4: add tests, fix c-maybe colon quoting. + * lib/quotearg.h: Improve documentation. + * lib/quotearg.c (quotearg_buffer_restyled): Don't add extra + escapes when adding outer quotes. When quoting trigraphs, use + valid C notation. When quoting NUL, omit extra characters if next + character is not digit. Alter prototype. + (quotearg_buffer, quotearg_alloc_mem, quotearg_n_options): Adjust + callers. + * modules/quotearg-tests: New module. + * tests/test-quotearg.c: New test. + 2008-02-07 Eric Blake <ebb9@byu.net> Quotearg part 3: add flag to control outer quote elision.
--- a/lib/quotearg.c +++ b/lib/quotearg.c @@ -163,6 +163,17 @@ return r; } +/* Return quoting options for STYLE, with no extra quoting. */ +static struct quoting_options +quoting_options_from_style (enum quoting_style style) +{ + struct quoting_options o; + o.style = style; + o.flags = 0; + memset (o.quote_these_too, 0, sizeof o.quote_these_too); + return o; +} + /* MSGID approximates a quotation mark. Return its translation if it has one; otherwise, return either it or "\"", depending on S. */ static char const * @@ -175,8 +186,8 @@ } /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of - argument ARG (of size ARGSIZE), using QUOTING_STYLE, FLAGS, and the - remaining part of O to control quoting. + argument ARG (of size ARGSIZE), using QUOTING_STYLE, FLAGS, and + QUOTE_THESE_TOO to control quoting. Terminate the output with a null character, and return the written size of the output, not counting the terminating null. If BUFFERSIZE is too small to store the output string, return the @@ -184,14 +195,14 @@ If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE. This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG, - ARGSIZE, O), except it uses QUOTING_STYLE and FLAGS instead of the - quoting style specified by O, and O may not be null. */ + ARGSIZE, O), except it breaks O into its component pieces and is + not careful about errno. */ static size_t quotearg_buffer_restyled (char *buffer, size_t buffersize, char const *arg, size_t argsize, enum quoting_style quoting_style, int flags, - struct quoting_options const *o) + unsigned int *quote_these_too) { size_t i; size_t len = 0; @@ -306,8 +317,11 @@ if (elide_outer_quotes) goto force_outer_quoting_style; STORE ('\\'); - STORE ('0'); - STORE ('0'); + if (i + 1 < argsize && '0' <= arg[i + 1] && arg[i + 1] <= '9') + { + STORE ('0'); + STORE ('0'); + } c = '0'; } else if (flags & QA_ELIDE_NULL_BYTES) @@ -336,7 +350,8 @@ c = arg[i + 2]; i += 2; STORE ('?'); - STORE ('\\'); + STORE ('"'); + STORE ('"'); STORE ('?'); break; @@ -529,8 +544,9 @@ } } - if (! (backslash_escapes - && o->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))) + if (! ((backslash_escapes || elide_outer_quotes) + && quote_these_too + && quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))) goto store_c; store_escape: @@ -542,7 +558,7 @@ STORE (c); } - if (i == 0 && quoting_style == shell_always_quoting_style + if (len == 0 && quoting_style == shell_always_quoting_style && elide_outer_quotes) goto force_outer_quoting_style; @@ -555,9 +571,11 @@ return len; force_outer_quoting_style: + /* Don't reuse quote_these_too, since the addition of outer quotes + sufficiently quotes the specified characters. */ return quotearg_buffer_restyled (buffer, buffersize, arg, argsize, quoting_style, - flags & ~QA_ELIDE_OUTER_QUOTES, o); + flags & ~QA_ELIDE_OUTER_QUOTES, NULL); } /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of @@ -577,7 +595,7 @@ struct quoting_options const *p = o ? o : &default_quoting_options; int e = errno; size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize, - p->style, p->flags, p); + p->style, p->flags, p->quote_these_too); errno = e; return r; } @@ -605,9 +623,10 @@ /* Elide embedded null bytes if we can't return a size. */ int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES); size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style, - flags, p) + 1; + flags, p->quote_these_too) + 1; char *buf = xcharalloc (bufsize); - quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags, p); + quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags, + p->quote_these_too); errno = e; if (size) *size = bufsize - 1; @@ -695,7 +714,8 @@ /* Elide embedded null bytes since we don't return a size. */ int flags = options->flags | QA_ELIDE_NULL_BYTES; size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize, - options->style, flags, options); + options->style, flags, + options->quote_these_too); if (size <= qsize) { @@ -704,7 +724,7 @@ free (val); sv[n].val = val = xcharalloc (size); quotearg_buffer_restyled (val, size, arg, argsize, options->style, - flags, options); + flags, options->quote_these_too); } errno = e; @@ -736,17 +756,6 @@ return quotearg_n_mem (0, arg, argsize); } -/* Return quoting options for STYLE, with no extra quoting. */ -static struct quoting_options -quoting_options_from_style (enum quoting_style style) -{ - struct quoting_options o; - o.style = style; - o.flags = 0; - memset (o.quote_these_too, 0, sizeof o.quote_these_too); - return o; -} - char * quotearg_n_style (int n, enum quoting_style s, char const *arg) {
--- a/lib/quotearg.h +++ b/lib/quotearg.h @@ -23,46 +23,141 @@ # include <stddef.h> -/* Basic quoting styles. */ +/* Basic quoting styles. For each style, an example is given on the + input strings "simple", "\0 \t\n'\"\033?""?/\\", and "a:b", using + quotearg_buffer, quotearg_mem, and quotearg_colon_mem with that + style and the default flags and quoted characters. Note that the + examples are shown here as valid C strings rather than what + displays on a terminal (with "??/" as a trigraph for "\\"). */ enum quoting_style { /* Output names as-is (ls --quoting-style=literal). Can result in embedded null bytes if QA_ELIDE_NULL_BYTES is not in - effect. */ + effect. + + quotearg_buffer: + "simple", "\0 \t\n'\"\033??/\\", "a:b" + quotearg: + "simple", " \t\n'\"\033??/\\", "a:b" + quotearg_colon: + "simple", " \t\n'\"\033??/\\", "a:b" + */ literal_quoting_style, /* Quote names for the shell if they contain shell metacharacters or would cause ambiguous output (ls --quoting-style=shell). Can result in embedded null bytes if QA_ELIDE_NULL_BYTES is not - in effect. */ + in effect. + + quotearg_buffer: + "simple", "'\0 \t\n'\\''\"\033??/\\'", "a:b" + quotearg: + "simple", "' \t\n'\\''\"\033??/\\'", "a:b" + quotearg_colon: + "simple", "' \t\n'\\''\"\033??/\\'", "'a:b'" + */ shell_quoting_style, /* Quote names for the shell, even if they would normally not require quoting (ls --quoting-style=shell-always). Can result in embedded null bytes if QA_ELIDE_NULL_BYTES is not in effect. Behaves like shell_quoting_style if QA_ELIDE_OUTER_QUOTES is in - effect. */ + effect. + + quotearg_buffer: + "'simple'", "'\0 \t\n'\\''\"\033??/\\'", "'a:b'" + quotearg: + "'simple'", "' \t\n'\\''\"\033??/\\'", "'a:b'" + quotearg_colon: + "'simple'", "' \t\n'\\''\"\033??/\\'", "'a:b'" + */ shell_always_quoting_style, /* Quote names as for a C language string (ls --quoting-style=c). Behaves like c_maybe_quoting_style if QA_ELIDE_OUTER_QUOTES is - in effect. */ + in effect. + + quotearg_buffer: + "\"simple\"", "\"\\0 \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"" + quotearg: + "\"simple\"", "\"\\0 \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"" + quotearg_colon: + "\"simple\"", "\"\\0 \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a\\:b\"" + */ c_quoting_style, /* Like c_quoting_style except omit the surrounding double-quote - characters if no quoted characters are encountered. */ + characters if no quoted characters are encountered. + + quotearg_buffer: + "simple", "\"\\0 \\t\\n'\\\"\\033?\"\"?/\\\\\"", "a:b" + quotearg: + "simple", "\"\\0 \\t\\n'\\\"\\033?\"\"?/\\\\\"", "a:b" + quotearg_colon: + "simple", "\"\\0 \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"" + */ c_maybe_quoting_style, /* Like c_quoting_style except always omit the surrounding - double-quote characters (ls --quoting-style=escape). */ + double-quote characters and don't worry about trigraphs (ls + --quoting-style=escape). + + quotearg_buffer: + "simple", "\\0 \\t\\n'\"\\033??/\\\\", "a:b" + quotearg: + "simple", "\\0 \\t\\n'\"\\033??/\\\\", "a:b" + quotearg_colon: + "simple", "\\0 \\t\\n'\"\\033??/\\\\", "a\\:b" + */ escape_quoting_style, /* Like clocale_quoting_style, but quote `like this' instead of - "like this" in the default C locale (ls --quoting-style=locale). */ + "like this" in the default C locale (ls --quoting-style=locale). + + LC_MESSAGES=C + quotearg_buffer: + "`simple'", "`\\0 \\t\\n\\'\"\\033??/\\\\'", "`a:b'" + quotearg: + "`simple'", "`\\0 \\t\\n\\'\"\\033??/\\\\'", "`a:b'" + quotearg_colon: + "`simple'", "`\\0 \\t\\n\\'\"\\033??/\\\\'", "`a\\:b'" + + LC_MESSAGES=pt_PT.utf8 + quotearg_buffer: + "\302\253simple\302\273", + "\302\253\\0 \\t\\n'\"\\033??/\\\\\302\253", "\302\253a:b\302\273" + quotearg: + "\302\253simple\302\273", + "\302\253\\0 \\t\\n'\"\\033??/\\\\\302\253", "\302\253a:b\302\273" + quotearg_colon: + "\302\253simple\302\273", + "\302\253\\0 \\t\\n'\"\\033??/\\\\\302\253", "\302\253a\\:b\302\273" + */ locale_quoting_style, /* Like c_quoting_style except use quotation marks appropriate for - the locale (ls --quoting-style=clocale). */ + the locale and don't worry about trigraphs (ls + --quoting-style=clocale). + + LC_MESSAGES=C + quotearg_buffer: + "\"simple\"", "\"\\0 \\t\\n'\\\"\\033??/\\\\\"", "\"a:b\"" + quotearg: + "\"simple\"", "\"\\0 \\t\\n'\\\"\\033??/\\\\\"", "\"a:b\"" + quotearg_colon: + "\"simple\"", "\"\\0 \\t\\n'\\\"\\033??/\\\\\"", "\"a\\:b\"" + + LC_MESSAGES=pt_PT.utf8 + quotearg_buffer: + "\302\253simple\302\273", + "\302\253\\0 \\t\\n'\"\\033??/\\\\\302\253", "\302\253a:b\302\273" + quotearg: + "\302\253simple\302\273", + "\302\253\\0 \\t\\n'\"\\033??/\\\\\302\253", "\302\253a:b\302\273" + quotearg_colon: + "\302\253simple\302\273", + "\302\253\\0 \\t\\n'\"\\033??/\\\\\302\253", "\302\253a\\:b\302\273" + */ clocale_quoting_style };
new file mode 100644 --- /dev/null +++ b/modules/quotearg-tests @@ -0,0 +1,12 @@ +Files: +tests/test-quotearg.c + +Depends-on: +progname +stdint + +configure.ac: + +Makefile.am: +TESTS += test-quotearg +check_PROGRAMS += test-quotearg
new file mode 100644 --- /dev/null +++ b/tests/test-quotearg.c @@ -0,0 +1,272 @@ +/* Test of quotearg family of functions. + Copyright (C) 2008 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 + the Free Software Foundation; either version 3, 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, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2008. */ + +#include <config.h> + +#include "quotearg.h" + +#include <ctype.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if ENABLE_NLS +# include <libintl.h> + +/* These quotes are borrowed from a pt_PT.utf8 translation. */ +# define LQ "\302\253" +# define RQ "\302\273" +#endif + +#define ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + abort (); \ + } \ + } \ + while (0) + +struct result_strings { + char const *str1; /* Translation of "". */ + char const *str2; /* Translation of "\0""1\0". */ + size_t len2; /* Length of str2. */ + char const *str3; /* Translation of "simple". */ + char const *str4; /* Translation of " \t\n'\"\033?""?/\\". */ + char const *str5; /* Translation of "a:b". */ +}; + +struct result_groups { + struct result_strings group1; /* Via quotearg_buffer. */ + struct result_strings group2; /* Via quotearg{,_mem}. */ + struct result_strings group3; /* Via quotearg_colon{,_mem}. */ +}; + +static struct result_strings inputs = { + "", "\0001\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b" +}; + +static struct result_groups results[] = { + /* literal_quoting_style */ + { { "", "\0""1\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b" }, + { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b" }, + { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b" } }, + + /* shell_quoting_style */ + { { "''", "\0""1\0", 3, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b" }, + { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b" }, + { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "'a:b'" } }, + + /* shell_always_quoting_style */ + { { "''", "'\0""1\0'", 5, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'" }, + { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'" }, + { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'" } }, + + /* c_quoting_style */ + { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"", + "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"" }, + { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"", + "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"" }, + { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"", + "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a\\:b\"" } }, + + /* c_maybe_quoting_style */ + { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", + "a:b" }, + { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", + "a:b" }, + { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", + "\"a:b\"" } }, + + /* escape_quoting_style */ + { { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b" }, + { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b" }, + { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a\\:b" } }, + + /* locale_quoting_style */ + { { "`'", "`\\0001\\0'", 9, "`simple'", "` \\t\\n\\'\"\\033?""?/\\\\'", + "`a:b'" }, + { "`'", "`\\0001\\0'", 9, "`simple'", "` \\t\\n\\'\"\\033?""?/\\\\'", + "`a:b'" }, + { "`'", "`\\0001\\0'", 9, "`simple'", "` \\t\\n\\'\"\\033?""?/\\\\'", + "`a\\:b'" } }, + + /* clocale_quoting_style */ + { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"", + "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"" }, + { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"", + "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"" }, + { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"", + "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"" } } +}; + +#if ENABLE_NLS +static struct result_groups locale_results[] = { + /* locale_quoting_style */ + { { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ, + LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ }, + { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ, + LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ }, + { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ, + LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a\\:b" RQ } }, + + /* clocale_quoting_style */ + { { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ, + LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ }, + { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ, + LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ }, + { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ, + LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a\\:b" RQ } } +}; +#endif /* ENABLE_NLS */ + +static void +compare (char const *a, size_t la, char const *b, size_t lb) +{ + ASSERT (la == lb); + ASSERT (memcmp (a, b, la) == 0); + ASSERT (b[lb] == '\0'); +} + +static void +compare_strings (char *(func) (char const *, size_t *), + struct result_strings *results) +{ + size_t len; + char *p; + + len = 0; + p = func (inputs.str1, &len); + compare (results->str1, strlen (results->str1), p, len); + + len = inputs.len2; + p = func (inputs.str2, &len); + compare (results->str2, results->len2, p, len); + + len = SIZE_MAX; + p = func (inputs.str3, &len); + compare (results->str3, strlen (results->str3), p, len); + + len = strlen (inputs.str4); + p = func (inputs.str4, &len); + compare (results->str4, strlen (results->str4), p, len); + + len = SIZE_MAX; + p = func (inputs.str5, &len); + compare (results->str5, strlen (results->str5), p, len); +} + +static char * +use_quotearg_buffer (const char *str, size_t *len) +{ + static char buf[100]; + size_t size; + memset (buf, 0xa5, 100); + size = quotearg_buffer (buf, 100, str, *len, NULL); + *len = size; + ASSERT ((unsigned char) buf[size + 1] == 0xa5); + return buf; +} + +static char * +use_quotearg (const char *str, size_t *len) +{ + char *p = *len == SIZE_MAX ? quotearg (str) : quotearg_mem (str, *len); + *len = strlen (p); + return p; +} + +static char * +use_quotearg_colon (const char *str, size_t *len) +{ + char *p = (*len == SIZE_MAX ? quotearg_colon (str) + : quotearg_colon_mem (str, *len)); + *len = strlen (p); + return p; +} + +#if ENABLE_NLS +/* True if the locale should be faked. */ +static bool fake_locale; + +/* A replacement gettext that allows testing of locale quotes without + requiring a locale. */ +char * +gettext (char const *str) +{ + if (fake_locale) + { + static char lq[] = LQ; + static char rq[] = RQ; + if (strcmp (str, "`") == 0) + return lq; + if (strcmp (str, "'") == 0) + return rq; + } + return (char *) str; +} + +char * +dgettext (char const *d, char const *str) +{ + return gettext (str); +} +#endif /* ENABLE_NLS */ + +int +main (int argc, char **argv) +{ + int i; + + /* This program is hard-wired to the C locale since it does not call + setlocale. */ + ASSERT (!isprint ('\033')); + for (i = literal_quoting_style; i <= clocale_quoting_style; i++) + { + set_quoting_style (NULL, i); + compare_strings (use_quotearg_buffer, &results[i].group1); + compare_strings (use_quotearg, &results[i].group2); + compare_strings (use_quotearg_colon, &results[i].group3); + } + +#if ENABLE_NLS + /* Rather than change locales, and require a .gmo file with + translations for "`" and "'" that match our expectations, we + merely override the gettext function to satisfy the link + dependencies of quotearg.c. */ + fake_locale = true; + + set_quoting_style (NULL, locale_quoting_style); + compare_strings (use_quotearg_buffer, &locale_results[0].group1); + compare_strings (use_quotearg, &locale_results[0].group2); + compare_strings (use_quotearg_colon, &locale_results[0].group3); + + set_quoting_style (NULL, clocale_quoting_style); + compare_strings (use_quotearg_buffer, &locale_results[1].group1); + compare_strings (use_quotearg, &locale_results[1].group2); + compare_strings (use_quotearg_colon, &locale_results[1].group3); +#endif /* ENABLE_NLS */ + + quotearg_free (); + return 0; +}