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