xref: /dragonfly/contrib/grep/lib/quotearg.c (revision 09d4459f)
195b7b453SJohn Marino /* quotearg.c - quote arguments for output
295b7b453SJohn Marino 
3*09d4459fSDaniel Fojt    Copyright (C) 1998-2002, 2004-2020 Free Software Foundation, Inc.
495b7b453SJohn Marino 
595b7b453SJohn Marino    This program is free software: you can redistribute it and/or modify
695b7b453SJohn Marino    it under the terms of the GNU General Public License as published by
795b7b453SJohn Marino    the Free Software Foundation; either version 3 of the License, or
895b7b453SJohn Marino    (at your option) any later version.
995b7b453SJohn Marino 
1095b7b453SJohn Marino    This program is distributed in the hope that it will be useful,
1195b7b453SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1295b7b453SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1395b7b453SJohn Marino    GNU General Public License for more details.
1495b7b453SJohn Marino 
1595b7b453SJohn Marino    You should have received a copy of the GNU General Public License
16*09d4459fSDaniel Fojt    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
1795b7b453SJohn Marino 
1895b7b453SJohn Marino /* Written by Paul Eggert <eggert@twinsun.com> */
1995b7b453SJohn Marino 
20cf28ed85SJohn Marino /* Without this pragma, gcc 4.7.0 20111124 mistakenly suggests that
21cf28ed85SJohn Marino    the quoting_options_from_style function might be candidate for
22cf28ed85SJohn Marino    attribute 'pure'  */
23cf28ed85SJohn Marino #if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
24cf28ed85SJohn Marino # pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
25cf28ed85SJohn Marino #endif
26cf28ed85SJohn Marino 
2795b7b453SJohn Marino #include <config.h>
2895b7b453SJohn Marino 
2995b7b453SJohn Marino #include "quotearg.h"
30cf28ed85SJohn Marino #include "quote.h"
3195b7b453SJohn Marino 
32*09d4459fSDaniel Fojt #include "minmax.h"
3395b7b453SJohn Marino #include "xalloc.h"
34cf28ed85SJohn Marino #include "c-strcaseeq.h"
35cf28ed85SJohn Marino #include "localcharset.h"
3695b7b453SJohn Marino 
3795b7b453SJohn Marino #include <ctype.h>
3895b7b453SJohn Marino #include <errno.h>
3995b7b453SJohn Marino #include <limits.h>
4095b7b453SJohn Marino #include <stdbool.h>
41*09d4459fSDaniel Fojt #include <stdint.h>
4295b7b453SJohn Marino #include <stdlib.h>
4395b7b453SJohn Marino #include <string.h>
4495b7b453SJohn Marino #include <wchar.h>
4595b7b453SJohn Marino #include <wctype.h>
4695b7b453SJohn Marino 
4795b7b453SJohn Marino #include "gettext.h"
4895b7b453SJohn Marino #define _(msgid) gettext (msgid)
4995b7b453SJohn Marino #define N_(msgid) msgid
5095b7b453SJohn Marino 
5195b7b453SJohn Marino #ifndef SIZE_MAX
5295b7b453SJohn Marino # define SIZE_MAX ((size_t) -1)
5395b7b453SJohn Marino #endif
5495b7b453SJohn Marino 
5595b7b453SJohn Marino #define INT_BITS (sizeof (int) * CHAR_BIT)
5695b7b453SJohn Marino 
57*09d4459fSDaniel Fojt #ifndef FALLTHROUGH
58*09d4459fSDaniel Fojt # if __GNUC__ < 7
59*09d4459fSDaniel Fojt #  define FALLTHROUGH ((void) 0)
60*09d4459fSDaniel Fojt # else
61*09d4459fSDaniel Fojt #  define FALLTHROUGH __attribute__ ((__fallthrough__))
62*09d4459fSDaniel Fojt # endif
63*09d4459fSDaniel Fojt #endif
64*09d4459fSDaniel Fojt 
6595b7b453SJohn Marino struct quoting_options
6695b7b453SJohn Marino {
6795b7b453SJohn Marino   /* Basic quoting style.  */
6895b7b453SJohn Marino   enum quoting_style style;
6995b7b453SJohn Marino 
7095b7b453SJohn Marino   /* Additional flags.  Bitwise combination of enum quoting_flags.  */
7195b7b453SJohn Marino   int flags;
7295b7b453SJohn Marino 
7395b7b453SJohn Marino   /* Quote the characters indicated by this bit vector even if the
7495b7b453SJohn Marino      quoting style would not normally require them to be quoted.  */
7595b7b453SJohn Marino   unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
7695b7b453SJohn Marino 
7795b7b453SJohn Marino   /* The left quote for custom_quoting_style.  */
7895b7b453SJohn Marino   char const *left_quote;
7995b7b453SJohn Marino 
8095b7b453SJohn Marino   /* The right quote for custom_quoting_style.  */
8195b7b453SJohn Marino   char const *right_quote;
8295b7b453SJohn Marino };
8395b7b453SJohn Marino 
8495b7b453SJohn Marino /* Names of quoting styles.  */
8595b7b453SJohn Marino char const *const quoting_style_args[] =
8695b7b453SJohn Marino {
8795b7b453SJohn Marino   "literal",
8895b7b453SJohn Marino   "shell",
8995b7b453SJohn Marino   "shell-always",
90*09d4459fSDaniel Fojt   "shell-escape",
91*09d4459fSDaniel Fojt   "shell-escape-always",
9295b7b453SJohn Marino   "c",
9395b7b453SJohn Marino   "c-maybe",
9495b7b453SJohn Marino   "escape",
9595b7b453SJohn Marino   "locale",
9695b7b453SJohn Marino   "clocale",
9795b7b453SJohn Marino   0
9895b7b453SJohn Marino };
9995b7b453SJohn Marino 
10095b7b453SJohn Marino /* Correspondences to quoting style names.  */
10195b7b453SJohn Marino enum quoting_style const quoting_style_vals[] =
10295b7b453SJohn Marino {
10395b7b453SJohn Marino   literal_quoting_style,
10495b7b453SJohn Marino   shell_quoting_style,
10595b7b453SJohn Marino   shell_always_quoting_style,
106*09d4459fSDaniel Fojt   shell_escape_quoting_style,
107*09d4459fSDaniel Fojt   shell_escape_always_quoting_style,
10895b7b453SJohn Marino   c_quoting_style,
10995b7b453SJohn Marino   c_maybe_quoting_style,
11095b7b453SJohn Marino   escape_quoting_style,
11195b7b453SJohn Marino   locale_quoting_style,
11295b7b453SJohn Marino   clocale_quoting_style
11395b7b453SJohn Marino };
11495b7b453SJohn Marino 
11595b7b453SJohn Marino /* The default quoting options.  */
11695b7b453SJohn Marino static struct quoting_options default_quoting_options;
11795b7b453SJohn Marino 
11895b7b453SJohn Marino /* Allocate a new set of quoting options, with contents initially identical
11995b7b453SJohn Marino    to O if O is not null, or to the default if O is null.
12095b7b453SJohn Marino    It is the caller's responsibility to free the result.  */
12195b7b453SJohn Marino struct quoting_options *
clone_quoting_options(struct quoting_options * o)12295b7b453SJohn Marino clone_quoting_options (struct quoting_options *o)
12395b7b453SJohn Marino {
12495b7b453SJohn Marino   int e = errno;
12595b7b453SJohn Marino   struct quoting_options *p = xmemdup (o ? o : &default_quoting_options,
12695b7b453SJohn Marino                                        sizeof *o);
12795b7b453SJohn Marino   errno = e;
12895b7b453SJohn Marino   return p;
12995b7b453SJohn Marino }
13095b7b453SJohn Marino 
13195b7b453SJohn Marino /* Get the value of O's quoting style.  If O is null, use the default.  */
13295b7b453SJohn Marino enum quoting_style
get_quoting_style(struct quoting_options const * o)133*09d4459fSDaniel Fojt get_quoting_style (struct quoting_options const *o)
13495b7b453SJohn Marino {
13595b7b453SJohn Marino   return (o ? o : &default_quoting_options)->style;
13695b7b453SJohn Marino }
13795b7b453SJohn Marino 
13895b7b453SJohn Marino /* In O (or in the default if O is null),
13995b7b453SJohn Marino    set the value of the quoting style to S.  */
14095b7b453SJohn Marino void
set_quoting_style(struct quoting_options * o,enum quoting_style s)14195b7b453SJohn Marino set_quoting_style (struct quoting_options *o, enum quoting_style s)
14295b7b453SJohn Marino {
14395b7b453SJohn Marino   (o ? o : &default_quoting_options)->style = s;
14495b7b453SJohn Marino }
14595b7b453SJohn Marino 
14695b7b453SJohn Marino /* In O (or in the default if O is null),
14795b7b453SJohn Marino    set the value of the quoting options for character C to I.
14895b7b453SJohn Marino    Return the old value.  Currently, the only values defined for I are
14995b7b453SJohn Marino    0 (the default) and 1 (which means to quote the character even if
15095b7b453SJohn Marino    it would not otherwise be quoted).  */
15195b7b453SJohn Marino int
set_char_quoting(struct quoting_options * o,char c,int i)15295b7b453SJohn Marino set_char_quoting (struct quoting_options *o, char c, int i)
15395b7b453SJohn Marino {
15495b7b453SJohn Marino   unsigned char uc = c;
15595b7b453SJohn Marino   unsigned int *p =
15695b7b453SJohn Marino     (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
15795b7b453SJohn Marino   int shift = uc % INT_BITS;
15895b7b453SJohn Marino   int r = (*p >> shift) & 1;
15995b7b453SJohn Marino   *p ^= ((i & 1) ^ r) << shift;
16095b7b453SJohn Marino   return r;
16195b7b453SJohn Marino }
16295b7b453SJohn Marino 
16395b7b453SJohn Marino /* In O (or in the default if O is null),
16495b7b453SJohn Marino    set the value of the quoting options flag to I, which can be a
16595b7b453SJohn Marino    bitwise combination of enum quoting_flags, or 0 for default
16695b7b453SJohn Marino    behavior.  Return the old value.  */
16795b7b453SJohn Marino int
set_quoting_flags(struct quoting_options * o,int i)16895b7b453SJohn Marino set_quoting_flags (struct quoting_options *o, int i)
16995b7b453SJohn Marino {
17095b7b453SJohn Marino   int r;
17195b7b453SJohn Marino   if (!o)
17295b7b453SJohn Marino     o = &default_quoting_options;
17395b7b453SJohn Marino   r = o->flags;
17495b7b453SJohn Marino   o->flags = i;
17595b7b453SJohn Marino   return r;
17695b7b453SJohn Marino }
17795b7b453SJohn Marino 
17895b7b453SJohn Marino void
set_custom_quoting(struct quoting_options * o,char const * left_quote,char const * right_quote)17995b7b453SJohn Marino set_custom_quoting (struct quoting_options *o,
18095b7b453SJohn Marino                     char const *left_quote, char const *right_quote)
18195b7b453SJohn Marino {
18295b7b453SJohn Marino   if (!o)
18395b7b453SJohn Marino     o = &default_quoting_options;
18495b7b453SJohn Marino   o->style = custom_quoting_style;
18595b7b453SJohn Marino   if (!left_quote || !right_quote)
18695b7b453SJohn Marino     abort ();
18795b7b453SJohn Marino   o->left_quote = left_quote;
18895b7b453SJohn Marino   o->right_quote = right_quote;
18995b7b453SJohn Marino }
19095b7b453SJohn Marino 
19195b7b453SJohn Marino /* Return quoting options for STYLE, with no extra quoting.  */
192cf28ed85SJohn Marino static struct quoting_options /* NOT PURE!! */
quoting_options_from_style(enum quoting_style style)19395b7b453SJohn Marino quoting_options_from_style (enum quoting_style style)
19495b7b453SJohn Marino {
195680a9cb8SJohn Marino   struct quoting_options o = { literal_quoting_style, 0, { 0 }, NULL, NULL };
196200fbe8dSJohn Marino   if (style == custom_quoting_style)
197200fbe8dSJohn Marino     abort ();
19895b7b453SJohn Marino   o.style = style;
19995b7b453SJohn Marino   return o;
20095b7b453SJohn Marino }
20195b7b453SJohn Marino 
20295b7b453SJohn Marino /* MSGID approximates a quotation mark.  Return its translation if it
203cf28ed85SJohn Marino    has one; otherwise, return either it or "\"", depending on S.
204cf28ed85SJohn Marino 
205cf28ed85SJohn Marino    S is either clocale_quoting_style or locale_quoting_style.  */
20695b7b453SJohn Marino static char const *
gettext_quote(char const * msgid,enum quoting_style s)20795b7b453SJohn Marino gettext_quote (char const *msgid, enum quoting_style s)
20895b7b453SJohn Marino {
20995b7b453SJohn Marino   char const *translation = _(msgid);
210cf28ed85SJohn Marino   char const *locale_code;
211cf28ed85SJohn Marino 
212cf28ed85SJohn Marino   if (translation != msgid)
21395b7b453SJohn Marino     return translation;
214cf28ed85SJohn Marino 
215cf28ed85SJohn Marino   /* For UTF-8 and GB-18030, use single quotes U+2018 and U+2019.
216cf28ed85SJohn Marino      Here is a list of other locales that include U+2018 and U+2019:
217cf28ed85SJohn Marino 
218cf28ed85SJohn Marino         ISO-8859-7   0xA1                 KOI8-T       0x91
219cf28ed85SJohn Marino         CP869        0x8B                 CP874        0x91
220cf28ed85SJohn Marino         CP932        0x81 0x65            CP936        0xA1 0xAE
221cf28ed85SJohn Marino         CP949        0xA1 0xAE            CP950        0xA1 0xA5
222cf28ed85SJohn Marino         CP1250       0x91                 CP1251       0x91
223cf28ed85SJohn Marino         CP1252       0x91                 CP1253       0x91
224cf28ed85SJohn Marino         CP1254       0x91                 CP1255       0x91
225cf28ed85SJohn Marino         CP1256       0x91                 CP1257       0x91
226cf28ed85SJohn Marino         EUC-JP       0xA1 0xC6            EUC-KR       0xA1 0xAE
227cf28ed85SJohn Marino         EUC-TW       0xA1 0xE4            BIG5         0xA1 0xA5
228cf28ed85SJohn Marino         BIG5-HKSCS   0xA1 0xA5            EUC-CN       0xA1 0xAE
229cf28ed85SJohn Marino         GBK          0xA1 0xAE            Georgian-PS  0x91
230cf28ed85SJohn Marino         PT154        0x91
231cf28ed85SJohn Marino 
232cf28ed85SJohn Marino      None of these is still in wide use; using iconv is overkill.  */
233cf28ed85SJohn Marino   locale_code = locale_charset ();
234cf28ed85SJohn Marino   if (STRCASEEQ (locale_code, "UTF-8", 'U','T','F','-','8',0,0,0,0))
235cf28ed85SJohn Marino     return msgid[0] == '`' ? "\xe2\x80\x98": "\xe2\x80\x99";
236cf28ed85SJohn Marino   if (STRCASEEQ (locale_code, "GB18030", 'G','B','1','8','0','3','0',0,0))
237cf28ed85SJohn Marino     return msgid[0] == '`' ? "\xa1\ae": "\xa1\xaf";
238cf28ed85SJohn Marino 
239cf28ed85SJohn Marino   return (s == clocale_quoting_style ? "\"" : "'");
24095b7b453SJohn Marino }
24195b7b453SJohn Marino 
24295b7b453SJohn Marino /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
24395b7b453SJohn Marino    argument ARG (of size ARGSIZE), using QUOTING_STYLE, FLAGS, and
24495b7b453SJohn Marino    QUOTE_THESE_TOO to control quoting.
24595b7b453SJohn Marino    Terminate the output with a null character, and return the written
24695b7b453SJohn Marino    size of the output, not counting the terminating null.
24795b7b453SJohn Marino    If BUFFERSIZE is too small to store the output string, return the
24895b7b453SJohn Marino    value that would have been returned had BUFFERSIZE been large enough.
24995b7b453SJohn Marino    If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE.
25095b7b453SJohn Marino 
25195b7b453SJohn Marino    This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
25295b7b453SJohn Marino    ARGSIZE, O), except it breaks O into its component pieces and is
25395b7b453SJohn Marino    not careful about errno.  */
25495b7b453SJohn Marino 
25595b7b453SJohn 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)25695b7b453SJohn Marino quotearg_buffer_restyled (char *buffer, size_t buffersize,
25795b7b453SJohn Marino                           char const *arg, size_t argsize,
25895b7b453SJohn Marino                           enum quoting_style quoting_style, int flags,
25995b7b453SJohn Marino                           unsigned int const *quote_these_too,
26095b7b453SJohn Marino                           char const *left_quote,
26195b7b453SJohn Marino                           char const *right_quote)
26295b7b453SJohn Marino {
26395b7b453SJohn Marino   size_t i;
26495b7b453SJohn Marino   size_t len = 0;
265*09d4459fSDaniel Fojt   size_t orig_buffersize = 0;
26695b7b453SJohn Marino   char const *quote_string = 0;
26795b7b453SJohn Marino   size_t quote_string_len = 0;
26895b7b453SJohn Marino   bool backslash_escapes = false;
26995b7b453SJohn Marino   bool unibyte_locale = MB_CUR_MAX == 1;
27095b7b453SJohn Marino   bool elide_outer_quotes = (flags & QA_ELIDE_OUTER_QUOTES) != 0;
271*09d4459fSDaniel Fojt   bool pending_shell_escape_end = false;
272*09d4459fSDaniel Fojt   bool encountered_single_quote = false;
273*09d4459fSDaniel Fojt   bool all_c_and_shell_quote_compat = true;
27495b7b453SJohn Marino 
27595b7b453SJohn Marino #define STORE(c) \
27695b7b453SJohn Marino     do \
27795b7b453SJohn Marino       { \
27895b7b453SJohn Marino         if (len < buffersize) \
27995b7b453SJohn Marino           buffer[len] = (c); \
28095b7b453SJohn Marino         len++; \
28195b7b453SJohn Marino       } \
28295b7b453SJohn Marino     while (0)
28395b7b453SJohn Marino 
284*09d4459fSDaniel Fojt #define START_ESC() \
285*09d4459fSDaniel Fojt     do \
286*09d4459fSDaniel Fojt       { \
287*09d4459fSDaniel Fojt         if (elide_outer_quotes) \
288*09d4459fSDaniel Fojt           goto force_outer_quoting_style; \
289*09d4459fSDaniel Fojt         escaping = true; \
290*09d4459fSDaniel Fojt         if (quoting_style == shell_always_quoting_style \
291*09d4459fSDaniel Fojt             && ! pending_shell_escape_end) \
292*09d4459fSDaniel Fojt           { \
293*09d4459fSDaniel Fojt             STORE ('\''); \
294*09d4459fSDaniel Fojt             STORE ('$'); \
295*09d4459fSDaniel Fojt             STORE ('\''); \
296*09d4459fSDaniel Fojt             pending_shell_escape_end = true; \
297*09d4459fSDaniel Fojt           } \
298*09d4459fSDaniel Fojt         STORE ('\\'); \
299*09d4459fSDaniel Fojt       } \
300*09d4459fSDaniel Fojt     while (0)
301*09d4459fSDaniel Fojt 
302*09d4459fSDaniel Fojt #define END_ESC() \
303*09d4459fSDaniel Fojt     do \
304*09d4459fSDaniel Fojt       { \
305*09d4459fSDaniel Fojt         if (pending_shell_escape_end && ! escaping) \
306*09d4459fSDaniel Fojt           { \
307*09d4459fSDaniel Fojt             STORE ('\''); \
308*09d4459fSDaniel Fojt             STORE ('\''); \
309*09d4459fSDaniel Fojt             pending_shell_escape_end = false; \
310*09d4459fSDaniel Fojt           } \
311*09d4459fSDaniel Fojt       } \
312*09d4459fSDaniel Fojt     while (0)
313*09d4459fSDaniel Fojt 
314*09d4459fSDaniel Fojt  process_input:
315*09d4459fSDaniel Fojt 
31695b7b453SJohn Marino   switch (quoting_style)
31795b7b453SJohn Marino     {
31895b7b453SJohn Marino     case c_maybe_quoting_style:
31995b7b453SJohn Marino       quoting_style = c_quoting_style;
32095b7b453SJohn Marino       elide_outer_quotes = true;
321*09d4459fSDaniel Fojt       FALLTHROUGH;
32295b7b453SJohn Marino     case c_quoting_style:
32395b7b453SJohn Marino       if (!elide_outer_quotes)
32495b7b453SJohn Marino         STORE ('"');
32595b7b453SJohn Marino       backslash_escapes = true;
32695b7b453SJohn Marino       quote_string = "\"";
32795b7b453SJohn Marino       quote_string_len = 1;
32895b7b453SJohn Marino       break;
32995b7b453SJohn Marino 
33095b7b453SJohn Marino     case escape_quoting_style:
33195b7b453SJohn Marino       backslash_escapes = true;
33295b7b453SJohn Marino       elide_outer_quotes = false;
33395b7b453SJohn Marino       break;
33495b7b453SJohn Marino 
33595b7b453SJohn Marino     case locale_quoting_style:
33695b7b453SJohn Marino     case clocale_quoting_style:
33795b7b453SJohn Marino     case custom_quoting_style:
33895b7b453SJohn Marino       {
33995b7b453SJohn Marino         if (quoting_style != custom_quoting_style)
34095b7b453SJohn Marino           {
34195b7b453SJohn Marino             /* TRANSLATORS:
34295b7b453SJohn Marino                Get translations for open and closing quotation marks.
34395b7b453SJohn Marino                The message catalog should translate "`" to a left
34495b7b453SJohn Marino                quotation mark suitable for the locale, and similarly for
345cf28ed85SJohn Marino                "'".  For example, a French Unicode local should translate
346cf28ed85SJohn Marino                these to U+00AB (LEFT-POINTING DOUBLE ANGLE
347cf28ed85SJohn Marino                QUOTATION MARK), and U+00BB (RIGHT-POINTING DOUBLE ANGLE
348cf28ed85SJohn Marino                QUOTATION MARK), respectively.
34995b7b453SJohn Marino 
350cf28ed85SJohn Marino                If the catalog has no translation, we will try to
351cf28ed85SJohn Marino                use Unicode U+2018 (LEFT SINGLE QUOTATION MARK) and
352cf28ed85SJohn Marino                Unicode U+2019 (RIGHT SINGLE QUOTATION MARK).  If the
353cf28ed85SJohn Marino                current locale is not Unicode, locale_quoting_style
354cf28ed85SJohn Marino                will quote 'like this', and clocale_quoting_style will
355cf28ed85SJohn Marino                quote "like this".  You should always include translations
356cf28ed85SJohn Marino                for "`" and "'" even if U+2018 and U+2019 are appropriate
357cf28ed85SJohn Marino                for your locale.
35895b7b453SJohn Marino 
35995b7b453SJohn Marino                If you don't know what to put here, please see
360*09d4459fSDaniel Fojt                <https://en.wikipedia.org/wiki/Quotation_marks_in_other_languages>
36195b7b453SJohn Marino                and use glyphs suitable for your language.  */
36295b7b453SJohn Marino             left_quote = gettext_quote (N_("`"), quoting_style);
36395b7b453SJohn Marino             right_quote = gettext_quote (N_("'"), quoting_style);
36495b7b453SJohn Marino           }
36595b7b453SJohn Marino         if (!elide_outer_quotes)
36695b7b453SJohn Marino           for (quote_string = left_quote; *quote_string; quote_string++)
36795b7b453SJohn Marino             STORE (*quote_string);
36895b7b453SJohn Marino         backslash_escapes = true;
36995b7b453SJohn Marino         quote_string = right_quote;
37095b7b453SJohn Marino         quote_string_len = strlen (quote_string);
37195b7b453SJohn Marino       }
37295b7b453SJohn Marino       break;
37395b7b453SJohn Marino 
374*09d4459fSDaniel Fojt     case shell_escape_quoting_style:
375*09d4459fSDaniel Fojt       backslash_escapes = true;
376*09d4459fSDaniel Fojt       FALLTHROUGH;
37795b7b453SJohn Marino     case shell_quoting_style:
37895b7b453SJohn Marino       elide_outer_quotes = true;
379*09d4459fSDaniel Fojt       FALLTHROUGH;
380*09d4459fSDaniel Fojt     case shell_escape_always_quoting_style:
381*09d4459fSDaniel Fojt       if (!elide_outer_quotes)
382*09d4459fSDaniel Fojt         backslash_escapes = true;
383*09d4459fSDaniel Fojt       FALLTHROUGH;
38495b7b453SJohn Marino     case shell_always_quoting_style:
385*09d4459fSDaniel Fojt       quoting_style = shell_always_quoting_style;
38695b7b453SJohn Marino       if (!elide_outer_quotes)
38795b7b453SJohn Marino         STORE ('\'');
38895b7b453SJohn Marino       quote_string = "'";
38995b7b453SJohn Marino       quote_string_len = 1;
39095b7b453SJohn Marino       break;
39195b7b453SJohn Marino 
39295b7b453SJohn Marino     case literal_quoting_style:
39395b7b453SJohn Marino       elide_outer_quotes = false;
39495b7b453SJohn Marino       break;
39595b7b453SJohn Marino 
39695b7b453SJohn Marino     default:
39795b7b453SJohn Marino       abort ();
39895b7b453SJohn Marino     }
39995b7b453SJohn Marino 
40095b7b453SJohn Marino   for (i = 0;  ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize);  i++)
40195b7b453SJohn Marino     {
40295b7b453SJohn Marino       unsigned char c;
40395b7b453SJohn Marino       unsigned char esc;
40495b7b453SJohn Marino       bool is_right_quote = false;
405*09d4459fSDaniel Fojt       bool escaping = false;
406*09d4459fSDaniel Fojt       bool c_and_shell_quote_compat = false;
40795b7b453SJohn Marino 
40895b7b453SJohn Marino       if (backslash_escapes
409*09d4459fSDaniel Fojt           && quoting_style != shell_always_quoting_style
41095b7b453SJohn Marino           && quote_string_len
411680a9cb8SJohn Marino           && (i + quote_string_len
412680a9cb8SJohn Marino               <= (argsize == SIZE_MAX && 1 < quote_string_len
413680a9cb8SJohn Marino                   /* Use strlen only if we must: when argsize is SIZE_MAX,
414680a9cb8SJohn Marino                      and when the quote string is more than 1 byte long.
415680a9cb8SJohn Marino                      If we do call strlen, save the result.  */
416680a9cb8SJohn Marino                   ? (argsize = strlen (arg)) : argsize))
41795b7b453SJohn Marino           && memcmp (arg + i, quote_string, quote_string_len) == 0)
41895b7b453SJohn Marino         {
41995b7b453SJohn Marino           if (elide_outer_quotes)
42095b7b453SJohn Marino             goto force_outer_quoting_style;
42195b7b453SJohn Marino           is_right_quote = true;
42295b7b453SJohn Marino         }
42395b7b453SJohn Marino 
42495b7b453SJohn Marino       c = arg[i];
42595b7b453SJohn Marino       switch (c)
42695b7b453SJohn Marino         {
42795b7b453SJohn Marino         case '\0':
42895b7b453SJohn Marino           if (backslash_escapes)
42995b7b453SJohn Marino             {
430*09d4459fSDaniel Fojt               START_ESC ();
43195b7b453SJohn Marino               /* If quote_string were to begin with digits, we'd need to
43295b7b453SJohn Marino                  test for the end of the arg as well.  However, it's
43395b7b453SJohn Marino                  hard to imagine any locale that would use digits in
43495b7b453SJohn Marino                  quotes, and set_custom_quoting is documented not to
435*09d4459fSDaniel Fojt                  accept them.  Use only a single \0 with shell-escape
436*09d4459fSDaniel Fojt                  as currently digits are not printed within $'...'  */
437*09d4459fSDaniel Fojt               if (quoting_style != shell_always_quoting_style
438*09d4459fSDaniel Fojt                   && i + 1 < argsize && '0' <= arg[i + 1] && arg[i + 1] <= '9')
43995b7b453SJohn Marino                 {
44095b7b453SJohn Marino                   STORE ('0');
44195b7b453SJohn Marino                   STORE ('0');
44295b7b453SJohn Marino                 }
44395b7b453SJohn Marino               c = '0';
44495b7b453SJohn Marino               /* We don't have to worry that this last '0' will be
44595b7b453SJohn Marino                  backslash-escaped because, again, quote_string should
44695b7b453SJohn Marino                  not start with it and because quote_these_too is
44795b7b453SJohn Marino                  documented as not accepting it.  */
44895b7b453SJohn Marino             }
44995b7b453SJohn Marino           else if (flags & QA_ELIDE_NULL_BYTES)
45095b7b453SJohn Marino             continue;
45195b7b453SJohn Marino           break;
45295b7b453SJohn Marino 
45395b7b453SJohn Marino         case '?':
45495b7b453SJohn Marino           switch (quoting_style)
45595b7b453SJohn Marino             {
45695b7b453SJohn Marino             case shell_always_quoting_style:
45795b7b453SJohn Marino               if (elide_outer_quotes)
45895b7b453SJohn Marino                 goto force_outer_quoting_style;
45995b7b453SJohn Marino               break;
46095b7b453SJohn Marino 
46195b7b453SJohn Marino             case c_quoting_style:
46295b7b453SJohn Marino               if ((flags & QA_SPLIT_TRIGRAPHS)
46395b7b453SJohn Marino                   && i + 2 < argsize && arg[i + 1] == '?')
46495b7b453SJohn Marino                 switch (arg[i + 2])
46595b7b453SJohn Marino                   {
46695b7b453SJohn Marino                   case '!': case '\'':
46795b7b453SJohn Marino                   case '(': case ')': case '-': case '/':
46895b7b453SJohn Marino                   case '<': case '=': case '>':
46995b7b453SJohn Marino                     /* Escape the second '?' in what would otherwise be
47095b7b453SJohn Marino                        a trigraph.  */
47195b7b453SJohn Marino                     if (elide_outer_quotes)
47295b7b453SJohn Marino                       goto force_outer_quoting_style;
47395b7b453SJohn Marino                     c = arg[i + 2];
47495b7b453SJohn Marino                     i += 2;
47595b7b453SJohn Marino                     STORE ('?');
47695b7b453SJohn Marino                     STORE ('"');
47795b7b453SJohn Marino                     STORE ('"');
47895b7b453SJohn Marino                     STORE ('?');
47995b7b453SJohn Marino                     break;
48095b7b453SJohn Marino 
48195b7b453SJohn Marino                   default:
48295b7b453SJohn Marino                     break;
48395b7b453SJohn Marino                   }
48495b7b453SJohn Marino               break;
48595b7b453SJohn Marino 
48695b7b453SJohn Marino             default:
48795b7b453SJohn Marino               break;
48895b7b453SJohn Marino             }
48995b7b453SJohn Marino           break;
49095b7b453SJohn Marino 
49195b7b453SJohn Marino         case '\a': esc = 'a'; goto c_escape;
49295b7b453SJohn Marino         case '\b': esc = 'b'; goto c_escape;
49395b7b453SJohn Marino         case '\f': esc = 'f'; goto c_escape;
49495b7b453SJohn Marino         case '\n': esc = 'n'; goto c_and_shell_escape;
49595b7b453SJohn Marino         case '\r': esc = 'r'; goto c_and_shell_escape;
49695b7b453SJohn Marino         case '\t': esc = 't'; goto c_and_shell_escape;
49795b7b453SJohn Marino         case '\v': esc = 'v'; goto c_escape;
49895b7b453SJohn Marino         case '\\': esc = c;
499*09d4459fSDaniel Fojt           /* Never need to escape '\' in shell case.  */
500*09d4459fSDaniel Fojt           if (quoting_style == shell_always_quoting_style)
501*09d4459fSDaniel Fojt             {
502*09d4459fSDaniel Fojt               if (elide_outer_quotes)
503*09d4459fSDaniel Fojt                 goto force_outer_quoting_style;
504*09d4459fSDaniel Fojt               goto store_c;
505*09d4459fSDaniel Fojt             }
506*09d4459fSDaniel Fojt 
50795b7b453SJohn Marino           /* No need to escape the escape if we are trying to elide
50895b7b453SJohn Marino              outer quotes and nothing else is problematic.  */
50995b7b453SJohn Marino           if (backslash_escapes && elide_outer_quotes && quote_string_len)
51095b7b453SJohn Marino             goto store_c;
51195b7b453SJohn Marino 
51295b7b453SJohn Marino         c_and_shell_escape:
51395b7b453SJohn Marino           if (quoting_style == shell_always_quoting_style
51495b7b453SJohn Marino               && elide_outer_quotes)
51595b7b453SJohn Marino             goto force_outer_quoting_style;
516*09d4459fSDaniel Fojt           /* fall through */
51795b7b453SJohn Marino         c_escape:
51895b7b453SJohn Marino           if (backslash_escapes)
51995b7b453SJohn Marino             {
52095b7b453SJohn Marino               c = esc;
52195b7b453SJohn Marino               goto store_escape;
52295b7b453SJohn Marino             }
52395b7b453SJohn Marino           break;
52495b7b453SJohn Marino 
52595b7b453SJohn Marino         case '{': case '}': /* sometimes special if isolated */
52695b7b453SJohn Marino           if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1))
52795b7b453SJohn Marino             break;
528*09d4459fSDaniel Fojt           FALLTHROUGH;
52995b7b453SJohn Marino         case '#': case '~':
53095b7b453SJohn Marino           if (i != 0)
53195b7b453SJohn Marino             break;
532*09d4459fSDaniel Fojt           FALLTHROUGH;
53395b7b453SJohn Marino         case ' ':
534*09d4459fSDaniel Fojt           c_and_shell_quote_compat = true;
535*09d4459fSDaniel Fojt           FALLTHROUGH;
53695b7b453SJohn Marino         case '!': /* special in bash */
53795b7b453SJohn Marino         case '"': case '$': case '&':
53895b7b453SJohn Marino         case '(': case ')': case '*': case ';':
53995b7b453SJohn Marino         case '<':
54095b7b453SJohn Marino         case '=': /* sometimes special in 0th or (with "set -k") later args */
54195b7b453SJohn Marino         case '>': case '[':
54295b7b453SJohn Marino         case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
54395b7b453SJohn Marino         case '`': case '|':
54495b7b453SJohn Marino           /* A shell special character.  In theory, '$' and '`' could
54595b7b453SJohn Marino              be the first bytes of multibyte characters, which means
54695b7b453SJohn Marino              we should check them with mbrtowc, but in practice this
54795b7b453SJohn Marino              doesn't happen so it's not worth worrying about.  */
54895b7b453SJohn Marino           if (quoting_style == shell_always_quoting_style
54995b7b453SJohn Marino               && elide_outer_quotes)
55095b7b453SJohn Marino             goto force_outer_quoting_style;
55195b7b453SJohn Marino           break;
55295b7b453SJohn Marino 
55395b7b453SJohn Marino         case '\'':
554*09d4459fSDaniel Fojt           encountered_single_quote = true;
555*09d4459fSDaniel Fojt           c_and_shell_quote_compat = true;
55695b7b453SJohn Marino           if (quoting_style == shell_always_quoting_style)
55795b7b453SJohn Marino             {
55895b7b453SJohn Marino               if (elide_outer_quotes)
55995b7b453SJohn Marino                 goto force_outer_quoting_style;
560*09d4459fSDaniel Fojt 
561*09d4459fSDaniel Fojt               if (buffersize && ! orig_buffersize)
562*09d4459fSDaniel Fojt                 {
563*09d4459fSDaniel Fojt                   /* Just scan string to see if supports a more concise
564*09d4459fSDaniel Fojt                      representation, rather than writing a longer string
565*09d4459fSDaniel Fojt                      but returning the length of the more concise form.  */
566*09d4459fSDaniel Fojt                   orig_buffersize = buffersize;
567*09d4459fSDaniel Fojt                   buffersize = 0;
568*09d4459fSDaniel Fojt                 }
569*09d4459fSDaniel Fojt 
57095b7b453SJohn Marino               STORE ('\'');
57195b7b453SJohn Marino               STORE ('\\');
57295b7b453SJohn Marino               STORE ('\'');
573*09d4459fSDaniel Fojt               pending_shell_escape_end = false;
57495b7b453SJohn Marino             }
57595b7b453SJohn Marino           break;
57695b7b453SJohn Marino 
57795b7b453SJohn Marino         case '%': case '+': case ',': case '-': case '.': case '/':
57895b7b453SJohn Marino         case '0': case '1': case '2': case '3': case '4': case '5':
57995b7b453SJohn Marino         case '6': case '7': case '8': case '9': case ':':
58095b7b453SJohn Marino         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
58195b7b453SJohn Marino         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
58295b7b453SJohn Marino         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
58395b7b453SJohn Marino         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
58495b7b453SJohn Marino         case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
58595b7b453SJohn Marino         case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
58695b7b453SJohn Marino         case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
58795b7b453SJohn Marino         case 'o': case 'p': case 'q': case 'r': case 's': case 't':
58895b7b453SJohn Marino         case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
58995b7b453SJohn Marino           /* These characters don't cause problems, no matter what the
59095b7b453SJohn Marino              quoting style is.  They cannot start multibyte sequences.
59195b7b453SJohn Marino              A digit or a special letter would cause trouble if it
59295b7b453SJohn Marino              appeared at the beginning of quote_string because we'd then
59395b7b453SJohn Marino              escape by prepending a backslash.  However, it's hard to
59495b7b453SJohn Marino              imagine any locale that would use digits or letters as
59595b7b453SJohn Marino              quotes, and set_custom_quoting is documented not to accept
59695b7b453SJohn Marino              them.  Also, a digit or a special letter would cause
59795b7b453SJohn Marino              trouble if it appeared in quote_these_too, but that's also
59895b7b453SJohn Marino              documented as not accepting them.  */
599*09d4459fSDaniel Fojt           c_and_shell_quote_compat = true;
60095b7b453SJohn Marino           break;
60195b7b453SJohn Marino 
60295b7b453SJohn Marino         default:
60395b7b453SJohn Marino           /* If we have a multibyte sequence, copy it until we reach
60495b7b453SJohn Marino              its end, find an error, or come back to the initial shift
60595b7b453SJohn Marino              state.  For C-like styles, if the sequence has
60695b7b453SJohn Marino              unprintable characters, escape the whole sequence, since
60795b7b453SJohn Marino              we can't easily escape single characters within it.  */
60895b7b453SJohn Marino           {
60995b7b453SJohn Marino             /* Length of multibyte sequence found so far.  */
61095b7b453SJohn Marino             size_t m;
61195b7b453SJohn Marino 
61295b7b453SJohn Marino             bool printable;
61395b7b453SJohn Marino 
61495b7b453SJohn Marino             if (unibyte_locale)
61595b7b453SJohn Marino               {
61695b7b453SJohn Marino                 m = 1;
61795b7b453SJohn Marino                 printable = isprint (c) != 0;
61895b7b453SJohn Marino               }
61995b7b453SJohn Marino             else
62095b7b453SJohn Marino               {
62195b7b453SJohn Marino                 mbstate_t mbstate;
62295b7b453SJohn Marino                 memset (&mbstate, 0, sizeof mbstate);
62395b7b453SJohn Marino 
62495b7b453SJohn Marino                 m = 0;
62595b7b453SJohn Marino                 printable = true;
62695b7b453SJohn Marino                 if (argsize == SIZE_MAX)
62795b7b453SJohn Marino                   argsize = strlen (arg);
62895b7b453SJohn Marino 
62995b7b453SJohn Marino                 do
63095b7b453SJohn Marino                   {
63195b7b453SJohn Marino                     wchar_t w;
63295b7b453SJohn Marino                     size_t bytes = mbrtowc (&w, &arg[i + m],
63395b7b453SJohn Marino                                             argsize - (i + m), &mbstate);
63495b7b453SJohn Marino                     if (bytes == 0)
63595b7b453SJohn Marino                       break;
63695b7b453SJohn Marino                     else if (bytes == (size_t) -1)
63795b7b453SJohn Marino                       {
63895b7b453SJohn Marino                         printable = false;
63995b7b453SJohn Marino                         break;
64095b7b453SJohn Marino                       }
64195b7b453SJohn Marino                     else if (bytes == (size_t) -2)
64295b7b453SJohn Marino                       {
64395b7b453SJohn Marino                         printable = false;
64495b7b453SJohn Marino                         while (i + m < argsize && arg[i + m])
64595b7b453SJohn Marino                           m++;
64695b7b453SJohn Marino                         break;
64795b7b453SJohn Marino                       }
64895b7b453SJohn Marino                     else
64995b7b453SJohn Marino                       {
65095b7b453SJohn Marino                         /* Work around a bug with older shells that "see" a '\'
65195b7b453SJohn Marino                            that is really the 2nd byte of a multibyte character.
65295b7b453SJohn Marino                            In practice the problem is limited to ASCII
65395b7b453SJohn Marino                            chars >= '@' that are shell special chars.  */
65495b7b453SJohn Marino                         if ('[' == 0x5b && elide_outer_quotes
65595b7b453SJohn Marino                             && quoting_style == shell_always_quoting_style)
65695b7b453SJohn Marino                           {
65795b7b453SJohn Marino                             size_t j;
65895b7b453SJohn Marino                             for (j = 1; j < bytes; j++)
65995b7b453SJohn Marino                               switch (arg[i + m + j])
66095b7b453SJohn Marino                                 {
66195b7b453SJohn Marino                                 case '[': case '\\': case '^':
66295b7b453SJohn Marino                                 case '`': case '|':
66395b7b453SJohn Marino                                   goto force_outer_quoting_style;
66495b7b453SJohn Marino 
66595b7b453SJohn Marino                                 default:
66695b7b453SJohn Marino                                   break;
66795b7b453SJohn Marino                                 }
66895b7b453SJohn Marino                           }
66995b7b453SJohn Marino 
67095b7b453SJohn Marino                         if (! iswprint (w))
67195b7b453SJohn Marino                           printable = false;
67295b7b453SJohn Marino                         m += bytes;
67395b7b453SJohn Marino                       }
67495b7b453SJohn Marino                   }
67595b7b453SJohn Marino                 while (! mbsinit (&mbstate));
67695b7b453SJohn Marino               }
67795b7b453SJohn Marino 
678*09d4459fSDaniel Fojt             c_and_shell_quote_compat = printable;
679*09d4459fSDaniel Fojt 
68095b7b453SJohn Marino             if (1 < m || (backslash_escapes && ! printable))
68195b7b453SJohn Marino               {
68295b7b453SJohn Marino                 /* Output a multibyte sequence, or an escaped
68395b7b453SJohn Marino                    unprintable unibyte character.  */
68495b7b453SJohn Marino                 size_t ilim = i + m;
68595b7b453SJohn Marino 
68695b7b453SJohn Marino                 for (;;)
68795b7b453SJohn Marino                   {
68895b7b453SJohn Marino                     if (backslash_escapes && ! printable)
68995b7b453SJohn Marino                       {
690*09d4459fSDaniel Fojt                         START_ESC ();
69195b7b453SJohn Marino                         STORE ('0' + (c >> 6));
69295b7b453SJohn Marino                         STORE ('0' + ((c >> 3) & 7));
69395b7b453SJohn Marino                         c = '0' + (c & 7);
69495b7b453SJohn Marino                       }
69595b7b453SJohn Marino                     else if (is_right_quote)
69695b7b453SJohn Marino                       {
69795b7b453SJohn Marino                         STORE ('\\');
69895b7b453SJohn Marino                         is_right_quote = false;
69995b7b453SJohn Marino                       }
70095b7b453SJohn Marino                     if (ilim <= i + 1)
70195b7b453SJohn Marino                       break;
702*09d4459fSDaniel Fojt                     END_ESC ();
70395b7b453SJohn Marino                     STORE (c);
70495b7b453SJohn Marino                     c = arg[++i];
70595b7b453SJohn Marino                   }
70695b7b453SJohn Marino 
70795b7b453SJohn Marino                 goto store_c;
70895b7b453SJohn Marino               }
70995b7b453SJohn Marino           }
71095b7b453SJohn Marino         }
71195b7b453SJohn Marino 
712*09d4459fSDaniel Fojt       if (! (((backslash_escapes && quoting_style != shell_always_quoting_style)
713*09d4459fSDaniel Fojt               || elide_outer_quotes)
71495b7b453SJohn Marino              && quote_these_too
715680a9cb8SJohn Marino              && quote_these_too[c / INT_BITS] >> (c % INT_BITS) & 1)
71695b7b453SJohn Marino           && !is_right_quote)
71795b7b453SJohn Marino         goto store_c;
71895b7b453SJohn Marino 
71995b7b453SJohn Marino     store_escape:
720*09d4459fSDaniel Fojt       START_ESC ();
72195b7b453SJohn Marino 
72295b7b453SJohn Marino     store_c:
723*09d4459fSDaniel Fojt       END_ESC ();
72495b7b453SJohn Marino       STORE (c);
725*09d4459fSDaniel Fojt 
726*09d4459fSDaniel Fojt       if (! c_and_shell_quote_compat)
727*09d4459fSDaniel Fojt         all_c_and_shell_quote_compat = false;
72895b7b453SJohn Marino     }
72995b7b453SJohn Marino 
73095b7b453SJohn Marino   if (len == 0 && quoting_style == shell_always_quoting_style
73195b7b453SJohn Marino       && elide_outer_quotes)
73295b7b453SJohn Marino     goto force_outer_quoting_style;
73395b7b453SJohn Marino 
734*09d4459fSDaniel Fojt   /* Single shell quotes (') are commonly enough used as an apostrophe,
735*09d4459fSDaniel Fojt      that we attempt to minimize the quoting in this case.  Note itʼs
736*09d4459fSDaniel Fojt      better to use the apostrophe modifier "\u02BC" if possible, as that
737*09d4459fSDaniel Fojt      renders better and works with the word match regex \W+ etc.  */
738*09d4459fSDaniel Fojt   if (quoting_style == shell_always_quoting_style && ! elide_outer_quotes
739*09d4459fSDaniel Fojt       && encountered_single_quote)
740*09d4459fSDaniel Fojt     {
741*09d4459fSDaniel Fojt       if (all_c_and_shell_quote_compat)
742*09d4459fSDaniel Fojt         return quotearg_buffer_restyled (buffer, orig_buffersize, arg, argsize,
743*09d4459fSDaniel Fojt                                          c_quoting_style,
744*09d4459fSDaniel Fojt                                          flags, quote_these_too,
745*09d4459fSDaniel Fojt                                          left_quote, right_quote);
746*09d4459fSDaniel Fojt       else if (! buffersize && orig_buffersize)
747*09d4459fSDaniel Fojt         {
748*09d4459fSDaniel Fojt           /* Disable read-only scan, and reprocess to write quoted string.  */
749*09d4459fSDaniel Fojt           buffersize = orig_buffersize;
750*09d4459fSDaniel Fojt           len = 0;
751*09d4459fSDaniel Fojt           goto process_input;
752*09d4459fSDaniel Fojt         }
753*09d4459fSDaniel Fojt     }
754*09d4459fSDaniel Fojt 
75595b7b453SJohn Marino   if (quote_string && !elide_outer_quotes)
75695b7b453SJohn Marino     for (; *quote_string; quote_string++)
75795b7b453SJohn Marino       STORE (*quote_string);
75895b7b453SJohn Marino 
75995b7b453SJohn Marino   if (len < buffersize)
76095b7b453SJohn Marino     buffer[len] = '\0';
76195b7b453SJohn Marino   return len;
76295b7b453SJohn Marino 
76395b7b453SJohn Marino  force_outer_quoting_style:
76495b7b453SJohn Marino   /* Don't reuse quote_these_too, since the addition of outer quotes
76595b7b453SJohn Marino      sufficiently quotes the specified characters.  */
766*09d4459fSDaniel Fojt   if (quoting_style == shell_always_quoting_style && backslash_escapes)
767*09d4459fSDaniel Fojt     quoting_style = shell_escape_always_quoting_style;
76895b7b453SJohn Marino   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
76995b7b453SJohn Marino                                    quoting_style,
77095b7b453SJohn Marino                                    flags & ~QA_ELIDE_OUTER_QUOTES, NULL,
77195b7b453SJohn Marino                                    left_quote, right_quote);
77295b7b453SJohn Marino }
77395b7b453SJohn Marino 
77495b7b453SJohn Marino /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
77595b7b453SJohn Marino    argument ARG (of size ARGSIZE), using O to control quoting.
77695b7b453SJohn Marino    If O is null, use the default.
77795b7b453SJohn Marino    Terminate the output with a null character, and return the written
77895b7b453SJohn Marino    size of the output, not counting the terminating null.
77995b7b453SJohn Marino    If BUFFERSIZE is too small to store the output string, return the
78095b7b453SJohn Marino    value that would have been returned had BUFFERSIZE been large enough.
78195b7b453SJohn Marino    If ARGSIZE is SIZE_MAX, use the string length of the argument for
78295b7b453SJohn Marino    ARGSIZE.  */
78395b7b453SJohn Marino size_t
quotearg_buffer(char * buffer,size_t buffersize,char const * arg,size_t argsize,struct quoting_options const * o)78495b7b453SJohn Marino quotearg_buffer (char *buffer, size_t buffersize,
78595b7b453SJohn Marino                  char const *arg, size_t argsize,
78695b7b453SJohn Marino                  struct quoting_options const *o)
78795b7b453SJohn Marino {
78895b7b453SJohn Marino   struct quoting_options const *p = o ? o : &default_quoting_options;
78995b7b453SJohn Marino   int e = errno;
79095b7b453SJohn Marino   size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
79195b7b453SJohn Marino                                        p->style, p->flags, p->quote_these_too,
79295b7b453SJohn Marino                                        p->left_quote, p->right_quote);
79395b7b453SJohn Marino   errno = e;
79495b7b453SJohn Marino   return r;
79595b7b453SJohn Marino }
79695b7b453SJohn Marino 
79795b7b453SJohn Marino /* Equivalent to quotearg_alloc (ARG, ARGSIZE, NULL, O).  */
79895b7b453SJohn Marino char *
quotearg_alloc(char const * arg,size_t argsize,struct quoting_options const * o)79995b7b453SJohn Marino quotearg_alloc (char const *arg, size_t argsize,
80095b7b453SJohn Marino                 struct quoting_options const *o)
80195b7b453SJohn Marino {
80295b7b453SJohn Marino   return quotearg_alloc_mem (arg, argsize, NULL, o);
80395b7b453SJohn Marino }
80495b7b453SJohn Marino 
80595b7b453SJohn Marino /* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
80695b7b453SJohn Marino    allocated storage containing the quoted string, and store the
80795b7b453SJohn Marino    resulting size into *SIZE, if non-NULL.  The result can contain
80895b7b453SJohn Marino    embedded null bytes only if ARGSIZE is not SIZE_MAX, SIZE is not
80995b7b453SJohn Marino    NULL, and set_quoting_flags has not set the null byte elision
81095b7b453SJohn Marino    flag.  */
81195b7b453SJohn Marino char *
quotearg_alloc_mem(char const * arg,size_t argsize,size_t * size,struct quoting_options const * o)81295b7b453SJohn Marino quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size,
81395b7b453SJohn Marino                     struct quoting_options const *o)
81495b7b453SJohn Marino {
81595b7b453SJohn Marino   struct quoting_options const *p = o ? o : &default_quoting_options;
81695b7b453SJohn Marino   int e = errno;
81795b7b453SJohn Marino   /* Elide embedded null bytes if we can't return a size.  */
81895b7b453SJohn Marino   int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES);
81995b7b453SJohn Marino   size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style,
82095b7b453SJohn Marino                                              flags, p->quote_these_too,
82195b7b453SJohn Marino                                              p->left_quote,
82295b7b453SJohn Marino                                              p->right_quote) + 1;
82395b7b453SJohn Marino   char *buf = xcharalloc (bufsize);
82495b7b453SJohn Marino   quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags,
82595b7b453SJohn Marino                             p->quote_these_too,
82695b7b453SJohn Marino                             p->left_quote, p->right_quote);
82795b7b453SJohn Marino   errno = e;
82895b7b453SJohn Marino   if (size)
82995b7b453SJohn Marino     *size = bufsize - 1;
83095b7b453SJohn Marino   return buf;
83195b7b453SJohn Marino }
83295b7b453SJohn Marino 
83395b7b453SJohn Marino /* A storage slot with size and pointer to a value.  */
83495b7b453SJohn Marino struct slotvec
83595b7b453SJohn Marino {
83695b7b453SJohn Marino   size_t size;
83795b7b453SJohn Marino   char *val;
83895b7b453SJohn Marino };
83995b7b453SJohn Marino 
84095b7b453SJohn Marino /* Preallocate a slot 0 buffer, so that the caller can always quote
84195b7b453SJohn Marino    one small component of a "memory exhausted" message in slot 0.  */
84295b7b453SJohn Marino static char slot0[256];
843*09d4459fSDaniel Fojt static int nslots = 1;
84495b7b453SJohn Marino static struct slotvec slotvec0 = {sizeof slot0, slot0};
84595b7b453SJohn Marino static struct slotvec *slotvec = &slotvec0;
84695b7b453SJohn Marino 
84795b7b453SJohn Marino void
quotearg_free(void)84895b7b453SJohn Marino quotearg_free (void)
84995b7b453SJohn Marino {
85095b7b453SJohn Marino   struct slotvec *sv = slotvec;
851*09d4459fSDaniel Fojt   int i;
85295b7b453SJohn Marino   for (i = 1; i < nslots; i++)
85395b7b453SJohn Marino     free (sv[i].val);
85495b7b453SJohn Marino   if (sv[0].val != slot0)
85595b7b453SJohn Marino     {
85695b7b453SJohn Marino       free (sv[0].val);
85795b7b453SJohn Marino       slotvec0.size = sizeof slot0;
85895b7b453SJohn Marino       slotvec0.val = slot0;
85995b7b453SJohn Marino     }
86095b7b453SJohn Marino   if (sv != &slotvec0)
86195b7b453SJohn Marino     {
86295b7b453SJohn Marino       free (sv);
86395b7b453SJohn Marino       slotvec = &slotvec0;
86495b7b453SJohn Marino     }
86595b7b453SJohn Marino   nslots = 1;
86695b7b453SJohn Marino }
86795b7b453SJohn Marino 
86895b7b453SJohn Marino /* Use storage slot N to return a quoted version of argument ARG.
86995b7b453SJohn Marino    ARG is of size ARGSIZE, but if that is SIZE_MAX, ARG is a
87095b7b453SJohn Marino    null-terminated string.
87195b7b453SJohn Marino    OPTIONS specifies the quoting options.
87295b7b453SJohn Marino    The returned value points to static storage that can be
87395b7b453SJohn Marino    reused by the next call to this function with the same value of N.
87495b7b453SJohn Marino    N must be nonnegative.  N is deliberately declared with type "int"
87595b7b453SJohn Marino    to allow for future extensions (using negative values).  */
87695b7b453SJohn Marino static char *
quotearg_n_options(int n,char const * arg,size_t argsize,struct quoting_options const * options)87795b7b453SJohn Marino quotearg_n_options (int n, char const *arg, size_t argsize,
87895b7b453SJohn Marino                     struct quoting_options const *options)
87995b7b453SJohn Marino {
88095b7b453SJohn Marino   int e = errno;
88195b7b453SJohn Marino 
88295b7b453SJohn Marino   struct slotvec *sv = slotvec;
88395b7b453SJohn Marino 
88495b7b453SJohn Marino   if (n < 0)
88595b7b453SJohn Marino     abort ();
88695b7b453SJohn Marino 
887*09d4459fSDaniel Fojt   if (nslots <= n)
88895b7b453SJohn Marino     {
88995b7b453SJohn Marino       bool preallocated = (sv == &slotvec0);
890*09d4459fSDaniel Fojt       int nmax = MIN (INT_MAX, MIN (PTRDIFF_MAX, SIZE_MAX) / sizeof *sv) - 1;
89195b7b453SJohn Marino 
892*09d4459fSDaniel Fojt       if (nmax < n)
89395b7b453SJohn Marino         xalloc_die ();
89495b7b453SJohn Marino 
895*09d4459fSDaniel Fojt       slotvec = sv = xrealloc (preallocated ? NULL : sv, (n + 1) * sizeof *sv);
89695b7b453SJohn Marino       if (preallocated)
89795b7b453SJohn Marino         *sv = slotvec0;
898*09d4459fSDaniel Fojt       memset (sv + nslots, 0, (n + 1 - nslots) * sizeof *sv);
899*09d4459fSDaniel Fojt       nslots = n + 1;
90095b7b453SJohn Marino     }
90195b7b453SJohn Marino 
90295b7b453SJohn Marino   {
90395b7b453SJohn Marino     size_t size = sv[n].size;
90495b7b453SJohn Marino     char *val = sv[n].val;
90595b7b453SJohn Marino     /* Elide embedded null bytes since we don't return a size.  */
90695b7b453SJohn Marino     int flags = options->flags | QA_ELIDE_NULL_BYTES;
90795b7b453SJohn Marino     size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize,
90895b7b453SJohn Marino                                              options->style, flags,
90995b7b453SJohn Marino                                              options->quote_these_too,
91095b7b453SJohn Marino                                              options->left_quote,
91195b7b453SJohn Marino                                              options->right_quote);
91295b7b453SJohn Marino 
91395b7b453SJohn Marino     if (size <= qsize)
91495b7b453SJohn Marino       {
91595b7b453SJohn Marino         sv[n].size = size = qsize + 1;
91695b7b453SJohn Marino         if (val != slot0)
91795b7b453SJohn Marino           free (val);
91895b7b453SJohn Marino         sv[n].val = val = xcharalloc (size);
91995b7b453SJohn Marino         quotearg_buffer_restyled (val, size, arg, argsize, options->style,
92095b7b453SJohn Marino                                   flags, options->quote_these_too,
92195b7b453SJohn Marino                                   options->left_quote,
92295b7b453SJohn Marino                                   options->right_quote);
92395b7b453SJohn Marino       }
92495b7b453SJohn Marino 
92595b7b453SJohn Marino     errno = e;
92695b7b453SJohn Marino     return val;
92795b7b453SJohn Marino   }
92895b7b453SJohn Marino }
92995b7b453SJohn Marino 
93095b7b453SJohn Marino char *
quotearg_n(int n,char const * arg)93195b7b453SJohn Marino quotearg_n (int n, char const *arg)
93295b7b453SJohn Marino {
93395b7b453SJohn Marino   return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options);
93495b7b453SJohn Marino }
93595b7b453SJohn Marino 
93695b7b453SJohn Marino char *
quotearg_n_mem(int n,char const * arg,size_t argsize)93795b7b453SJohn Marino quotearg_n_mem (int n, char const *arg, size_t argsize)
93895b7b453SJohn Marino {
93995b7b453SJohn Marino   return quotearg_n_options (n, arg, argsize, &default_quoting_options);
94095b7b453SJohn Marino }
94195b7b453SJohn Marino 
94295b7b453SJohn Marino char *
quotearg(char const * arg)94395b7b453SJohn Marino quotearg (char const *arg)
94495b7b453SJohn Marino {
94595b7b453SJohn Marino   return quotearg_n (0, arg);
94695b7b453SJohn Marino }
94795b7b453SJohn Marino 
94895b7b453SJohn Marino char *
quotearg_mem(char const * arg,size_t argsize)94995b7b453SJohn Marino quotearg_mem (char const *arg, size_t argsize)
95095b7b453SJohn Marino {
95195b7b453SJohn Marino   return quotearg_n_mem (0, arg, argsize);
95295b7b453SJohn Marino }
95395b7b453SJohn Marino 
95495b7b453SJohn Marino char *
quotearg_n_style(int n,enum quoting_style s,char const * arg)95595b7b453SJohn Marino quotearg_n_style (int n, enum quoting_style s, char const *arg)
95695b7b453SJohn Marino {
95795b7b453SJohn Marino   struct quoting_options const o = quoting_options_from_style (s);
95895b7b453SJohn Marino   return quotearg_n_options (n, arg, SIZE_MAX, &o);
95995b7b453SJohn Marino }
96095b7b453SJohn Marino 
96195b7b453SJohn Marino char *
quotearg_n_style_mem(int n,enum quoting_style s,char const * arg,size_t argsize)96295b7b453SJohn Marino quotearg_n_style_mem (int n, enum quoting_style s,
96395b7b453SJohn Marino                       char const *arg, size_t argsize)
96495b7b453SJohn Marino {
96595b7b453SJohn Marino   struct quoting_options const o = quoting_options_from_style (s);
96695b7b453SJohn Marino   return quotearg_n_options (n, arg, argsize, &o);
96795b7b453SJohn Marino }
96895b7b453SJohn Marino 
96995b7b453SJohn Marino char *
quotearg_style(enum quoting_style s,char const * arg)97095b7b453SJohn Marino quotearg_style (enum quoting_style s, char const *arg)
97195b7b453SJohn Marino {
97295b7b453SJohn Marino   return quotearg_n_style (0, s, arg);
97395b7b453SJohn Marino }
97495b7b453SJohn Marino 
97595b7b453SJohn Marino char *
quotearg_style_mem(enum quoting_style s,char const * arg,size_t argsize)97695b7b453SJohn Marino quotearg_style_mem (enum quoting_style s, char const *arg, size_t argsize)
97795b7b453SJohn Marino {
97895b7b453SJohn Marino   return quotearg_n_style_mem (0, s, arg, argsize);
97995b7b453SJohn Marino }
98095b7b453SJohn Marino 
98195b7b453SJohn Marino char *
quotearg_char_mem(char const * arg,size_t argsize,char ch)98295b7b453SJohn Marino quotearg_char_mem (char const *arg, size_t argsize, char ch)
98395b7b453SJohn Marino {
98495b7b453SJohn Marino   struct quoting_options options;
98595b7b453SJohn Marino   options = default_quoting_options;
98695b7b453SJohn Marino   set_char_quoting (&options, ch, 1);
98795b7b453SJohn Marino   return quotearg_n_options (0, arg, argsize, &options);
98895b7b453SJohn Marino }
98995b7b453SJohn Marino 
99095b7b453SJohn Marino char *
quotearg_char(char const * arg,char ch)99195b7b453SJohn Marino quotearg_char (char const *arg, char ch)
99295b7b453SJohn Marino {
99395b7b453SJohn Marino   return quotearg_char_mem (arg, SIZE_MAX, ch);
99495b7b453SJohn Marino }
99595b7b453SJohn Marino 
99695b7b453SJohn Marino char *
quotearg_colon(char const * arg)99795b7b453SJohn Marino quotearg_colon (char const *arg)
99895b7b453SJohn Marino {
99995b7b453SJohn Marino   return quotearg_char (arg, ':');
100095b7b453SJohn Marino }
100195b7b453SJohn Marino 
100295b7b453SJohn Marino char *
quotearg_colon_mem(char const * arg,size_t argsize)100395b7b453SJohn Marino quotearg_colon_mem (char const *arg, size_t argsize)
100495b7b453SJohn Marino {
100595b7b453SJohn Marino   return quotearg_char_mem (arg, argsize, ':');
100695b7b453SJohn Marino }
100795b7b453SJohn Marino 
100895b7b453SJohn Marino char *
quotearg_n_style_colon(int n,enum quoting_style s,char const * arg)1009*09d4459fSDaniel Fojt quotearg_n_style_colon (int n, enum quoting_style s, char const *arg)
1010*09d4459fSDaniel Fojt {
1011*09d4459fSDaniel Fojt   struct quoting_options options;
1012*09d4459fSDaniel Fojt   options = quoting_options_from_style (s);
1013*09d4459fSDaniel Fojt   set_char_quoting (&options, ':', 1);
1014*09d4459fSDaniel Fojt   return quotearg_n_options (n, arg, SIZE_MAX, &options);
1015*09d4459fSDaniel Fojt }
1016*09d4459fSDaniel Fojt 
1017*09d4459fSDaniel Fojt char *
quotearg_n_custom(int n,char const * left_quote,char const * right_quote,char const * arg)101895b7b453SJohn Marino quotearg_n_custom (int n, char const *left_quote,
101995b7b453SJohn Marino                    char const *right_quote, char const *arg)
102095b7b453SJohn Marino {
102195b7b453SJohn Marino   return quotearg_n_custom_mem (n, left_quote, right_quote, arg,
102295b7b453SJohn Marino                                 SIZE_MAX);
102395b7b453SJohn Marino }
102495b7b453SJohn Marino 
102595b7b453SJohn Marino char *
quotearg_n_custom_mem(int n,char const * left_quote,char const * right_quote,char const * arg,size_t argsize)102695b7b453SJohn Marino quotearg_n_custom_mem (int n, char const *left_quote,
102795b7b453SJohn Marino                        char const *right_quote,
102895b7b453SJohn Marino                        char const *arg, size_t argsize)
102995b7b453SJohn Marino {
103095b7b453SJohn Marino   struct quoting_options o = default_quoting_options;
103195b7b453SJohn Marino   set_custom_quoting (&o, left_quote, right_quote);
103295b7b453SJohn Marino   return quotearg_n_options (n, arg, argsize, &o);
103395b7b453SJohn Marino }
103495b7b453SJohn Marino 
103595b7b453SJohn Marino char *
quotearg_custom(char const * left_quote,char const * right_quote,char const * arg)103695b7b453SJohn Marino quotearg_custom (char const *left_quote, char const *right_quote,
103795b7b453SJohn Marino                  char const *arg)
103895b7b453SJohn Marino {
103995b7b453SJohn Marino   return quotearg_n_custom (0, left_quote, right_quote, arg);
104095b7b453SJohn Marino }
104195b7b453SJohn Marino 
104295b7b453SJohn Marino char *
quotearg_custom_mem(char const * left_quote,char const * right_quote,char const * arg,size_t argsize)104395b7b453SJohn Marino quotearg_custom_mem (char const *left_quote, char const *right_quote,
104495b7b453SJohn Marino                      char const *arg, size_t argsize)
104595b7b453SJohn Marino {
104695b7b453SJohn Marino   return quotearg_n_custom_mem (0, left_quote, right_quote, arg,
104795b7b453SJohn Marino                                 argsize);
104895b7b453SJohn Marino }
1049cf28ed85SJohn Marino 
1050cf28ed85SJohn Marino 
1051680a9cb8SJohn Marino /* The quoting option used by the functions of quote.h.  */
1052cf28ed85SJohn Marino struct quoting_options quote_quoting_options =
1053cf28ed85SJohn Marino   {
1054cf28ed85SJohn Marino     locale_quoting_style,
1055cf28ed85SJohn Marino     0,
1056cf28ed85SJohn Marino     { 0 },
1057cf28ed85SJohn Marino     NULL, NULL
1058cf28ed85SJohn Marino   };
1059cf28ed85SJohn Marino 
1060cf28ed85SJohn Marino char const *
quote_n_mem(int n,char const * arg,size_t argsize)1061680a9cb8SJohn Marino quote_n_mem (int n, char const *arg, size_t argsize)
1062cf28ed85SJohn Marino {
1063680a9cb8SJohn Marino   return quotearg_n_options (n, arg, argsize, &quote_quoting_options);
1064cf28ed85SJohn Marino }
1065cf28ed85SJohn Marino 
1066cf28ed85SJohn Marino char const *
quote_mem(char const * arg,size_t argsize)1067680a9cb8SJohn Marino quote_mem (char const *arg, size_t argsize)
1068cf28ed85SJohn Marino {
1069680a9cb8SJohn Marino   return quote_n_mem (0, arg, argsize);
1070680a9cb8SJohn Marino }
1071680a9cb8SJohn Marino 
1072680a9cb8SJohn Marino char const *
quote_n(int n,char const * arg)1073680a9cb8SJohn Marino quote_n (int n, char const *arg)
1074680a9cb8SJohn Marino {
1075680a9cb8SJohn Marino   return quote_n_mem (n, arg, SIZE_MAX);
1076680a9cb8SJohn Marino }
1077680a9cb8SJohn Marino 
1078680a9cb8SJohn Marino char const *
quote(char const * arg)1079680a9cb8SJohn Marino quote (char const *arg)
1080680a9cb8SJohn Marino {
1081680a9cb8SJohn Marino   return quote_n (0, arg);
1082cf28ed85SJohn Marino }
1083*09d4459fSDaniel Fojt 
1084*09d4459fSDaniel Fojt /*
1085*09d4459fSDaniel Fojt  * Hey Emacs!
1086*09d4459fSDaniel Fojt  * Local Variables:
1087*09d4459fSDaniel Fojt  * coding: utf-8
1088*09d4459fSDaniel Fojt  * End:
1089*09d4459fSDaniel Fojt  */
1090