#include <xalloc.h>
#include <ctype.h>
-#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
-# define ISASCII(c) 1
-#else
-# define ISASCII(c) isascii (c)
-#endif
-#define ISPRINT(c) (ISASCII (c) && isprint (c))
#if ENABLE_NLS
# include <libintl.h>
#else
# define _(text) text
#endif
+#define N_(text) text
#if HAVE_LIMITS_H
# include <limits.h>
# define UCHAR_MAX ((unsigned char) -1)
#endif
+#if HAVE_C_BACKSLASH_A
+# define ALERT_CHAR '\a'
+#else
+# define ALERT_CHAR '\7'
+#endif
+
#if HAVE_STDLIB_H
# include <stdlib.h>
#endif
# include <string.h>
#endif
-#if HAVE_MBRTOWC && HAVE_WCHAR_H
+#if HAVE_WCHAR_H
# include <wchar.h>
+#endif
+
+#if HAVE_MBRTOWC
+size_t mbrtowc ();
+# ifdef mbstate_t
+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
+# define mbsinit(ps) 1
+# endif
#else
-# define iswprint(wc) 1
-# define mbrtowc(pwc, s, n, ps) 1
+/* Disable multibyte processing entirely. Since MB_CUR_MAX is 1, the
+ other macros are defined only for documentation and to satisfy C
+ syntax. */
+# undef MB_CUR_MAX
+# define MB_CUR_MAX 1
+# define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
# define mbsinit(ps) 1
-# define mbstate_t int
+# define iswprint(wc) ISPRINT ((unsigned char) (wc))
+#endif
+
+#ifndef iswprint
+# if HAVE_WCTYPE_H
+# include <wctype.h>
+# endif
+# if !defined iswprint && !HAVE_ISWPRINT
+# define iswprint(wc) 1
+# endif
#endif
#define INT_BITS (sizeof (int) * CHAR_BIT)
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+/* Undefine to protect against the definition in wctype.h of solaris2.6. */
+#undef ISPRINT
+#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
+
struct quoting_options
{
/* Basic quoting style. */
/* Quote the characters indicated by this bit vector even if the
quoting style would not normally require them to be quoted. */
- int quote_these_too[((UCHAR_MAX + 1) / INT_BITS
- + ((UCHAR_MAX + 1) % INT_BITS != 0))];
+ int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
};
/* Names of quoting styles. */
"c",
"escape",
"locale",
+ "clocale",
0
};
shell_always_quoting_style,
c_quoting_style,
escape_quoting_style,
- locale_quoting_style
+ locale_quoting_style,
+ clocale_quoting_style
};
/* The default quoting options. */
return r;
}
+/* MSGID approximates a quotation mark. Return its translation if it
+ has one; otherwise, return either it or "\"", depending on S. */
+static char const *
+gettext_quote (char const *msgid, enum quoting_style s)
+{
+ char const *translation = _(msgid);
+ if (translation == msgid && s == clocale_quoting_style)
+ translation = "\"";
+ return translation;
+}
+
/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
argument ARG (of size ARGSIZE), using QUOTING_STYLE and the
non-quoting-style part of O to control quoting.
char const *quote_string = 0;
size_t quote_string_len = 0;
int backslash_escapes = 0;
+ int unibyte_locale = MB_CUR_MAX == 1;
#define STORE(c) \
do \
break;
case locale_quoting_style:
- for (quote_string = _("`"); *quote_string; quote_string++)
- STORE (*quote_string);
- backslash_escapes = 1;
- quote_string = _("'");
- quote_string_len = strlen (quote_string);
+ case clocale_quoting_style:
+ {
+ /* Get translations for open and closing quotation marks.
+
+ The message catalog should translate "`" to a left
+ quotation mark suitable for the locale, and similarly for
+ "'". If the catalog has no translation,
+ locale_quoting_style quotes `like this', and
+ clocale_quoting_style quotes "like this".
+
+ For example, an American English Unicode locale should
+ translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and
+ should translate "'" to U+201D (RIGHT DOUBLE QUOTATION
+ MARK). A British English Unicode locale should instead
+ translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and
+ U+2019 (RIGHT SINGLE QUOTATION MARK), respectively. */
+
+ char const *left = gettext_quote (N_("`"), quoting_style);
+ char const *right = gettext_quote (N_("'"), quoting_style);
+ for (quote_string = left; *quote_string; quote_string++)
+ STORE (*quote_string);
+ backslash_escapes = 1;
+ quote_string = right;
+ quote_string_len = strlen (quote_string);
+ }
break;
case shell_always_quoting_style:
}
break;
-#if HAVE_C_BACKSLASH_A
- case '\a': esc = 'a'; goto c_escape;
-#endif
+ case ALERT_CHAR: esc = 'a'; goto c_escape;
case '\b': esc = 'b'; goto c_escape;
case '\f': esc = 'f'; goto c_escape;
case '\n': esc = 'n'; goto c_and_shell_escape;
we can't easily escape single characters within it. */
{
/* Length of multibyte sequence found so far. */
- size_t m = 0;
+ size_t m;
- int printable = 1;
- mbstate_t mbstate;
- memset (&mbstate, 0, sizeof mbstate);
+ int printable;
- if (argsize == (size_t) -1)
- argsize = strlen (arg);
-
- do
+ if (unibyte_locale)
{
- wchar_t w;
- size_t bytes = mbrtowc (&w, &arg[i + m],
- argsize - (i + m), &mbstate);
- if (bytes == 0)
- break;
- else if (bytes == (size_t) -1)
- {
- printable = 0;
- break;
- }
- else if (bytes == (size_t) -2)
- {
- printable = 0;
- while (i + m < argsize && arg[i + m])
- m++;
- break;
- }
- else
- {
- if (! iswprint (w))
- printable = 0;
- m += bytes;
- }
+ m = 1;
+ printable = ISPRINT (c);
}
- while (! mbsinit (&mbstate));
-
- if (m <= 1)
+ else
{
- /* Escape a unibyte character like a multibyte
- sequence if using backslash escapes, and if the
- character is not printable. */
- m = backslash_escapes && ! ISPRINT (c);
- printable = 0;
+ mbstate_t mbstate;
+ memset (&mbstate, 0, sizeof mbstate);
+
+ m = 0;
+ printable = 1;
+ if (argsize == (size_t) -1)
+ argsize = strlen (arg);
+
+ do
+ {
+ wchar_t w;
+ size_t bytes = mbrtowc (&w, &arg[i + m],
+ argsize - (i + m), &mbstate);
+ if (bytes == 0)
+ break;
+ else if (bytes == (size_t) -1)
+ {
+ printable = 0;
+ break;
+ }
+ else if (bytes == (size_t) -2)
+ {
+ printable = 0;
+ while (i + m < argsize && arg[i + m])
+ m++;
+ break;
+ }
+ else
+ {
+ if (! iswprint (w))
+ printable = 0;
+ m += bytes;
+ }
+ }
+ while (! mbsinit (&mbstate));
}
- if (m)
+ if (1 < m || (backslash_escapes && ! printable))
{
/* Output a multibyte sequence, or an escaped
unprintable unibyte character. */
- size_t imax = i + m - 1;
+ size_t ilim = i + m;
for (;;)
{
STORE ('0' + ((c >> 3) & 7));
c = '0' + (c & 7);
}
- if (i == imax)
+ if (ilim <= i + 1)
break;
STORE (c);
c = arg[++i];
OPTIONS specifies the quoting options.
The returned value points to static storage that can be
reused by the next call to this function with the same value of N.
- N must be nonnegative. N is deliberately declared with type `int'
+ N must be nonnegative. N is deliberately declared with type "int"
to allow for future extensions (using negative values). */
static char *
quotearg_n_options (int n, char const *arg,
struct quoting_options const *options)
{
- static unsigned int nslots;
- static struct slotvec
+ /* Preallocate a slot 0 buffer, so that the caller can always quote
+ one small component of a "memory exhausted" message in slot 0. */
+ static char slot0[256];
+ static unsigned int nslots = 1;
+ struct slotvec
{
size_t size;
char *val;
- } *slotvec;
+ };
+ static struct slotvec slotvec0 = {sizeof slot0, slot0};
+ static struct slotvec *slotvec = &slotvec0;
if (nslots <= n)
{
size_t s = n1 * sizeof (struct slotvec);
if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
abort ();
+ if (slotvec == &slotvec0)
+ {
+ slotvec = (struct slotvec *) xmalloc (sizeof (struct slotvec));
+ *slotvec = slotvec0;
+ }
slotvec = (struct slotvec *) xrealloc (slotvec, s);
memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
nslots = n;
if (size <= qsize)
{
slotvec[n].size = size = qsize + 1;
- slotvec[n].val = val = xrealloc (val, size);
+ slotvec[n].val = val = xrealloc (val == slot0 ? 0 : val, size);
quotearg_buffer (val, size, arg, (size_t) -1, options);
}