xref: /dragonfly/contrib/diffutils/lib/quotearg.c (revision 6ea1f93e)
144b87433SJohn Marino /* quotearg.c - quote arguments for output
244b87433SJohn Marino 
3*6ea1f93eSDaniel Fojt    Copyright (C) 1998-2002, 2004-2018 Free Software Foundation, Inc.
444b87433SJohn Marino 
544b87433SJohn Marino    This program is free software: you can redistribute it and/or modify
644b87433SJohn Marino    it under the terms of the GNU General Public License as published by
744b87433SJohn Marino    the Free Software Foundation; either version 3 of the License, or
844b87433SJohn Marino    (at your option) any later version.
944b87433SJohn Marino 
1044b87433SJohn Marino    This program is distributed in the hope that it will be useful,
1144b87433SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1244b87433SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1344b87433SJohn Marino    GNU General Public License for more details.
1444b87433SJohn Marino 
1544b87433SJohn Marino    You should have received a copy of the GNU General Public License
16*6ea1f93eSDaniel Fojt    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
1744b87433SJohn Marino 
1844b87433SJohn Marino /* Written by Paul Eggert <eggert@twinsun.com> */
1944b87433SJohn Marino 
204536c563SJohn Marino /* Without this pragma, gcc 4.7.0 20111124 mistakenly suggests that
214536c563SJohn Marino    the quoting_options_from_style function might be candidate for
224536c563SJohn Marino    attribute 'pure'  */
234536c563SJohn Marino #if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
244536c563SJohn Marino # pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
254536c563SJohn Marino #endif
264536c563SJohn Marino 
2744b87433SJohn Marino #include <config.h>
2844b87433SJohn Marino 
2944b87433SJohn Marino #include "quotearg.h"
304536c563SJohn Marino #include "quote.h"
3144b87433SJohn Marino 
32*6ea1f93eSDaniel Fojt #include "minmax.h"
3344b87433SJohn Marino #include "xalloc.h"
344536c563SJohn Marino #include "c-strcaseeq.h"
354536c563SJohn Marino #include "localcharset.h"
3644b87433SJohn Marino 
3744b87433SJohn Marino #include <ctype.h>
3844b87433SJohn Marino #include <errno.h>
3944b87433SJohn Marino #include <limits.h>
4044b87433SJohn Marino #include <stdbool.h>
41*6ea1f93eSDaniel Fojt #include <stdint.h>
4244b87433SJohn Marino #include <stdlib.h>
4344b87433SJohn Marino #include <string.h>
4444b87433SJohn Marino #include <wchar.h>
4544b87433SJohn Marino #include <wctype.h>
4644b87433SJohn Marino 
4744b87433SJohn Marino #include "gettext.h"
4844b87433SJohn Marino #define _(msgid) gettext (msgid)
4944b87433SJohn Marino #define N_(msgid) msgid
5044b87433SJohn Marino 
5144b87433SJohn Marino #ifndef SIZE_MAX
5244b87433SJohn Marino # define SIZE_MAX ((size_t) -1)
5344b87433SJohn Marino #endif
5444b87433SJohn Marino 
5544b87433SJohn Marino #define INT_BITS (sizeof (int) * CHAR_BIT)
5644b87433SJohn Marino 
57*6ea1f93eSDaniel Fojt #ifndef FALLTHROUGH
58*6ea1f93eSDaniel Fojt # if __GNUC__ < 7
59*6ea1f93eSDaniel Fojt #  define FALLTHROUGH ((void) 0)
60*6ea1f93eSDaniel Fojt # else
61*6ea1f93eSDaniel Fojt #  define FALLTHROUGH __attribute__ ((__fallthrough__))
62*6ea1f93eSDaniel Fojt # endif
63*6ea1f93eSDaniel Fojt #endif
64*6ea1f93eSDaniel Fojt 
6544b87433SJohn Marino struct quoting_options
6644b87433SJohn Marino {
6744b87433SJohn Marino   /* Basic quoting style.  */
6844b87433SJohn Marino   enum quoting_style style;
6944b87433SJohn Marino 
7044b87433SJohn Marino   /* Additional flags.  Bitwise combination of enum quoting_flags.  */
7144b87433SJohn Marino   int flags;
7244b87433SJohn Marino 
7344b87433SJohn Marino   /* Quote the characters indicated by this bit vector even if the
7444b87433SJohn Marino      quoting style would not normally require them to be quoted.  */
7544b87433SJohn Marino   unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
7644b87433SJohn Marino 
7744b87433SJohn Marino   /* The left quote for custom_quoting_style.  */
7844b87433SJohn Marino   char const *left_quote;
7944b87433SJohn Marino 
8044b87433SJohn Marino   /* The right quote for custom_quoting_style.  */
8144b87433SJohn Marino   char const *right_quote;
8244b87433SJohn Marino };
8344b87433SJohn Marino 
8444b87433SJohn Marino /* Names of quoting styles.  */
8544b87433SJohn Marino char const *const quoting_style_args[] =
8644b87433SJohn Marino {
8744b87433SJohn Marino   "literal",
8844b87433SJohn Marino   "shell",
8944b87433SJohn Marino   "shell-always",
90*6ea1f93eSDaniel Fojt   "shell-escape",
91*6ea1f93eSDaniel Fojt   "shell-escape-always",
9244b87433SJohn Marino   "c",
9344b87433SJohn Marino   "c-maybe",
9444b87433SJohn Marino   "escape",
9544b87433SJohn Marino   "locale",
9644b87433SJohn Marino   "clocale",
9744b87433SJohn Marino   0
9844b87433SJohn Marino };
9944b87433SJohn Marino 
10044b87433SJohn Marino /* Correspondences to quoting style names.  */
10144b87433SJohn Marino enum quoting_style const quoting_style_vals[] =
10244b87433SJohn Marino {
10344b87433SJohn Marino   literal_quoting_style,
10444b87433SJohn Marino   shell_quoting_style,
10544b87433SJohn Marino   shell_always_quoting_style,
106*6ea1f93eSDaniel Fojt   shell_escape_quoting_style,
107*6ea1f93eSDaniel Fojt   shell_escape_always_quoting_style,
10844b87433SJohn Marino   c_quoting_style,
10944b87433SJohn Marino   c_maybe_quoting_style,
11044b87433SJohn Marino   escape_quoting_style,
11144b87433SJohn Marino   locale_quoting_style,
11244b87433SJohn Marino   clocale_quoting_style
11344b87433SJohn Marino };
11444b87433SJohn Marino 
11544b87433SJohn Marino /* The default quoting options.  */
11644b87433SJohn Marino static struct quoting_options default_quoting_options;
11744b87433SJohn Marino 
11844b87433SJohn Marino /* Allocate a new set of quoting options, with contents initially identical
11944b87433SJohn Marino    to O if O is not null, or to the default if O is null.
12044b87433SJohn Marino    It is the caller's responsibility to free the result.  */
12144b87433SJohn Marino struct quoting_options *
clone_quoting_options(struct quoting_options * o)12244b87433SJohn Marino clone_quoting_options (struct quoting_options *o)
12344b87433SJohn Marino {
12444b87433SJohn Marino   int e = errno;
12544b87433SJohn Marino   struct quoting_options *p = xmemdup (o ? o : &default_quoting_options,
12644b87433SJohn Marino                                        sizeof *o);
12744b87433SJohn Marino   errno = e;
12844b87433SJohn Marino   return p;
12944b87433SJohn Marino }
13044b87433SJohn Marino 
13144b87433SJohn Marino /* Get the value of O's quoting style.  If O is null, use the default.  */
13244b87433SJohn Marino enum quoting_style
get_quoting_style(struct quoting_options const * o)133*6ea1f93eSDaniel Fojt get_quoting_style (struct quoting_options const *o)
13444b87433SJohn Marino {
13544b87433SJohn Marino   return (o ? o : &default_quoting_options)->style;
13644b87433SJohn Marino }
13744b87433SJohn Marino 
13844b87433SJohn Marino /* In O (or in the default if O is null),
13944b87433SJohn Marino    set the value of the quoting style to S.  */
14044b87433SJohn Marino void
set_quoting_style(struct quoting_options * o,enum quoting_style s)14144b87433SJohn Marino set_quoting_style (struct quoting_options *o, enum quoting_style s)
14244b87433SJohn Marino {
14344b87433SJohn Marino   (o ? o : &default_quoting_options)->style = s;
14444b87433SJohn Marino }
14544b87433SJohn Marino 
14644b87433SJohn Marino /* In O (or in the default if O is null),
14744b87433SJohn Marino    set the value of the quoting options for character C to I.
14844b87433SJohn Marino    Return the old value.  Currently, the only values defined for I are
14944b87433SJohn Marino    0 (the default) and 1 (which means to quote the character even if
15044b87433SJohn Marino    it would not otherwise be quoted).  */
15144b87433SJohn Marino int
set_char_quoting(struct quoting_options * o,char c,int i)15244b87433SJohn Marino set_char_quoting (struct quoting_options *o, char c, int i)
15344b87433SJohn Marino {
15444b87433SJohn Marino   unsigned char uc = c;
15544b87433SJohn Marino   unsigned int *p =
15644b87433SJohn Marino     (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
15744b87433SJohn Marino   int shift = uc % INT_BITS;
15844b87433SJohn Marino   int r = (*p >> shift) & 1;
15944b87433SJohn Marino   *p ^= ((i & 1) ^ r) << shift;
16044b87433SJohn Marino   return r;
16144b87433SJohn Marino }
16244b87433SJohn Marino 
16344b87433SJohn Marino /* In O (or in the default if O is null),
16444b87433SJohn Marino    set the value of the quoting options flag to I, which can be a
16544b87433SJohn Marino    bitwise combination of enum quoting_flags, or 0 for default
16644b87433SJohn Marino    behavior.  Return the old value.  */
16744b87433SJohn Marino int
set_quoting_flags(struct quoting_options * o,int i)16844b87433SJohn Marino set_quoting_flags (struct quoting_options *o, int i)
16944b87433SJohn Marino {
17044b87433SJohn Marino   int r;
17144b87433SJohn Marino   if (!o)
17244b87433SJohn Marino     o = &default_quoting_options;
17344b87433SJohn Marino   r = o->flags;
17444b87433SJohn Marino   o->flags = i;
17544b87433SJohn Marino   return r;
17644b87433SJohn Marino }
17744b87433SJohn Marino 
17844b87433SJohn Marino void
set_custom_quoting(struct quoting_options * o,char const * left_quote,char const * right_quote)17944b87433SJohn Marino set_custom_quoting (struct quoting_options *o,
18044b87433SJohn Marino                     char const *left_quote, char const *right_quote)
18144b87433SJohn Marino {
18244b87433SJohn Marino   if (!o)
18344b87433SJohn Marino     o = &default_quoting_options;
18444b87433SJohn Marino   o->style = custom_quoting_style;
18544b87433SJohn Marino   if (!left_quote || !right_quote)
18644b87433SJohn Marino     abort ();
18744b87433SJohn Marino   o->left_quote = left_quote;
18844b87433SJohn Marino   o->right_quote = right_quote;
18944b87433SJohn Marino }
19044b87433SJohn Marino 
19144b87433SJohn Marino /* Return quoting options for STYLE, with no extra quoting.  */
1924536c563SJohn Marino static struct quoting_options /* NOT PURE!! */
quoting_options_from_style(enum quoting_style style)19344b87433SJohn Marino quoting_options_from_style (enum quoting_style style)
19444b87433SJohn Marino {
195*6ea1f93eSDaniel Fojt   struct quoting_options o = { literal_quoting_style, 0, { 0 }, NULL, NULL };
196008e37b6SJohn Marino   if (style == custom_quoting_style)
197008e37b6SJohn Marino     abort ();
19844b87433SJohn Marino   o.style = style;
19944b87433SJohn Marino   return o;
20044b87433SJohn Marino }
20144b87433SJohn Marino 
20244b87433SJohn Marino /* MSGID approximates a quotation mark.  Return its translation if it
2034536c563SJohn Marino    has one; otherwise, return either it or "\"", depending on S.
2044536c563SJohn Marino 
2054536c563SJohn Marino    S is either clocale_quoting_style or locale_quoting_style.  */
20644b87433SJohn Marino static char const *
gettext_quote(char const * msgid,enum quoting_style s)20744b87433SJohn Marino gettext_quote (char const *msgid, enum quoting_style s)
20844b87433SJohn Marino {
20944b87433SJohn Marino   char const *translation = _(msgid);
2104536c563SJohn Marino   char const *locale_code;
2114536c563SJohn Marino 
2124536c563SJohn Marino   if (translation != msgid)
21344b87433SJohn Marino     return translation;
2144536c563SJohn Marino 
2154536c563SJohn Marino   /* For UTF-8 and GB-18030, use single quotes U+2018 and U+2019.
2164536c563SJohn Marino      Here is a list of other locales that include U+2018 and U+2019:
2174536c563SJohn Marino 
2184536c563SJohn Marino         ISO-8859-7   0xA1                 KOI8-T       0x91
2194536c563SJohn Marino         CP869        0x8B                 CP874        0x91
2204536c563SJohn Marino         CP932        0x81 0x65            CP936        0xA1 0xAE
2214536c563SJohn Marino         CP949        0xA1 0xAE            CP950        0xA1 0xA5
2224536c563SJohn Marino         CP1250       0x91                 CP1251       0x91
2234536c563SJohn Marino         CP1252       0x91                 CP1253       0x91
2244536c563SJohn Marino         CP1254       0x91                 CP1255       0x91
2254536c563SJohn Marino         CP1256       0x91                 CP1257       0x91
2264536c563SJohn Marino         EUC-JP       0xA1 0xC6            EUC-KR       0xA1 0xAE
2274536c563SJohn Marino         EUC-TW       0xA1 0xE4            BIG5         0xA1 0xA5
2284536c563SJohn Marino         BIG5-HKSCS   0xA1 0xA5            EUC-CN       0xA1 0xAE
2294536c563SJohn Marino         GBK          0xA1 0xAE            Georgian-PS  0x91
2304536c563SJohn Marino         PT154        0x91
2314536c563SJohn Marino 
2324536c563SJohn Marino      None of these is still in wide use; using iconv is overkill.  */
2334536c563SJohn Marino   locale_code = locale_charset ();
2344536c563SJohn Marino   if (STRCASEEQ (locale_code, "UTF-8", 'U','T','F','-','8',0,0,0,0))
2354536c563SJohn Marino     return msgid[0] == '`' ? "\xe2\x80\x98": "\xe2\x80\x99";
2364536c563SJohn Marino   if (STRCASEEQ (locale_code, "GB18030", 'G','B','1','8','0','3','0',0,0))
2374536c563SJohn Marino     return msgid[0] == '`' ? "\xa1\ae": "\xa1\xaf";
2384536c563SJohn Marino 
2394536c563SJohn Marino   return (s == clocale_quoting_style ? "\"" : "'");
24044b87433SJohn Marino }
24144b87433SJohn Marino 
24244b87433SJohn Marino /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
24344b87433SJohn Marino    argument ARG (of size ARGSIZE), using QUOTING_STYLE, FLAGS, and
24444b87433SJohn Marino    QUOTE_THESE_TOO to control quoting.
24544b87433SJohn Marino    Terminate the output with a null character, and return the written
24644b87433SJohn Marino    size of the output, not counting the terminating null.
24744b87433SJohn Marino    If BUFFERSIZE is too small to store the output string, return the
24844b87433SJohn Marino    value that would have been returned had BUFFERSIZE been large enough.
24944b87433SJohn Marino    If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE.
25044b87433SJohn Marino 
25144b87433SJohn Marino    This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
25244b87433SJohn Marino    ARGSIZE, O), except it breaks O into its component pieces and is
25344b87433SJohn Marino    not careful about errno.  */
25444b87433SJohn Marino 
25544b87433SJohn Marino static size_t
quotearg_buffer_restyled(char * buffer,size_t buffersize,char const * arg,size_t argsize,enum quoting_style quoting_style,int flags,unsigned int const * quote_these_too,char const * left_quote,char const * right_quote)25644b87433SJohn Marino quotearg_buffer_restyled (char *buffer, size_t buffersize,
25744b87433SJohn Marino                           char const *arg, size_t argsize,
25844b87433SJohn Marino                           enum quoting_style quoting_style, int flags,
25944b87433SJohn Marino                           unsigned int const *quote_these_too,
26044b87433SJohn Marino                           char const *left_quote,
26144b87433SJohn Marino                           char const *right_quote)
26244b87433SJohn Marino {
26344b87433SJohn Marino   size_t i;
26444b87433SJohn Marino   size_t len = 0;
265*6ea1f93eSDaniel Fojt   size_t orig_buffersize = 0;
26644b87433SJohn Marino   char const *quote_string = 0;
26744b87433SJohn Marino   size_t quote_string_len = 0;
26844b87433SJohn Marino   bool backslash_escapes = false;
26944b87433SJohn Marino   bool unibyte_locale = MB_CUR_MAX == 1;
27044b87433SJohn Marino   bool elide_outer_quotes = (flags & QA_ELIDE_OUTER_QUOTES) != 0;
271*6ea1f93eSDaniel Fojt   bool pending_shell_escape_end = false;
272*6ea1f93eSDaniel Fojt   bool encountered_single_quote = false;
273*6ea1f93eSDaniel Fojt   bool all_c_and_shell_quote_compat = true;
27444b87433SJohn Marino 
27544b87433SJohn Marino #define STORE(c) \
27644b87433SJohn Marino     do \
27744b87433SJohn Marino       { \
27844b87433SJohn Marino         if (len < buffersize) \
27944b87433SJohn Marino           buffer[len] = (c); \
28044b87433SJohn Marino         len++; \
28144b87433SJohn Marino       } \
28244b87433SJohn Marino     while (0)
28344b87433SJohn Marino 
284*6ea1f93eSDaniel Fojt #define START_ESC() \
285*6ea1f93eSDaniel Fojt     do \
286*6ea1f93eSDaniel Fojt       { \
287*6ea1f93eSDaniel Fojt         if (elide_outer_quotes) \
288*6ea1f93eSDaniel Fojt           goto force_outer_quoting_style; \
289*6ea1f93eSDaniel Fojt         escaping = true; \
290*6ea1f93eSDaniel Fojt         if (quoting_style == shell_always_quoting_style \
291*6ea1f93eSDaniel Fojt             && ! pending_shell_escape_end) \
292*6ea1f93eSDaniel Fojt           { \
293*6ea1f93eSDaniel Fojt             STORE ('\''); \
294*6ea1f93eSDaniel Fojt             STORE ('$'); \
295*6ea1f93eSDaniel Fojt             STORE ('\''); \
296*6ea1f93eSDaniel Fojt             pending_shell_escape_end = true; \
297*6ea1f93eSDaniel Fojt           } \
298*6ea1f93eSDaniel Fojt         STORE ('\\'); \
299*6ea1f93eSDaniel Fojt       } \
300*6ea1f93eSDaniel Fojt     while (0)
301*6ea1f93eSDaniel Fojt 
302*6ea1f93eSDaniel Fojt #define END_ESC() \
303*6ea1f93eSDaniel Fojt     do \
304*6ea1f93eSDaniel Fojt       { \
305*6ea1f93eSDaniel Fojt         if (pending_shell_escape_end && ! escaping) \
306*6ea1f93eSDaniel Fojt           { \
307*6ea1f93eSDaniel Fojt             STORE ('\''); \
308*6ea1f93eSDaniel Fojt             STORE ('\''); \
309*6ea1f93eSDaniel Fojt             pending_shell_escape_end = false; \
310*6ea1f93eSDaniel Fojt           } \
311*6ea1f93eSDaniel Fojt       } \
312*6ea1f93eSDaniel Fojt     while (0)
313*6ea1f93eSDaniel Fojt 
314*6ea1f93eSDaniel Fojt  process_input:
315*6ea1f93eSDaniel Fojt 
31644b87433SJohn Marino   switch (quoting_style)
31744b87433SJohn Marino     {
31844b87433SJohn Marino     case c_maybe_quoting_style:
31944b87433SJohn Marino       quoting_style = c_quoting_style;
32044b87433SJohn Marino       elide_outer_quotes = true;
321*6ea1f93eSDaniel Fojt       FALLTHROUGH;
32244b87433SJohn Marino     case c_quoting_style:
32344b87433SJohn Marino       if (!elide_outer_quotes)
32444b87433SJohn Marino         STORE ('"');
32544b87433SJohn Marino       backslash_escapes = true;
32644b87433SJohn Marino       quote_string = "\"";
32744b87433SJohn Marino       quote_string_len = 1;
32844b87433SJohn Marino       break;
32944b87433SJohn Marino 
33044b87433SJohn Marino     case escape_quoting_style:
33144b87433SJohn Marino       backslash_escapes = true;
33244b87433SJohn Marino       elide_outer_quotes = false;
33344b87433SJohn Marino       break;
33444b87433SJohn Marino 
33544b87433SJohn Marino     case locale_quoting_style:
33644b87433SJohn Marino     case clocale_quoting_style:
33744b87433SJohn Marino     case custom_quoting_style:
33844b87433SJohn Marino       {
33944b87433SJohn Marino         if (quoting_style != custom_quoting_style)
34044b87433SJohn Marino           {
34144b87433SJohn Marino             /* TRANSLATORS:
34244b87433SJohn Marino                Get translations for open and closing quotation marks.
34344b87433SJohn Marino                The message catalog should translate "`" to a left
34444b87433SJohn Marino                quotation mark suitable for the locale, and similarly for
3454536c563SJohn Marino                "'".  For example, a French Unicode local should translate
3464536c563SJohn Marino                these to U+00AB (LEFT-POINTING DOUBLE ANGLE
3474536c563SJohn Marino                QUOTATION MARK), and U+00BB (RIGHT-POINTING DOUBLE ANGLE
3484536c563SJohn Marino                QUOTATION MARK), respectively.
34944b87433SJohn Marino 
3504536c563SJohn Marino                If the catalog has no translation, we will try to
3514536c563SJohn Marino                use Unicode U+2018 (LEFT SINGLE QUOTATION MARK) and
3524536c563SJohn Marino                Unicode U+2019 (RIGHT SINGLE QUOTATION MARK).  If the
3534536c563SJohn Marino                current locale is not Unicode, locale_quoting_style
3544536c563SJohn Marino                will quote 'like this', and clocale_quoting_style will
3554536c563SJohn Marino                quote "like this".  You should always include translations
3564536c563SJohn Marino                for "`" and "'" even if U+2018 and U+2019 are appropriate
3574536c563SJohn Marino                for your locale.
35844b87433SJohn Marino 
35944b87433SJohn Marino                If you don't know what to put here, please see
360*6ea1f93eSDaniel Fojt                <https://en.wikipedia.org/wiki/Quotation_marks_in_other_languages>
36144b87433SJohn Marino                and use glyphs suitable for your language.  */
36244b87433SJohn Marino             left_quote = gettext_quote (N_("`"), quoting_style);
36344b87433SJohn Marino             right_quote = gettext_quote (N_("'"), quoting_style);
36444b87433SJohn Marino           }
36544b87433SJohn Marino         if (!elide_outer_quotes)
36644b87433SJohn Marino           for (quote_string = left_quote; *quote_string; quote_string++)
36744b87433SJohn Marino             STORE (*quote_string);
36844b87433SJohn Marino         backslash_escapes = true;
36944b87433SJohn Marino         quote_string = right_quote;
37044b87433SJohn Marino         quote_string_len = strlen (quote_string);
37144b87433SJohn Marino       }
37244b87433SJohn Marino       break;
37344b87433SJohn Marino 
374*6ea1f93eSDaniel Fojt     case shell_escape_quoting_style:
375*6ea1f93eSDaniel Fojt       backslash_escapes = true;
376*6ea1f93eSDaniel Fojt       FALLTHROUGH;
37744b87433SJohn Marino     case shell_quoting_style:
37844b87433SJohn Marino       elide_outer_quotes = true;
379*6ea1f93eSDaniel Fojt       FALLTHROUGH;
380*6ea1f93eSDaniel Fojt     case shell_escape_always_quoting_style:
381*6ea1f93eSDaniel Fojt       if (!elide_outer_quotes)
382*6ea1f93eSDaniel Fojt         backslash_escapes = true;
383*6ea1f93eSDaniel Fojt       FALLTHROUGH;
38444b87433SJohn Marino     case shell_always_quoting_style:
385*6ea1f93eSDaniel Fojt       quoting_style = shell_always_quoting_style;
38644b87433SJohn Marino       if (!elide_outer_quotes)
38744b87433SJohn Marino         STORE ('\'');
38844b87433SJohn Marino       quote_string = "'";
38944b87433SJohn Marino       quote_string_len = 1;
39044b87433SJohn Marino       break;
39144b87433SJohn Marino 
39244b87433SJohn Marino     case literal_quoting_style:
39344b87433SJohn Marino       elide_outer_quotes = false;
39444b87433SJohn Marino       break;
39544b87433SJohn Marino 
39644b87433SJohn Marino     default:
39744b87433SJohn Marino       abort ();
39844b87433SJohn Marino     }
39944b87433SJohn Marino 
40044b87433SJohn Marino   for (i = 0;  ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize);  i++)
40144b87433SJohn Marino     {
40244b87433SJohn Marino       unsigned char c;
40344b87433SJohn Marino       unsigned char esc;
40444b87433SJohn Marino       bool is_right_quote = false;
405*6ea1f93eSDaniel Fojt       bool escaping = false;
406*6ea1f93eSDaniel Fojt       bool c_and_shell_quote_compat = false;
40744b87433SJohn Marino 
40844b87433SJohn Marino       if (backslash_escapes
409*6ea1f93eSDaniel Fojt           && quoting_style != shell_always_quoting_style
41044b87433SJohn Marino           && quote_string_len
411*6ea1f93eSDaniel Fojt           && (i + quote_string_len
412*6ea1f93eSDaniel Fojt               <= (argsize == SIZE_MAX && 1 < quote_string_len
413*6ea1f93eSDaniel Fojt                   /* Use strlen only if we must: when argsize is SIZE_MAX,
414*6ea1f93eSDaniel Fojt                      and when the quote string is more than 1 byte long.
415*6ea1f93eSDaniel Fojt                      If we do call strlen, save the result.  */
416*6ea1f93eSDaniel Fojt                   ? (argsize = strlen (arg)) : argsize))
41744b87433SJohn Marino           && memcmp (arg + i, quote_string, quote_string_len) == 0)
41844b87433SJohn Marino         {
41944b87433SJohn Marino           if (elide_outer_quotes)
42044b87433SJohn Marino             goto force_outer_quoting_style;
42144b87433SJohn Marino           is_right_quote = true;
42244b87433SJohn Marino         }
42344b87433SJohn Marino 
42444b87433SJohn Marino       c = arg[i];
42544b87433SJohn Marino       switch (c)
42644b87433SJohn Marino         {
42744b87433SJohn Marino         case '\0':
42844b87433SJohn Marino           if (backslash_escapes)
42944b87433SJohn Marino             {
430*6ea1f93eSDaniel Fojt               START_ESC ();
43144b87433SJohn Marino               /* If quote_string were to begin with digits, we'd need to
43244b87433SJohn Marino                  test for the end of the arg as well.  However, it's
43344b87433SJohn Marino                  hard to imagine any locale that would use digits in
43444b87433SJohn Marino                  quotes, and set_custom_quoting is documented not to
435*6ea1f93eSDaniel Fojt                  accept them.  Use only a single \0 with shell-escape
436*6ea1f93eSDaniel Fojt                  as currently digits are not printed within $'...'  */
437*6ea1f93eSDaniel Fojt               if (quoting_style != shell_always_quoting_style
438*6ea1f93eSDaniel Fojt                   && i + 1 < argsize && '0' <= arg[i + 1] && arg[i + 1] <= '9')
43944b87433SJohn Marino                 {
44044b87433SJohn Marino                   STORE ('0');
44144b87433SJohn Marino                   STORE ('0');
44244b87433SJohn Marino                 }
44344b87433SJohn Marino               c = '0';
44444b87433SJohn Marino               /* We don't have to worry that this last '0' will be
44544b87433SJohn Marino                  backslash-escaped because, again, quote_string should
44644b87433SJohn Marino                  not start with it and because quote_these_too is
44744b87433SJohn Marino                  documented as not accepting it.  */
44844b87433SJohn Marino             }
44944b87433SJohn Marino           else if (flags & QA_ELIDE_NULL_BYTES)
45044b87433SJohn Marino             continue;
45144b87433SJohn Marino           break;
45244b87433SJohn Marino 
45344b87433SJohn Marino         case '?':
45444b87433SJohn Marino           switch (quoting_style)
45544b87433SJohn Marino             {
45644b87433SJohn Marino             case shell_always_quoting_style:
45744b87433SJohn Marino               if (elide_outer_quotes)
45844b87433SJohn Marino                 goto force_outer_quoting_style;
45944b87433SJohn Marino               break;
46044b87433SJohn Marino 
46144b87433SJohn Marino             case c_quoting_style:
46244b87433SJohn Marino               if ((flags & QA_SPLIT_TRIGRAPHS)
46344b87433SJohn Marino                   && i + 2 < argsize && arg[i + 1] == '?')
46444b87433SJohn Marino                 switch (arg[i + 2])
46544b87433SJohn Marino                   {
46644b87433SJohn Marino                   case '!': case '\'':
46744b87433SJohn Marino                   case '(': case ')': case '-': case '/':
46844b87433SJohn Marino                   case '<': case '=': case '>':
46944b87433SJohn Marino                     /* Escape the second '?' in what would otherwise be
47044b87433SJohn Marino                        a trigraph.  */
47144b87433SJohn Marino                     if (elide_outer_quotes)
47244b87433SJohn Marino                       goto force_outer_quoting_style;
47344b87433SJohn Marino                     c = arg[i + 2];
47444b87433SJohn Marino                     i += 2;
47544b87433SJohn Marino                     STORE ('?');
47644b87433SJohn Marino                     STORE ('"');
47744b87433SJohn Marino                     STORE ('"');
47844b87433SJohn Marino                     STORE ('?');
47944b87433SJohn Marino                     break;
48044b87433SJohn Marino 
48144b87433SJohn Marino                   default:
48244b87433SJohn Marino                     break;
48344b87433SJohn Marino                   }
48444b87433SJohn Marino               break;
48544b87433SJohn Marino 
48644b87433SJohn Marino             default:
48744b87433SJohn Marino               break;
48844b87433SJohn Marino             }
48944b87433SJohn Marino           break;
49044b87433SJohn Marino 
49144b87433SJohn Marino         case '\a': esc = 'a'; goto c_escape;
49244b87433SJohn Marino         case '\b': esc = 'b'; goto c_escape;
49344b87433SJohn Marino         case '\f': esc = 'f'; goto c_escape;
49444b87433SJohn Marino         case '\n': esc = 'n'; goto c_and_shell_escape;
49544b87433SJohn Marino         case '\r': esc = 'r'; goto c_and_shell_escape;
49644b87433SJohn Marino         case '\t': esc = 't'; goto c_and_shell_escape;
49744b87433SJohn Marino         case '\v': esc = 'v'; goto c_escape;
49844b87433SJohn Marino         case '\\': esc = c;
499*6ea1f93eSDaniel Fojt           /* Never need to escape '\' in shell case.  */
500*6ea1f93eSDaniel Fojt           if (quoting_style == shell_always_quoting_style)
501*6ea1f93eSDaniel Fojt             {
502*6ea1f93eSDaniel Fojt               if (elide_outer_quotes)
503*6ea1f93eSDaniel Fojt                 goto force_outer_quoting_style;
504*6ea1f93eSDaniel Fojt               goto store_c;
505*6ea1f93eSDaniel Fojt             }
506*6ea1f93eSDaniel Fojt 
50744b87433SJohn Marino           /* No need to escape the escape if we are trying to elide
50844b87433SJohn Marino              outer quotes and nothing else is problematic.  */
50944b87433SJohn Marino           if (backslash_escapes && elide_outer_quotes && quote_string_len)
51044b87433SJohn Marino             goto store_c;
51144b87433SJohn Marino 
51244b87433SJohn Marino         c_and_shell_escape:
51344b87433SJohn Marino           if (quoting_style == shell_always_quoting_style
51444b87433SJohn Marino               && elide_outer_quotes)
51544b87433SJohn Marino             goto force_outer_quoting_style;
516*6ea1f93eSDaniel Fojt           /* fall through */
51744b87433SJohn Marino         c_escape:
51844b87433SJohn Marino           if (backslash_escapes)
51944b87433SJohn Marino             {
52044b87433SJohn Marino               c = esc;
52144b87433SJohn Marino               goto store_escape;
52244b87433SJohn Marino             }
52344b87433SJohn Marino           break;
52444b87433SJohn Marino 
52544b87433SJohn Marino         case '{': case '}': /* sometimes special if isolated */
52644b87433SJohn Marino           if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1))
52744b87433SJohn Marino             break;
528*6ea1f93eSDaniel Fojt           FALLTHROUGH;
52944b87433SJohn Marino         case '#': case '~':
53044b87433SJohn Marino           if (i != 0)
53144b87433SJohn Marino             break;
532*6ea1f93eSDaniel Fojt           FALLTHROUGH;
53344b87433SJohn Marino         case ' ':
534*6ea1f93eSDaniel Fojt           c_and_shell_quote_compat = true;
535*6ea1f93eSDaniel Fojt           FALLTHROUGH;
53644b87433SJohn Marino         case '!': /* special in bash */
53744b87433SJohn Marino         case '"': case '$': case '&':
53844b87433SJohn Marino         case '(': case ')': case '*': case ';':
53944b87433SJohn Marino         case '<':
54044b87433SJohn Marino         case '=': /* sometimes special in 0th or (with "set -k") later args */
54144b87433SJohn Marino         case '>': case '[':
54244b87433SJohn Marino         case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
54344b87433SJohn Marino         case '`': case '|':
54444b87433SJohn Marino           /* A shell special character.  In theory, '$' and '`' could
54544b87433SJohn Marino              be the first bytes of multibyte characters, which means
54644b87433SJohn Marino              we should check them with mbrtowc, but in practice this
54744b87433SJohn Marino              doesn't happen so it's not worth worrying about.  */
54844b87433SJohn Marino           if (quoting_style == shell_always_quoting_style
54944b87433SJohn Marino               && elide_outer_quotes)
55044b87433SJohn Marino             goto force_outer_quoting_style;
55144b87433SJohn Marino           break;
55244b87433SJohn Marino 
55344b87433SJohn Marino         case '\'':
554*6ea1f93eSDaniel Fojt           encountered_single_quote = true;
555*6ea1f93eSDaniel Fojt           c_and_shell_quote_compat = true;
55644b87433SJohn Marino           if (quoting_style == shell_always_quoting_style)
55744b87433SJohn Marino             {
55844b87433SJohn Marino               if (elide_outer_quotes)
55944b87433SJohn Marino                 goto force_outer_quoting_style;
560*6ea1f93eSDaniel Fojt 
561*6ea1f93eSDaniel Fojt               if (buffersize && ! orig_buffersize)
562*6ea1f93eSDaniel Fojt                 {
563*6ea1f93eSDaniel Fojt                   /* Just scan string to see if supports a more concise
564*6ea1f93eSDaniel Fojt                      representation, rather than writing a longer string
565*6ea1f93eSDaniel Fojt                      but returning the length of the more concise form.  */
566*6ea1f93eSDaniel Fojt                   orig_buffersize = buffersize;
567*6ea1f93eSDaniel Fojt                   buffersize = 0;
568*6ea1f93eSDaniel Fojt                 }
569*6ea1f93eSDaniel Fojt 
57044b87433SJohn Marino               STORE ('\'');
57144b87433SJohn Marino               STORE ('\\');
57244b87433SJohn Marino               STORE ('\'');
573*6ea1f93eSDaniel Fojt               pending_shell_escape_end = false;
57444b87433SJohn Marino             }
57544b87433SJohn Marino           break;
57644b87433SJohn Marino 
57744b87433SJohn Marino         case '%': case '+': case ',': case '-': case '.': case '/':
57844b87433SJohn Marino         case '0': case '1': case '2': case '3': case '4': case '5':
57944b87433SJohn Marino         case '6': case '7': case '8': case '9': case ':':
58044b87433SJohn Marino         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
58144b87433SJohn Marino         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
58244b87433SJohn Marino         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
58344b87433SJohn Marino         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
58444b87433SJohn Marino         case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
58544b87433SJohn Marino         case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
58644b87433SJohn Marino         case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
58744b87433SJohn Marino         case 'o': case 'p': case 'q': case 'r': case 's': case 't':
58844b87433SJohn Marino         case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
58944b87433SJohn Marino           /* These characters don't cause problems, no matter what the
59044b87433SJohn Marino              quoting style is.  They cannot start multibyte sequences.
59144b87433SJohn Marino              A digit or a special letter would cause trouble if it
59244b87433SJohn Marino              appeared at the beginning of quote_string because we'd then
59344b87433SJohn Marino              escape by prepending a backslash.  However, it's hard to
59444b87433SJohn Marino              imagine any locale that would use digits or letters as
59544b87433SJohn Marino              quotes, and set_custom_quoting is documented not to accept
59644b87433SJohn Marino              them.  Also, a digit or a special letter would cause
59744b87433SJohn Marino              trouble if it appeared in quote_these_too, but that's also
59844b87433SJohn Marino              documented as not accepting them.  */
599*6ea1f93eSDaniel Fojt           c_and_shell_quote_compat = true;
60044b87433SJohn Marino           break;
60144b87433SJohn Marino 
60244b87433SJohn Marino         default:
60344b87433SJohn Marino           /* If we have a multibyte sequence, copy it until we reach
60444b87433SJohn Marino              its end, find an error, or come back to the initial shift
60544b87433SJohn Marino              state.  For C-like styles, if the sequence has
60644b87433SJohn Marino              unprintable characters, escape the whole sequence, since
60744b87433SJohn Marino              we can't easily escape single characters within it.  */
60844b87433SJohn Marino           {
60944b87433SJohn Marino             /* Length of multibyte sequence found so far.  */
61044b87433SJohn Marino             size_t m;
61144b87433SJohn Marino 
61244b87433SJohn Marino             bool printable;
61344b87433SJohn Marino 
61444b87433SJohn Marino             if (unibyte_locale)
61544b87433SJohn Marino               {
61644b87433SJohn Marino                 m = 1;
61744b87433SJohn Marino                 printable = isprint (c) != 0;
61844b87433SJohn Marino               }
61944b87433SJohn Marino             else
62044b87433SJohn Marino               {
62144b87433SJohn Marino                 mbstate_t mbstate;
62244b87433SJohn Marino                 memset (&mbstate, 0, sizeof mbstate);
62344b87433SJohn Marino 
62444b87433SJohn Marino                 m = 0;
62544b87433SJohn Marino                 printable = true;
62644b87433SJohn Marino                 if (argsize == SIZE_MAX)
62744b87433SJohn Marino                   argsize = strlen (arg);
62844b87433SJohn Marino 
62944b87433SJohn Marino                 do
63044b87433SJohn Marino                   {
63144b87433SJohn Marino                     wchar_t w;
63244b87433SJohn Marino                     size_t bytes = mbrtowc (&w, &arg[i + m],
63344b87433SJohn Marino                                             argsize - (i + m), &mbstate);
63444b87433SJohn Marino                     if (bytes == 0)
63544b87433SJohn Marino                       break;
63644b87433SJohn Marino                     else if (bytes == (size_t) -1)
63744b87433SJohn Marino                       {
63844b87433SJohn Marino                         printable = false;
63944b87433SJohn Marino                         break;
64044b87433SJohn Marino                       }
64144b87433SJohn Marino                     else if (bytes == (size_t) -2)
64244b87433SJohn Marino                       {
64344b87433SJohn Marino                         printable = false;
64444b87433SJohn Marino                         while (i + m < argsize && arg[i + m])
64544b87433SJohn Marino                           m++;
64644b87433SJohn Marino                         break;
64744b87433SJohn Marino                       }
64844b87433SJohn Marino                     else
64944b87433SJohn Marino                       {
65044b87433SJohn Marino                         /* Work around a bug with older shells that "see" a '\'
65144b87433SJohn Marino                            that is really the 2nd byte of a multibyte character.
65244b87433SJohn Marino                            In practice the problem is limited to ASCII
65344b87433SJohn Marino                            chars >= '@' that are shell special chars.  */
65444b87433SJohn Marino                         if ('[' == 0x5b && elide_outer_quotes
65544b87433SJohn Marino                             && quoting_style == shell_always_quoting_style)
65644b87433SJohn Marino                           {
65744b87433SJohn Marino                             size_t j;
65844b87433SJohn Marino                             for (j = 1; j < bytes; j++)
65944b87433SJohn Marino                               switch (arg[i + m + j])
66044b87433SJohn Marino                                 {
66144b87433SJohn Marino                                 case '[': case '\\': case '^':
66244b87433SJohn Marino                                 case '`': case '|':
66344b87433SJohn Marino                                   goto force_outer_quoting_style;
66444b87433SJohn Marino 
66544b87433SJohn Marino                                 default:
66644b87433SJohn Marino                                   break;
66744b87433SJohn Marino                                 }
66844b87433SJohn Marino                           }
66944b87433SJohn Marino 
67044b87433SJohn Marino                         if (! iswprint (w))
67144b87433SJohn Marino                           printable = false;
67244b87433SJohn Marino                         m += bytes;
67344b87433SJohn Marino                       }
67444b87433SJohn Marino                   }
67544b87433SJohn Marino                 while (! mbsinit (&mbstate));
67644b87433SJohn Marino               }
67744b87433SJohn Marino 
678*6ea1f93eSDaniel Fojt             c_and_shell_quote_compat = printable;
679*6ea1f93eSDaniel Fojt 
68044b87433SJohn Marino             if (1 < m || (backslash_escapes && ! printable))
68144b87433SJohn Marino               {
68244b87433SJohn Marino                 /* Output a multibyte sequence, or an escaped
68344b87433SJohn Marino                    unprintable unibyte character.  */
68444b87433SJohn Marino                 size_t ilim = i + m;
68544b87433SJohn Marino 
68644b87433SJohn Marino                 for (;;)
68744b87433SJohn Marino                   {
68844b87433SJohn Marino                     if (backslash_escapes && ! printable)
68944b87433SJohn Marino                       {
690*6ea1f93eSDaniel Fojt                         START_ESC ();
69144b87433SJohn Marino                         STORE ('0' + (c >> 6));
69244b87433SJohn Marino                         STORE ('0' + ((c >> 3) & 7));
69344b87433SJohn Marino                         c = '0' + (c & 7);
69444b87433SJohn Marino                       }
69544b87433SJohn Marino                     else if (is_right_quote)
69644b87433SJohn Marino                       {
69744b87433SJohn Marino                         STORE ('\\');
69844b87433SJohn Marino                         is_right_quote = false;
69944b87433SJohn Marino                       }
70044b87433SJohn Marino                     if (ilim <= i + 1)
70144b87433SJohn Marino                       break;
702*6ea1f93eSDaniel Fojt                     END_ESC ();
70344b87433SJohn Marino                     STORE (c);
70444b87433SJohn Marino                     c = arg[++i];
70544b87433SJohn Marino                   }
70644b87433SJohn Marino 
70744b87433SJohn Marino                 goto store_c;
70844b87433SJohn Marino               }
70944b87433SJohn Marino           }
71044b87433SJohn Marino         }
71144b87433SJohn Marino 
712*6ea1f93eSDaniel Fojt       if (! (((backslash_escapes && quoting_style != shell_always_quoting_style)
713*6ea1f93eSDaniel Fojt               || elide_outer_quotes)
71444b87433SJohn Marino              && quote_these_too
715*6ea1f93eSDaniel Fojt              && quote_these_too[c / INT_BITS] >> (c % INT_BITS) & 1)
71644b87433SJohn Marino           && !is_right_quote)
71744b87433SJohn Marino         goto store_c;
71844b87433SJohn Marino 
71944b87433SJohn Marino     store_escape:
720*6ea1f93eSDaniel Fojt       START_ESC ();
72144b87433SJohn Marino 
72244b87433SJohn Marino     store_c:
723*6ea1f93eSDaniel Fojt       END_ESC ();
72444b87433SJohn Marino       STORE (c);
725*6ea1f93eSDaniel Fojt 
726*6ea1f93eSDaniel Fojt       if (! c_and_shell_quote_compat)
727*6ea1f93eSDaniel Fojt         all_c_and_shell_quote_compat = false;
72844b87433SJohn Marino     }
72944b87433SJohn Marino 
73044b87433SJohn Marino   if (len == 0 && quoting_style == shell_always_quoting_style
73144b87433SJohn Marino       && elide_outer_quotes)
73244b87433SJohn Marino     goto force_outer_quoting_style;
73344b87433SJohn Marino 
734*6ea1f93eSDaniel Fojt   /* Single shell quotes (') are commonly enough used as an apostrophe,
735*6ea1f93eSDaniel Fojt      that we attempt to minimize the quoting in this case.  Note itʼs
736*6ea1f93eSDaniel Fojt      better to use the apostrophe modifier "\u02BC" if possible, as that
737*6ea1f93eSDaniel Fojt      renders better and works with the word match regex \W+ etc.  */
738*6ea1f93eSDaniel Fojt   if (quoting_style == shell_always_quoting_style && ! elide_outer_quotes
739*6ea1f93eSDaniel Fojt       && encountered_single_quote)
740*6ea1f93eSDaniel Fojt     {
741*6ea1f93eSDaniel Fojt       if (all_c_and_shell_quote_compat)
742*6ea1f93eSDaniel Fojt         return quotearg_buffer_restyled (buffer, orig_buffersize, arg, argsize,
743*6ea1f93eSDaniel Fojt                                          c_quoting_style,
744*6ea1f93eSDaniel Fojt                                          flags, quote_these_too,
745*6ea1f93eSDaniel Fojt                                          left_quote, right_quote);
746*6ea1f93eSDaniel Fojt       else if (! buffersize && orig_buffersize)
747*6ea1f93eSDaniel Fojt         {
748*6ea1f93eSDaniel Fojt           /* Disable read-only scan, and reprocess to write quoted string.  */
749*6ea1f93eSDaniel Fojt           buffersize = orig_buffersize;
750*6ea1f93eSDaniel Fojt           len = 0;
751*6ea1f93eSDaniel Fojt           goto process_input;
752*6ea1f93eSDaniel Fojt         }
753*6ea1f93eSDaniel Fojt     }
754*6ea1f93eSDaniel Fojt 
75544b87433SJohn Marino   if (quote_string && !elide_outer_quotes)
75644b87433SJohn Marino     for (; *quote_string; quote_string++)
75744b87433SJohn Marino       STORE (*quote_string);
75844b87433SJohn Marino 
75944b87433SJohn Marino   if (len < buffersize)
76044b87433SJohn Marino     buffer[len] = '\0';
76144b87433SJohn Marino   return len;
76244b87433SJohn Marino 
76344b87433SJohn Marino  force_outer_quoting_style:
76444b87433SJohn Marino   /* Don't reuse quote_these_too, since the addition of outer quotes
76544b87433SJohn Marino      sufficiently quotes the specified characters.  */
766*6ea1f93eSDaniel Fojt   if (quoting_style == shell_always_quoting_style && backslash_escapes)
767*6ea1f93eSDaniel Fojt     quoting_style = shell_escape_always_quoting_style;
76844b87433SJohn Marino   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
76944b87433SJohn Marino                                    quoting_style,
77044b87433SJohn Marino                                    flags & ~QA_ELIDE_OUTER_QUOTES, NULL,
77144b87433SJohn Marino                                    left_quote, right_quote);
77244b87433SJohn Marino }
77344b87433SJohn Marino 
77444b87433SJohn Marino /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
77544b87433SJohn Marino    argument ARG (of size ARGSIZE), using O to control quoting.
77644b87433SJohn Marino    If O is null, use the default.
77744b87433SJohn Marino    Terminate the output with a null character, and return the written
77844b87433SJohn Marino    size of the output, not counting the terminating null.
77944b87433SJohn Marino    If BUFFERSIZE is too small to store the output string, return the
78044b87433SJohn Marino    value that would have been returned had BUFFERSIZE been large enough.
78144b87433SJohn Marino    If ARGSIZE is SIZE_MAX, use the string length of the argument for
78244b87433SJohn Marino    ARGSIZE.  */
78344b87433SJohn Marino size_t
quotearg_buffer(char * buffer,size_t buffersize,char const * arg,size_t argsize,struct quoting_options const * o)78444b87433SJohn Marino quotearg_buffer (char *buffer, size_t buffersize,
78544b87433SJohn Marino                  char const *arg, size_t argsize,
78644b87433SJohn Marino                  struct quoting_options const *o)
78744b87433SJohn Marino {
78844b87433SJohn Marino   struct quoting_options const *p = o ? o : &default_quoting_options;
78944b87433SJohn Marino   int e = errno;
79044b87433SJohn Marino   size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
79144b87433SJohn Marino                                        p->style, p->flags, p->quote_these_too,
79244b87433SJohn Marino                                        p->left_quote, p->right_quote);
79344b87433SJohn Marino   errno = e;
79444b87433SJohn Marino   return r;
79544b87433SJohn Marino }
79644b87433SJohn Marino 
79744b87433SJohn Marino /* Equivalent to quotearg_alloc (ARG, ARGSIZE, NULL, O).  */
79844b87433SJohn Marino char *
quotearg_alloc(char const * arg,size_t argsize,struct quoting_options const * o)79944b87433SJohn Marino quotearg_alloc (char const *arg, size_t argsize,
80044b87433SJohn Marino                 struct quoting_options const *o)
80144b87433SJohn Marino {
80244b87433SJohn Marino   return quotearg_alloc_mem (arg, argsize, NULL, o);
80344b87433SJohn Marino }
80444b87433SJohn Marino 
80544b87433SJohn Marino /* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
80644b87433SJohn Marino    allocated storage containing the quoted string, and store the
80744b87433SJohn Marino    resulting size into *SIZE, if non-NULL.  The result can contain
80844b87433SJohn Marino    embedded null bytes only if ARGSIZE is not SIZE_MAX, SIZE is not
80944b87433SJohn Marino    NULL, and set_quoting_flags has not set the null byte elision
81044b87433SJohn Marino    flag.  */
81144b87433SJohn Marino char *
quotearg_alloc_mem(char const * arg,size_t argsize,size_t * size,struct quoting_options const * o)81244b87433SJohn Marino quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size,
81344b87433SJohn Marino                     struct quoting_options const *o)
81444b87433SJohn Marino {
81544b87433SJohn Marino   struct quoting_options const *p = o ? o : &default_quoting_options;
81644b87433SJohn Marino   int e = errno;
81744b87433SJohn Marino   /* Elide embedded null bytes if we can't return a size.  */
81844b87433SJohn Marino   int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES);
81944b87433SJohn Marino   size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style,
82044b87433SJohn Marino                                              flags, p->quote_these_too,
82144b87433SJohn Marino                                              p->left_quote,
82244b87433SJohn Marino                                              p->right_quote) + 1;
82344b87433SJohn Marino   char *buf = xcharalloc (bufsize);
82444b87433SJohn Marino   quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags,
82544b87433SJohn Marino                             p->quote_these_too,
82644b87433SJohn Marino                             p->left_quote, p->right_quote);
82744b87433SJohn Marino   errno = e;
82844b87433SJohn Marino   if (size)
82944b87433SJohn Marino     *size = bufsize - 1;
83044b87433SJohn Marino   return buf;
83144b87433SJohn Marino }
83244b87433SJohn Marino 
83344b87433SJohn Marino /* A storage slot with size and pointer to a value.  */
83444b87433SJohn Marino struct slotvec
83544b87433SJohn Marino {
83644b87433SJohn Marino   size_t size;
83744b87433SJohn Marino   char *val;
83844b87433SJohn Marino };
83944b87433SJohn Marino 
84044b87433SJohn Marino /* Preallocate a slot 0 buffer, so that the caller can always quote
84144b87433SJohn Marino    one small component of a "memory exhausted" message in slot 0.  */
84244b87433SJohn Marino static char slot0[256];
843*6ea1f93eSDaniel Fojt static int nslots = 1;
84444b87433SJohn Marino static struct slotvec slotvec0 = {sizeof slot0, slot0};
84544b87433SJohn Marino static struct slotvec *slotvec = &slotvec0;
84644b87433SJohn Marino 
84744b87433SJohn Marino void
quotearg_free(void)84844b87433SJohn Marino quotearg_free (void)
84944b87433SJohn Marino {
85044b87433SJohn Marino   struct slotvec *sv = slotvec;
851*6ea1f93eSDaniel Fojt   int i;
85244b87433SJohn Marino   for (i = 1; i < nslots; i++)
85344b87433SJohn Marino     free (sv[i].val);
85444b87433SJohn Marino   if (sv[0].val != slot0)
85544b87433SJohn Marino     {
85644b87433SJohn Marino       free (sv[0].val);
85744b87433SJohn Marino       slotvec0.size = sizeof slot0;
85844b87433SJohn Marino       slotvec0.val = slot0;
85944b87433SJohn Marino     }
86044b87433SJohn Marino   if (sv != &slotvec0)
86144b87433SJohn Marino     {
86244b87433SJohn Marino       free (sv);
86344b87433SJohn Marino       slotvec = &slotvec0;
86444b87433SJohn Marino     }
86544b87433SJohn Marino   nslots = 1;
86644b87433SJohn Marino }
86744b87433SJohn Marino 
86844b87433SJohn Marino /* Use storage slot N to return a quoted version of argument ARG.
86944b87433SJohn Marino    ARG is of size ARGSIZE, but if that is SIZE_MAX, ARG is a
87044b87433SJohn Marino    null-terminated string.
87144b87433SJohn Marino    OPTIONS specifies the quoting options.
87244b87433SJohn Marino    The returned value points to static storage that can be
87344b87433SJohn Marino    reused by the next call to this function with the same value of N.
87444b87433SJohn Marino    N must be nonnegative.  N is deliberately declared with type "int"
87544b87433SJohn Marino    to allow for future extensions (using negative values).  */
87644b87433SJohn Marino static char *
quotearg_n_options(int n,char const * arg,size_t argsize,struct quoting_options const * options)87744b87433SJohn Marino quotearg_n_options (int n, char const *arg, size_t argsize,
87844b87433SJohn Marino                     struct quoting_options const *options)
87944b87433SJohn Marino {
88044b87433SJohn Marino   int e = errno;
88144b87433SJohn Marino 
88244b87433SJohn Marino   struct slotvec *sv = slotvec;
88344b87433SJohn Marino 
88444b87433SJohn Marino   if (n < 0)
88544b87433SJohn Marino     abort ();
88644b87433SJohn Marino 
887*6ea1f93eSDaniel Fojt   if (nslots <= n)
88844b87433SJohn Marino     {
88944b87433SJohn Marino       bool preallocated = (sv == &slotvec0);
890*6ea1f93eSDaniel Fojt       int nmax = MIN (INT_MAX, MIN (PTRDIFF_MAX, SIZE_MAX) / sizeof *sv) - 1;
89144b87433SJohn Marino 
892*6ea1f93eSDaniel Fojt       if (nmax < n)
89344b87433SJohn Marino         xalloc_die ();
89444b87433SJohn Marino 
895*6ea1f93eSDaniel Fojt       slotvec = sv = xrealloc (preallocated ? NULL : sv, (n + 1) * sizeof *sv);
89644b87433SJohn Marino       if (preallocated)
89744b87433SJohn Marino         *sv = slotvec0;
898*6ea1f93eSDaniel Fojt       memset (sv + nslots, 0, (n + 1 - nslots) * sizeof *sv);
899*6ea1f93eSDaniel Fojt       nslots = n + 1;
90044b87433SJohn Marino     }
90144b87433SJohn Marino 
90244b87433SJohn Marino   {
90344b87433SJohn Marino     size_t size = sv[n].size;
90444b87433SJohn Marino     char *val = sv[n].val;
90544b87433SJohn Marino     /* Elide embedded null bytes since we don't return a size.  */
90644b87433SJohn Marino     int flags = options->flags | QA_ELIDE_NULL_BYTES;
90744b87433SJohn Marino     size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize,
90844b87433SJohn Marino                                              options->style, flags,
90944b87433SJohn Marino                                              options->quote_these_too,
91044b87433SJohn Marino                                              options->left_quote,
91144b87433SJohn Marino                                              options->right_quote);
91244b87433SJohn Marino 
91344b87433SJohn Marino     if (size <= qsize)
91444b87433SJohn Marino       {
91544b87433SJohn Marino         sv[n].size = size = qsize + 1;
91644b87433SJohn Marino         if (val != slot0)
91744b87433SJohn Marino           free (val);
91844b87433SJohn Marino         sv[n].val = val = xcharalloc (size);
91944b87433SJohn Marino         quotearg_buffer_restyled (val, size, arg, argsize, options->style,
92044b87433SJohn Marino                                   flags, options->quote_these_too,
92144b87433SJohn Marino                                   options->left_quote,
92244b87433SJohn Marino                                   options->right_quote);
92344b87433SJohn Marino       }
92444b87433SJohn Marino 
92544b87433SJohn Marino     errno = e;
92644b87433SJohn Marino     return val;
92744b87433SJohn Marino   }
92844b87433SJohn Marino }
92944b87433SJohn Marino 
93044b87433SJohn Marino char *
quotearg_n(int n,char const * arg)93144b87433SJohn Marino quotearg_n (int n, char const *arg)
93244b87433SJohn Marino {
93344b87433SJohn Marino   return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options);
93444b87433SJohn Marino }
93544b87433SJohn Marino 
93644b87433SJohn Marino char *
quotearg_n_mem(int n,char const * arg,size_t argsize)93744b87433SJohn Marino quotearg_n_mem (int n, char const *arg, size_t argsize)
93844b87433SJohn Marino {
93944b87433SJohn Marino   return quotearg_n_options (n, arg, argsize, &default_quoting_options);
94044b87433SJohn Marino }
94144b87433SJohn Marino 
94244b87433SJohn Marino char *
quotearg(char const * arg)94344b87433SJohn Marino quotearg (char const *arg)
94444b87433SJohn Marino {
94544b87433SJohn Marino   return quotearg_n (0, arg);
94644b87433SJohn Marino }
94744b87433SJohn Marino 
94844b87433SJohn Marino char *
quotearg_mem(char const * arg,size_t argsize)94944b87433SJohn Marino quotearg_mem (char const *arg, size_t argsize)
95044b87433SJohn Marino {
95144b87433SJohn Marino   return quotearg_n_mem (0, arg, argsize);
95244b87433SJohn Marino }
95344b87433SJohn Marino 
95444b87433SJohn Marino char *
quotearg_n_style(int n,enum quoting_style s,char const * arg)95544b87433SJohn Marino quotearg_n_style (int n, enum quoting_style s, char const *arg)
95644b87433SJohn Marino {
95744b87433SJohn Marino   struct quoting_options const o = quoting_options_from_style (s);
95844b87433SJohn Marino   return quotearg_n_options (n, arg, SIZE_MAX, &o);
95944b87433SJohn Marino }
96044b87433SJohn Marino 
96144b87433SJohn Marino char *
quotearg_n_style_mem(int n,enum quoting_style s,char const * arg,size_t argsize)96244b87433SJohn Marino quotearg_n_style_mem (int n, enum quoting_style s,
96344b87433SJohn Marino                       char const *arg, size_t argsize)
96444b87433SJohn Marino {
96544b87433SJohn Marino   struct quoting_options const o = quoting_options_from_style (s);
96644b87433SJohn Marino   return quotearg_n_options (n, arg, argsize, &o);
96744b87433SJohn Marino }
96844b87433SJohn Marino 
96944b87433SJohn Marino char *
quotearg_style(enum quoting_style s,char const * arg)97044b87433SJohn Marino quotearg_style (enum quoting_style s, char const *arg)
97144b87433SJohn Marino {
97244b87433SJohn Marino   return quotearg_n_style (0, s, arg);
97344b87433SJohn Marino }
97444b87433SJohn Marino 
97544b87433SJohn Marino char *
quotearg_style_mem(enum quoting_style s,char const * arg,size_t argsize)97644b87433SJohn Marino quotearg_style_mem (enum quoting_style s, char const *arg, size_t argsize)
97744b87433SJohn Marino {
97844b87433SJohn Marino   return quotearg_n_style_mem (0, s, arg, argsize);
97944b87433SJohn Marino }
98044b87433SJohn Marino 
98144b87433SJohn Marino char *
quotearg_char_mem(char const * arg,size_t argsize,char ch)98244b87433SJohn Marino quotearg_char_mem (char const *arg, size_t argsize, char ch)
98344b87433SJohn Marino {
98444b87433SJohn Marino   struct quoting_options options;
98544b87433SJohn Marino   options = default_quoting_options;
98644b87433SJohn Marino   set_char_quoting (&options, ch, 1);
98744b87433SJohn Marino   return quotearg_n_options (0, arg, argsize, &options);
98844b87433SJohn Marino }
98944b87433SJohn Marino 
99044b87433SJohn Marino char *
quotearg_char(char const * arg,char ch)99144b87433SJohn Marino quotearg_char (char const *arg, char ch)
99244b87433SJohn Marino {
99344b87433SJohn Marino   return quotearg_char_mem (arg, SIZE_MAX, ch);
99444b87433SJohn Marino }
99544b87433SJohn Marino 
99644b87433SJohn Marino char *
quotearg_colon(char const * arg)99744b87433SJohn Marino quotearg_colon (char const *arg)
99844b87433SJohn Marino {
99944b87433SJohn Marino   return quotearg_char (arg, ':');
100044b87433SJohn Marino }
100144b87433SJohn Marino 
100244b87433SJohn Marino char *
quotearg_colon_mem(char const * arg,size_t argsize)100344b87433SJohn Marino quotearg_colon_mem (char const *arg, size_t argsize)
100444b87433SJohn Marino {
100544b87433SJohn Marino   return quotearg_char_mem (arg, argsize, ':');
100644b87433SJohn Marino }
100744b87433SJohn Marino 
100844b87433SJohn Marino char *
quotearg_n_style_colon(int n,enum quoting_style s,char const * arg)1009*6ea1f93eSDaniel Fojt quotearg_n_style_colon (int n, enum quoting_style s, char const *arg)
1010*6ea1f93eSDaniel Fojt {
1011*6ea1f93eSDaniel Fojt   struct quoting_options options;
1012*6ea1f93eSDaniel Fojt   options = quoting_options_from_style (s);
1013*6ea1f93eSDaniel Fojt   set_char_quoting (&options, ':', 1);
1014*6ea1f93eSDaniel Fojt   return quotearg_n_options (n, arg, SIZE_MAX, &options);
1015*6ea1f93eSDaniel Fojt }
1016*6ea1f93eSDaniel Fojt 
1017*6ea1f93eSDaniel Fojt char *
quotearg_n_custom(int n,char const * left_quote,char const * right_quote,char const * arg)101844b87433SJohn Marino quotearg_n_custom (int n, char const *left_quote,
101944b87433SJohn Marino                    char const *right_quote, char const *arg)
102044b87433SJohn Marino {
102144b87433SJohn Marino   return quotearg_n_custom_mem (n, left_quote, right_quote, arg,
102244b87433SJohn Marino                                 SIZE_MAX);
102344b87433SJohn Marino }
102444b87433SJohn Marino 
102544b87433SJohn Marino char *
quotearg_n_custom_mem(int n,char const * left_quote,char const * right_quote,char const * arg,size_t argsize)102644b87433SJohn Marino quotearg_n_custom_mem (int n, char const *left_quote,
102744b87433SJohn Marino                        char const *right_quote,
102844b87433SJohn Marino                        char const *arg, size_t argsize)
102944b87433SJohn Marino {
103044b87433SJohn Marino   struct quoting_options o = default_quoting_options;
103144b87433SJohn Marino   set_custom_quoting (&o, left_quote, right_quote);
103244b87433SJohn Marino   return quotearg_n_options (n, arg, argsize, &o);
103344b87433SJohn Marino }
103444b87433SJohn Marino 
103544b87433SJohn Marino char *
quotearg_custom(char const * left_quote,char const * right_quote,char const * arg)103644b87433SJohn Marino quotearg_custom (char const *left_quote, char const *right_quote,
103744b87433SJohn Marino                  char const *arg)
103844b87433SJohn Marino {
103944b87433SJohn Marino   return quotearg_n_custom (0, left_quote, right_quote, arg);
104044b87433SJohn Marino }
104144b87433SJohn Marino 
104244b87433SJohn Marino char *
quotearg_custom_mem(char const * left_quote,char const * right_quote,char const * arg,size_t argsize)104344b87433SJohn Marino quotearg_custom_mem (char const *left_quote, char const *right_quote,
104444b87433SJohn Marino                      char const *arg, size_t argsize)
104544b87433SJohn Marino {
104644b87433SJohn Marino   return quotearg_n_custom_mem (0, left_quote, right_quote, arg,
104744b87433SJohn Marino                                 argsize);
104844b87433SJohn Marino }
10494536c563SJohn Marino 
10504536c563SJohn Marino 
10514536c563SJohn Marino /* The quoting option used by the functions of quote.h.  */
10524536c563SJohn Marino struct quoting_options quote_quoting_options =
10534536c563SJohn Marino   {
10544536c563SJohn Marino     locale_quoting_style,
10554536c563SJohn Marino     0,
10564536c563SJohn Marino     { 0 },
10574536c563SJohn Marino     NULL, NULL
10584536c563SJohn Marino   };
10594536c563SJohn Marino 
10604536c563SJohn Marino char const *
quote_n_mem(int n,char const * arg,size_t argsize)10614536c563SJohn Marino quote_n_mem (int n, char const *arg, size_t argsize)
10624536c563SJohn Marino {
10634536c563SJohn Marino   return quotearg_n_options (n, arg, argsize, &quote_quoting_options);
10644536c563SJohn Marino }
10654536c563SJohn Marino 
10664536c563SJohn Marino char const *
quote_mem(char const * arg,size_t argsize)10674536c563SJohn Marino quote_mem (char const *arg, size_t argsize)
10684536c563SJohn Marino {
10694536c563SJohn Marino   return quote_n_mem (0, arg, argsize);
10704536c563SJohn Marino }
10714536c563SJohn Marino 
10724536c563SJohn Marino char const *
quote_n(int n,char const * arg)10734536c563SJohn Marino quote_n (int n, char const *arg)
10744536c563SJohn Marino {
10754536c563SJohn Marino   return quote_n_mem (n, arg, SIZE_MAX);
10764536c563SJohn Marino }
10774536c563SJohn Marino 
10784536c563SJohn Marino char const *
quote(char const * arg)10794536c563SJohn Marino quote (char const *arg)
10804536c563SJohn Marino {
10814536c563SJohn Marino   return quote_n (0, arg);
10824536c563SJohn Marino }
1083*6ea1f93eSDaniel Fojt 
1084*6ea1f93eSDaniel Fojt /*
1085*6ea1f93eSDaniel Fojt  * Hey Emacs!
1086*6ea1f93eSDaniel Fojt  * Local Variables:
1087*6ea1f93eSDaniel Fojt  * coding: utf-8
1088*6ea1f93eSDaniel Fojt  * End:
1089*6ea1f93eSDaniel Fojt  */
1090