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, "e_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