X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fquotearg.c;h=75fbc72f3d5174559161bdd35b9237d777dc9830;hb=56093e4d947bcc87bbc05ac3e8645509274f57b4;hp=f9628e5fa743e43f5c2d69cc03c69337c7afae5f;hpb=71e66c91f3e83d361242fabfb41155e38114369d;p=gnulib.git diff --git a/lib/quotearg.c b/lib/quotearg.c index f9628e5fa..75fbc72f3 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) { @@ -164,6 +163,17 @@ set_quoting_flags (struct quoting_options *o, int i) 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 * @@ -176,8 +186,8 @@ gettext_quote (char const *msgid, enum quoting_style s) } /* 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 @@ -185,14 +195,14 @@ gettext_quote (char const *msgid, enum quoting_style s) 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 const *quote_these_too) { size_t i; size_t len = 0; @@ -200,6 +210,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 +223,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 +237,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 +265,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 +302,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,23 +314,31 @@ 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'); + if (i + 1 < argsize && '0' <= arg[i + 1] && arg[i + 1] <= '9') + { + 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] == '?') + if ((flags & QA_SPLIT_TRIGRAPHS) + && i + 2 < argsize && arg[i + 1] == '?') switch (arg[i + 2]) { case '!': case '\'': @@ -307,10 +346,13 @@ 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 ('?'); - STORE ('\\'); + STORE ('"'); + STORE ('"'); STORE ('?'); break; @@ -331,11 +373,17 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, case '\r': esc = 'r'; goto c_and_shell_escape; case '\t': esc = 't'; goto c_and_shell_escape; case '\v': esc = 'v'; goto c_escape; - case '\\': esc = c; goto c_and_shell_escape; + case '\\': esc = c; + /* No need to escape the escape if we are trying to elide + outer quotes and nothing else is problematic. */ + if (backslash_escapes && elide_outer_quotes && quote_string_len) + goto store_c; 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 +413,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 +497,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 +506,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 +531,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)); @@ -503,21 +549,25 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, } } - 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: + 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 (len == 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 +575,12 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize, buffer[len] = '\0'; return len; - use_shell_always_quoting_style: + 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, - shell_always_quoting_style, flags, o); + quoting_style, + flags & ~QA_ELIDE_OUTER_QUOTES, NULL); } /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of @@ -547,7 +600,7 @@ quotearg_buffer (char *buffer, size_t buffersize, 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; } @@ -573,11 +626,12 @@ 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; + 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; @@ -663,9 +717,10 @@ 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->quote_these_too); if (size <= qsize) { @@ -674,7 +729,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->quote_these_too); } errno = e; @@ -706,17 +761,6 @@ quotearg_mem (char const *arg, size_t argsize) 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) {