/* Basic quoting style. */
enum quoting_style style;
- /* Additional flags. Behavior is altered according to these bits:
- 0x01: Elide null bytes rather than embed them unquoted.
- */
+ /* Additional flags. Bitwise combination of enum quoting_flags. */
int flags;
/* Quote the characters indicated by this bit vector even if the
"shell",
"shell-always",
"c",
+ "c-maybe",
"escape",
"locale",
"clocale",
shell_quoting_style,
shell_always_quoting_style,
c_quoting_style,
+ c_maybe_quoting_style,
escape_quoting_style,
locale_quoting_style,
clocale_quoting_style
}
/* In O (or in the default if O is null),
- set the value of the quoting options flag to I.
- Return the old value. Currently, the only values defined for I are
- 0 (the default) and 1 (which means to elide null bytes from styles
- that would otherwise output them unquoted). */
+ set the value of the quoting options flag to I, which can be a
+ bitwise combination of enum quoting_flags, or 0 for default
+ behavior. Return the old value. */
int
set_quoting_flags (struct quoting_options *o, int i)
{
size_t quote_string_len = 0;
bool backslash_escapes = false;
bool unibyte_locale = MB_CUR_MAX == 1;
+ bool elide_outer_quotes = (flags & QA_ELIDE_OUTER_QUOTES) != 0;
#define STORE(c) \
do \
switch (quoting_style)
{
+ case c_maybe_quoting_style:
+ quoting_style = c_quoting_style;
+ elide_outer_quotes = true;
+ /* Fall through. */
case c_quoting_style:
- STORE ('"');
+ if (!elide_outer_quotes)
+ STORE ('"');
backslash_escapes = true;
quote_string = "\"";
quote_string_len = 1;
case escape_quoting_style:
backslash_escapes = true;
+ elide_outer_quotes = false;
break;
case locale_quoting_style:
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);
+ if (!elide_outer_quotes)
+ for (quote_string = left; *quote_string; quote_string++)
+ STORE (*quote_string);
backslash_escapes = true;
quote_string = right;
quote_string_len = strlen (quote_string);
}
break;
+ case shell_quoting_style:
+ quoting_style = shell_always_quoting_style;
+ elide_outer_quotes = true;
+ /* Fall through. */
case shell_always_quoting_style:
- STORE ('\'');
+ if (!elide_outer_quotes)
+ STORE ('\'');
quote_string = "'";
quote_string_len = 1;
break;
- default:
+ case literal_quoting_style:
+ elide_outer_quotes = false;
break;
+
+ default:
+ abort ();
}
for (i = 0; ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize); i++)
&& quote_string_len
&& i + quote_string_len <= argsize
&& memcmp (arg + i, quote_string, quote_string_len) == 0)
- STORE ('\\');
+ {
+ if (elide_outer_quotes)
+ goto force_outer_quoting_style;
+ STORE ('\\');
+ }
c = arg[i];
switch (c)
case '\0':
if (backslash_escapes)
{
+ if (elide_outer_quotes)
+ goto force_outer_quoting_style;
STORE ('\\');
STORE ('0');
STORE ('0');
c = '0';
}
- else if (flags & 0x1)
+ else if (flags & QA_ELIDE_NULL_BYTES)
continue;
break;
case '?':
switch (quoting_style)
{
- case shell_quoting_style:
- goto use_shell_always_quoting_style;
+ case shell_always_quoting_style:
+ if (elide_outer_quotes)
+ goto force_outer_quoting_style;
+ break;
case c_quoting_style:
if (i + 2 < argsize && arg[i + 1] == '?')
case '<': case '=': case '>':
/* Escape the second '?' in what would otherwise be
a trigraph. */
+ if (elide_outer_quotes)
+ goto force_outer_quoting_style;
c = arg[i + 2];
i += 2;
STORE ('?');
case '\\': esc = c; goto c_and_shell_escape;
c_and_shell_escape:
- if (quoting_style == shell_quoting_style)
- goto use_shell_always_quoting_style;
+ if (quoting_style == shell_always_quoting_style
+ && elide_outer_quotes)
+ goto force_outer_quoting_style;
+ /* Fall through. */
c_escape:
if (backslash_escapes)
{
be the first bytes of multibyte characters, which means
we should check them with mbrtowc, but in practice this
doesn't happen so it's not worth worrying about. */
- if (quoting_style == shell_quoting_style)
- goto use_shell_always_quoting_style;
+ if (quoting_style == shell_always_quoting_style
+ && elide_outer_quotes)
+ goto force_outer_quoting_style;
break;
case '\'':
- switch (quoting_style)
+ if (quoting_style == shell_always_quoting_style)
{
- case shell_quoting_style:
- goto use_shell_always_quoting_style;
-
- case shell_always_quoting_style:
+ if (elide_outer_quotes)
+ goto force_outer_quoting_style;
STORE ('\'');
STORE ('\\');
STORE ('\'');
- break;
-
- default:
- break;
}
break;
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)
+ if ('[' == 0x5b && elide_outer_quotes
+ && quoting_style == shell_always_quoting_style)
{
size_t j;
for (j = 1; j < bytes; j++)
{
case '[': case '\\': case '^':
case '`': case '|':
- goto use_shell_always_quoting_style;
+ goto force_outer_quoting_style;
default:
break;
{
if (backslash_escapes && ! printable)
{
+ if (elide_outer_quotes)
+ goto force_outer_quoting_style;
STORE ('\\');
STORE ('0' + (c >> 6));
STORE ('0' + ((c >> 3) & 7));
goto store_c;
store_escape:
+ if (elide_outer_quotes)
+ goto force_outer_quoting_style;
STORE ('\\');
store_c:
STORE (c);
}
- if (i == 0 && quoting_style == shell_quoting_style)
- goto use_shell_always_quoting_style;
+ if (i == 0 && quoting_style == shell_always_quoting_style
+ && elide_outer_quotes)
+ goto force_outer_quoting_style;
- if (quote_string)
+ if (quote_string && !elide_outer_quotes)
for (; *quote_string; quote_string++)
STORE (*quote_string);
buffer[len] = '\0';
return len;
- use_shell_always_quoting_style:
+ force_outer_quoting_style:
return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
- shell_always_quoting_style, flags, o);
+ quoting_style,
+ flags & ~QA_ELIDE_OUTER_QUOTES, o);
}
/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
struct quoting_options const *p = o ? o : &default_quoting_options;
int e = errno;
/* Elide embedded null bytes if we can't return a size. */
- int flags = p->flags | (size ? 0 : 0x1);
+ 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;
char *buf = xcharalloc (bufsize);
size_t size = sv[n].size;
char *val = sv[n].val;
/* 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,
- options->flags | 0x1, options);
+ options->style, flags, options);
if (size <= qsize)
{
free (val);
sv[n].val = val = xcharalloc (size);
quotearg_buffer_restyled (val, size, arg, argsize, options->style,
- options->flags | 0x1, options);
+ flags, options);
}
errno = e;
enum quoting_style
{
/* Output names as-is (ls --quoting-style=literal). Can result in
- embedded null bytes in some cases. */
+ embedded null bytes if QA_ELIDE_NULL_BYTES is not in
+ effect. */
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 in some cases. */
+ Can result in embedded null bytes if QA_ELIDE_NULL_BYTES is not
+ in effect. */
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 in some cases. */
+ 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. */
shell_always_quoting_style,
- /* Quote names as for a C language string (ls --quoting-style=c). */
+ /* 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. */
c_quoting_style,
/* Like c_quoting_style except omit the surrounding double-quote
- characters (ls --quoting-style=escape). */
+ characters if no quoted characters are encountered. */
+ c_maybe_quoting_style,
+
+ /* Like c_quoting_style except always omit the surrounding
+ double-quote characters (ls --quoting-style=escape). */
escape_quoting_style,
/* Like clocale_quoting_style, but quote `like this' instead of
clocale_quoting_style
};
+/* Flags for use in set_quoting_flags. */
+enum quoting_flags
+ {
+ /* Always elide null bytes from styles that do not quote them,
+ even when the length of the result is available to the
+ caller. */
+ QA_ELIDE_NULL_BYTES = 0x01,
+
+ /* Omit the surrounding quote characters if no escaped characters
+ are encountered. */
+ QA_ELIDE_OUTER_QUOTES = 0x02
+ };
+
/* For now, --quoting-style=literal is the default, but this may change. */
# ifndef DEFAULT_QUOTING_STYLE
# define DEFAULT_QUOTING_STYLE literal_quoting_style
int set_char_quoting (struct quoting_options *o, char c, int i);
/* In O (or in the default if O is null),
- set the value of the quoting options flag to I.
- Return the old value. Currently, the only values defined for I are
- 0 (the default) and 1 (which means to elide null bytes from styles
- that would otherwise output them unquoted). */
+ set the value of the quoting options flag to I, which can be a
+ bitwise combination of enum quoting_flags, or 0 for default
+ behavior. Return the old value. */
int set_quoting_flags (struct quoting_options *o, int i);
/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of