X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fquotearg.c;h=75fbc72f3d5174559161bdd35b9237d777dc9830;hb=c70a54e290ea07f2ac94169b15aa1919dcb28028;hp=0ad8da893ce42547c085975ca32782d455d6c825;hpb=44fa0d78ad36205f393cd4aa4813d1e7a403d6dc;p=gnulib.git diff --git a/lib/quotearg.c b/lib/quotearg.c index 0ad8da893..75fbc72f3 100644 --- a/lib/quotearg.c +++ b/lib/quotearg.c @@ -1,12 +1,12 @@ /* quotearg.c - quote arguments for output - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free - Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, + 2008 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + 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 - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,8 +14,7 @@ GNU General Public License for more details. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ /* Written by Paul Eggert */ @@ -31,20 +30,13 @@ #include #include #include +#include +#include #include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) msgid -#if HAVE_WCHAR_H - -/* BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared. */ -# include -# include - -# include -#endif - #if !HAVE_MBRTOWC /* Disable multibyte processing entirely. Since MB_CUR_MAX is 1, the other macros are defined only for documentation and to satisfy C @@ -62,8 +54,6 @@ # define mbsinit(ps) 1 #endif -#include - #ifndef SIZE_MAX # define SIZE_MAX ((size_t) -1) #endif @@ -75,6 +65,9 @@ struct quoting_options /* Basic quoting style. */ enum quoting_style style; + /* Additional flags. Bitwise combination of enum quoting_flags. */ + int flags; + /* Quote the characters indicated by this bit vector even if the quoting style would not normally require them to be quoted. */ unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1]; @@ -87,6 +80,7 @@ char const *const quoting_style_args[] = "shell", "shell-always", "c", + "c-maybe", "escape", "locale", "clocale", @@ -100,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 @@ -153,6 +148,32 @@ set_char_quoting (struct quoting_options *o, char c, int i) return r; } +/* In O (or in the default if O is null), + 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) +{ + int r; + if (!o) + o = &default_quoting_options; + r = o->flags; + o->flags = 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 * @@ -165,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 and the - non-quoting-style 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 @@ -174,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 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, - struct quoting_options const *o) + enum quoting_style quoting_style, int flags, + unsigned int const *quote_these_too) { size_t i; size_t len = 0; @@ -189,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 \ @@ -201,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; @@ -210,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: @@ -237,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++) @@ -264,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) @@ -272,21 +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 & 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 '\'': @@ -294,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; @@ -318,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) { @@ -352,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; @@ -441,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++) @@ -449,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; @@ -474,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)); @@ -490,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); @@ -512,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, o); + quoting_style, + flags & ~QA_ELIDE_OUTER_QUOTES, NULL); } /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of @@ -534,22 +600,41 @@ 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); + p->style, p->flags, p->quote_these_too); errno = e; return r; } -/* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly - allocated storage containing the quoted string. */ +/* Equivalent to quotearg_alloc (ARG, ARGSIZE, NULL, O). */ char * quotearg_alloc (char const *arg, size_t argsize, struct quoting_options const *o) { + return quotearg_alloc_mem (arg, argsize, NULL, o); +} + +/* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly + allocated storage containing the quoted string, and store the + resulting size into *SIZE, if non-NULL. The result can contain + embedded null bytes only if ARGSIZE is not SIZE_MAX, SIZE is not + NULL, and set_quoting_flags has not set the null byte elision + flag. */ +char * +quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size, + struct quoting_options const *o) +{ + struct quoting_options const *p = o ? o : &default_quoting_options; int e = errno; - size_t bufsize = quotearg_buffer (0, 0, arg, argsize, o) + 1; + /* Elide embedded null bytes if we can't return a size. */ + int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES); + size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style, + flags, p->quote_these_too) + 1; char *buf = xcharalloc (bufsize); - quotearg_buffer (buf, bufsize, arg, argsize, o); + quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags, + p->quote_these_too); errno = e; + if (size) + *size = bufsize - 1; return buf; } @@ -631,7 +716,11 @@ quotearg_n_options (int n, char const *arg, size_t argsize, { size_t size = sv[n].size; char *val = sv[n].val; - size_t qsize = quotearg_buffer (val, size, arg, argsize, options); + /* 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, flags, + options->quote_these_too); if (size <= qsize) { @@ -639,7 +728,8 @@ quotearg_n_options (int n, char const *arg, size_t argsize, if (val != slot0) free (val); sv[n].val = val = xcharalloc (size); - quotearg_buffer (val, size, arg, argsize, options); + quotearg_buffer_restyled (val, size, arg, argsize, options->style, + flags, options->quote_these_too); } errno = e; @@ -654,19 +744,21 @@ quotearg_n (int n, char const *arg) } char * +quotearg_n_mem (int n, char const *arg, size_t argsize) +{ + return quotearg_n_options (n, arg, argsize, &default_quoting_options); +} + +char * quotearg (char const *arg) { return quotearg_n (0, arg); } -/* Return quoting options for STYLE, with no extra quoting. */ -static struct quoting_options -quoting_options_from_style (enum quoting_style style) +char * +quotearg_mem (char const *arg, size_t argsize) { - struct quoting_options o; - o.style = style; - memset (o.quote_these_too, 0, sizeof o.quote_these_too); - return o; + return quotearg_n_mem (0, arg, argsize); } char * @@ -691,12 +783,24 @@ quotearg_style (enum quoting_style s, char const *arg) } char * -quotearg_char (char const *arg, char ch) +quotearg_style_mem (enum quoting_style s, char const *arg, size_t argsize) +{ + return quotearg_n_style_mem (0, s, arg, argsize); +} + +char * +quotearg_char_mem (char const *arg, size_t argsize, char ch) { struct quoting_options options; options = default_quoting_options; set_char_quoting (&options, ch, 1); - return quotearg_n_options (0, arg, SIZE_MAX, &options); + return quotearg_n_options (0, arg, argsize, &options); +} + +char * +quotearg_char (char const *arg, char ch) +{ + return quotearg_char_mem (arg, SIZE_MAX, ch); } char * @@ -704,3 +808,9 @@ quotearg_colon (char const *arg) { return quotearg_char (arg, ':'); } + +char * +quotearg_colon_mem (char const *arg, size_t argsize) +{ + return quotearg_char_mem (arg, argsize, ':'); +}