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 *
}
/* 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
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;
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)
c = arg[i + 2];
i += 2;
STORE ('?');
- STORE ('\\');
+ STORE ('"');
+ STORE ('"');
STORE ('?');
break;
}
}
- 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:
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;
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
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;
}
/* 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;
/* 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)
{
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;
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)
{
# 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
};
--- /dev/null
+/* 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;
+}