/* quotearg.c - quote arguments for output
- Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 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
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Paul Eggert <eggert@twinsun.com> */
# include <config.h>
#endif
-#if HAVE_STDDEF_H
-# include <stddef.h> /* For the definition of size_t on windows w/MSVC. */
-#endif
-#include <sys/types.h>
-#include <quotearg.h>
-#include <xalloc.h>
+#include "quotearg.h"
-#include <ctype.h>
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(text) gettext (text)
-#else
-# define _(text) text
-#endif
-#define N_(text) text
+#include "xalloc.h"
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#ifndef CHAR_BIT
-# define CHAR_BIT 8
-#endif
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-#ifndef UCHAR_MAX
-# define UCHAR_MAX ((unsigned char) -1)
-#endif
-#ifndef UINT_MAX
-# define UINT_MAX ((unsigned int) -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 <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
-#if HAVE_STRING_H
-# include <string.h>
-#endif
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
#if HAVE_WCHAR_H
# undef MB_CUR_MAX
# define MB_CUR_MAX 1
# define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
+# define iswprint(wc) isprint ((unsigned char) (wc))
+# undef HAVE_MBSINIT
+#endif
+
+#if !defined mbsinit && !HAVE_MBSINIT
# define mbsinit(ps) 1
-# define iswprint(wc) ISPRINT ((unsigned char) (wc))
#endif
#ifndef iswprint
# 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)
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
#endif
-/* Undefine to protect against the definition in wctype.h of solaris2.6. */
-#undef ISPRINT
-#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
+#define INT_BITS (sizeof (int) * CHAR_BIT)
struct quoting_options
{
/* 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 / INT_BITS) + 1];
+ unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
};
/* Names of quoting styles. */
struct quoting_options *
clone_quoting_options (struct quoting_options *o)
{
- struct quoting_options *p
- = (struct quoting_options *) xmalloc (sizeof (struct quoting_options));
+ int e = errno;
+ struct quoting_options *p = xmalloc (sizeof *p);
*p = *(o ? o : &default_quoting_options);
+ errno = e;
return p;
}
set_char_quoting (struct quoting_options *o, char c, int i)
{
unsigned char uc = c;
- int *p = (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
+ unsigned int *p =
+ (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
int shift = uc % INT_BITS;
int r = (*p >> shift) & 1;
*p ^= ((i & 1) ^ r) << shift;
size of the output, not counting the terminating null.
If BUFFERSIZE is too small to store the output string, return the
value that would have been returned had BUFFERSIZE been large enough.
- If ARGSIZE is -1, use the string length of the argument for ARGSIZE.
+ 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 instead of the quoting
size_t len = 0;
char const *quote_string = 0;
size_t quote_string_len = 0;
- int backslash_escapes = 0;
- int unibyte_locale = MB_CUR_MAX == 1;
+ bool backslash_escapes = false;
+ bool unibyte_locale = MB_CUR_MAX == 1;
#define STORE(c) \
do \
{
case c_quoting_style:
STORE ('"');
- backslash_escapes = 1;
+ backslash_escapes = true;
quote_string = "\"";
quote_string_len = 1;
break;
case escape_quoting_style:
- backslash_escapes = 1;
+ backslash_escapes = true;
break;
case locale_quoting_style:
char const *right = gettext_quote (N_("'"), quoting_style);
for (quote_string = left; *quote_string; quote_string++)
STORE (*quote_string);
- backslash_escapes = 1;
+ backslash_escapes = true;
quote_string = right;
quote_string_len = strlen (quote_string);
}
break;
}
- for (i = 0; ! (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize); i++)
+ for (i = 0; ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize); i++)
{
unsigned char c;
unsigned char esc;
case '<': case '=': case '>':
/* Escape the second '?' in what would otherwise be
a trigraph. */
- i += 2;
c = arg[i + 2];
+ i += 2;
STORE ('?');
STORE ('\\');
STORE ('?');
}
break;
- case ALERT_CHAR: esc = 'a'; goto c_escape;
+ case '\a': 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;
}
break;
+ case '{': case '}': /* sometimes special if isolated */
+ if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1))
+ break;
+ /* Fall through. */
case '#': case '~':
if (i != 0)
break;
case '!': /* special in bash */
case '"': case '$': case '&':
case '(': case ')': case '*': case ';':
- case '<': case '>': case '[':
+ case '<':
+ case '=': /* sometimes special in 0th or (with "set -k") later args */
+ case '>': case '[':
case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
case '`': case '|':
/* A shell special character. In theory, '$' and '`' could
case '%': case '+': case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9': case ':': case '=':
+ case '6': case '7': case '8': case '9': case ':':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
- case '{': case '}':
/* These characters don't cause problems, no matter what the
quoting style is. They cannot start multibyte sequences. */
break;
/* Length of multibyte sequence found so far. */
size_t m;
- int printable;
+ bool printable;
if (unibyte_locale)
{
m = 1;
- printable = ISPRINT (c);
+ printable = isprint (c) != 0;
}
else
{
memset (&mbstate, 0, sizeof mbstate);
m = 0;
- printable = 1;
- if (argsize == (size_t) -1)
+ printable = true;
+ if (argsize == SIZE_MAX)
argsize = strlen (arg);
do
break;
else if (bytes == (size_t) -1)
{
- printable = 0;
+ printable = false;
break;
}
else if (bytes == (size_t) -2)
{
- printable = 0;
+ printable = false;
while (i + m < argsize && arg[i + m])
m++;
break;
}
else
{
+ /* Work around a bug with older shells that "see" a '\'
+ that is really the 2nd byte of a multibyte character.
+ In practice the problem is limited to ASCII
+ chars >= '@' that are shell special chars. */
+ if ('[' == 0x5b && quoting_style == shell_quoting_style)
+ {
+ size_t j;
+ for (j = 1; j < bytes; j++)
+ switch (arg[i + m + j])
+ {
+ case '[': case '\\': case '^':
+ case '`': case '|':
+ goto use_shell_always_quoting_style;
+ }
+ }
+
if (! iswprint (w))
- printable = 0;
+ printable = false;
m += bytes;
}
}
STORE (c);
}
+ if (i == 0 && quoting_style == shell_quoting_style)
+ goto use_shell_always_quoting_style;
+
if (quote_string)
for (; *quote_string; quote_string++)
STORE (*quote_string);
size of the output, not counting the terminating null.
If BUFFERSIZE is too small to store the output string, return the
value that would have been returned had BUFFERSIZE been large enough.
- If ARGSIZE is -1, use the string length of the argument for ARGSIZE. */
+ If ARGSIZE is SIZE_MAX, use the string length of the argument for
+ ARGSIZE. */
size_t
quotearg_buffer (char *buffer, size_t buffersize,
char const *arg, size_t argsize,
struct quoting_options const *o)
{
struct quoting_options const *p = o ? o : &default_quoting_options;
- return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
- p->style, p);
+ int e = errno;
+ size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
+ p->style, p);
+ errno = e;
+ return r;
+}
+
+/* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
+ allocated storage containing the quoted string. */
+char *
+quotearg_alloc (char const *arg, size_t argsize,
+ struct quoting_options const *o)
+{
+ int e = errno;
+ size_t bufsize = quotearg_buffer (0, 0, arg, argsize, o) + 1;
+ char *buf = xmalloc (bufsize);
+ quotearg_buffer (buf, bufsize, arg, argsize, o);
+ errno = e;
+ return buf;
}
/* Use storage slot N to return a quoted version of argument ARG.
- ARG is of size ARGSIZE, but if that is -1, ARG is a null-terminated string.
+ ARG is of size ARGSIZE, but if that is SIZE_MAX, ARG is a
+ null-terminated string.
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.
quotearg_n_options (int n, char const *arg, size_t argsize,
struct quoting_options const *options)
{
+ int e = errno;
+
/* 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];
if (nslots <= n0)
{
unsigned int n1 = n0 + 1;
- size_t s = n1 * sizeof *slotvec;
- if (SIZE_MAX / UINT_MAX <= sizeof *slotvec
- && n1 != s / sizeof *slotvec)
+ if (xalloc_oversized (n1, sizeof *slotvec))
xalloc_die ();
if (slotvec == &slotvec0)
{
- slotvec = (struct slotvec *) xmalloc (sizeof *slotvec);
+ slotvec = xmalloc (sizeof *slotvec);
*slotvec = slotvec0;
}
- slotvec = (struct slotvec *) xrealloc (slotvec, s);
+ slotvec = xrealloc (slotvec, n1 * sizeof *slotvec);
memset (slotvec + nslots, 0, (n1 - nslots) * sizeof *slotvec);
nslots = n1;
}
if (size <= qsize)
{
slotvec[n].size = size = qsize + 1;
- slotvec[n].val = val = xrealloc (val == slot0 ? 0 : val, size);
+ if (val != slot0)
+ free (val);
+ slotvec[n].val = val = xmalloc (size);
quotearg_buffer (val, size, arg, argsize, options);
}
+ errno = e;
return val;
}
}
char *
quotearg_n (int n, char const *arg)
{
- return quotearg_n_options (n, arg, (size_t) -1, &default_quoting_options);
+ return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options);
}
char *
quotearg_n_style (int n, enum quoting_style s, char const *arg)
{
struct quoting_options const o = quoting_options_from_style (s);
- return quotearg_n_options (n, arg, (size_t) -1, &o);
+ return quotearg_n_options (n, arg, SIZE_MAX, &o);
}
char *
struct quoting_options options;
options = default_quoting_options;
set_char_quoting (&options, ch, 1);
- return quotearg_n_options (0, arg, (size_t) -1, &options);
+ return quotearg_n_options (0, arg, SIZE_MAX, &options);
}
char *