From 74dd1966a5db708c66201bf952976ef27bd33e7e Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 7 Feb 2008 16:44:01 -0700 Subject: [PATCH] Quotearg part 3: add flag to control outer quote elision. * lib/quotearg.h (c_maybe_quoting_style): New style. (enum quoting_flags): Better documentation of flags. * lib/quotearg.c (quoting_style_args, quoting_style_vals): Add c-maybe style. (quotearg_buffer_restyled): Handle new flag to elide outer quotes. Signed-off-by: Eric Blake --- ChangeLog | 8 +++++ lib/quotearg.c | 110 ++++++++++++++++++++++++++++++++++++--------------------- lib/quotearg.h | 40 ++++++++++++++++----- 3 files changed, 109 insertions(+), 49 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3f2ed9ca1..2da06170e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2008-02-07 Eric Blake + Quotearg part 3: add flag to control outer quote elision. + * lib/quotearg.h (c_maybe_quoting_style): New style. + (enum quoting_flags): Better documentation of flags. + * lib/quotearg.c (quoting_style_args, quoting_style_vals): Add + c-maybe style. + (quotearg_buffer_restyled): Handle new flag to elide outer + quotes. + Quotearg part 2: add flag that can control NUL elision. * lib/quotearg.h (set_quoting_flags): New prototype. * lib/quotearg.c (struct quoting_options): Add flag field. diff --git a/lib/quotearg.c b/lib/quotearg.c index f9628e5fa..b6237b0ba 100644 --- a/lib/quotearg.c +++ b/lib/quotearg.c @@ -65,9 +65,7 @@ struct quoting_options /* 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 @@ -82,6 +80,7 @@ char const *const quoting_style_args[] = "shell", "shell-always", "c", + "c-maybe", "escape", "locale", "clocale", @@ -95,6 +94,7 @@ enum quoting_style const quoting_style_vals[] = shell_quoting_style, shell_always_quoting_style, c_quoting_style, + c_maybe_quoting_style, escape_quoting_style, locale_quoting_style, clocale_quoting_style @@ -149,10 +149,9 @@ 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) { @@ -200,6 +199,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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 \ @@ -212,8 +212,13 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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; @@ -221,6 +226,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, case escape_quoting_style: backslash_escapes = true; + elide_outer_quotes = false; break; case locale_quoting_style: @@ -248,22 +254,32 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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++) @@ -275,7 +291,11 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, && 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) @@ -283,20 +303,24 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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] == '?') @@ -307,6 +331,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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 ('?'); @@ -334,8 +360,10 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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) { @@ -365,24 +393,19 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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; @@ -454,7 +477,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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++) @@ -462,7 +486,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, { case '[': case '\\': case '^': case '`': case '|': - goto use_shell_always_quoting_style; + goto force_outer_quoting_style; default: break; @@ -487,6 +511,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, { if (backslash_escapes && ! printable) { + if (elide_outer_quotes) + goto force_outer_quoting_style; STORE ('\\'); STORE ('0' + (c >> 6)); STORE ('0' + ((c >> 3) & 7)); @@ -508,16 +534,19 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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); @@ -525,9 +554,10 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, 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 @@ -573,7 +603,7 @@ quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size, 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); @@ -663,9 +693,9 @@ quotearg_n_options (int n, char const *arg, size_t argsize, 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) { @@ -674,7 +704,7 @@ quotearg_n_options (int n, char const *arg, size_t argsize, 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; diff --git a/lib/quotearg.h b/lib/quotearg.h index 501c8561c..5d3ca4706 100644 --- a/lib/quotearg.h +++ b/lib/quotearg.h @@ -27,24 +27,34 @@ 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 @@ -56,6 +66,19 @@ enum quoting_style 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 @@ -90,10 +113,9 @@ void set_quoting_style (struct quoting_options *o, enum quoting_style s); 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 -- 2.11.0