root/maint/gnulib/lib/quotearg.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clone_quoting_options
  2. get_quoting_style
  3. set_quoting_style
  4. set_char_quoting
  5. set_quoting_flags
  6. set_custom_quoting
  7. quoting_options_from_style
  8. gettext_quote
  9. quotearg_buffer_restyled
  10. quotearg_buffer
  11. quotearg_alloc
  12. quotearg_alloc_mem
  13. quotearg_free
  14. quotearg_n_options
  15. quotearg_n
  16. quotearg_n_mem
  17. quotearg
  18. quotearg_mem
  19. quotearg_n_style
  20. quotearg_n_style_mem
  21. quotearg_style
  22. quotearg_style_mem
  23. quotearg_char_mem
  24. quotearg_char
  25. quotearg_colon
  26. quotearg_colon_mem
  27. quotearg_n_style_colon
  28. quotearg_n_custom
  29. quotearg_n_custom_mem
  30. quotearg_custom
  31. quotearg_custom_mem
  32. quote_n_mem
  33. quote_mem
  34. quote_n
  35. quote

   1 /* quotearg.c - quote arguments for output
   2 
   3    Copyright (C) 1998-2002, 2004-2021 Free Software Foundation, Inc.
   4 
   5    This program is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU General Public License as published by
   7    the Free Software Foundation; either version 3 of the License, or
   8    (at your option) any later version.
   9 
  10    This program is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU General Public License for more details.
  14 
  15    You should have received a copy of the GNU General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 /* Written by Paul Eggert <eggert@twinsun.com> */
  19 
  20 /* Without this pragma, gcc 4.7.0 20111124 mistakenly suggests that
  21    the quoting_options_from_style function might be candidate for
  22    attribute 'pure'  */
  23 #if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
  24 # pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
  25 #endif
  26 
  27 #include <config.h>
  28 
  29 #include "quotearg.h"
  30 #include "quote.h"
  31 
  32 #include "attribute.h"
  33 #include "minmax.h"
  34 #include "xalloc.h"
  35 #include "c-strcaseeq.h"
  36 #include "localcharset.h"
  37 
  38 #include <ctype.h>
  39 #include <errno.h>
  40 #include <limits.h>
  41 #include <stdbool.h>
  42 #include <stdint.h>
  43 #include <stdlib.h>
  44 #include <string.h>
  45 #include <wchar.h>
  46 #include <wctype.h>
  47 
  48 #include "gettext.h"
  49 #define _(msgid) gettext (msgid)
  50 #define N_(msgid) msgid
  51 
  52 #ifndef SIZE_MAX
  53 # define SIZE_MAX ((size_t) -1)
  54 #endif
  55 
  56 #define INT_BITS (sizeof (int) * CHAR_BIT)
  57 
  58 struct quoting_options
  59 {
  60   /* Basic quoting style.  */
  61   enum quoting_style style;
  62 
  63   /* Additional flags.  Bitwise combination of enum quoting_flags.  */
  64   int flags;
  65 
  66   /* Quote the characters indicated by this bit vector even if the
  67      quoting style would not normally require them to be quoted.  */
  68   unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
  69 
  70   /* The left quote for custom_quoting_style.  */
  71   char const *left_quote;
  72 
  73   /* The right quote for custom_quoting_style.  */
  74   char const *right_quote;
  75 };
  76 
  77 /* Names of quoting styles.  */
  78 char const *const quoting_style_args[] =
  79 {
  80   "literal",
  81   "shell",
  82   "shell-always",
  83   "shell-escape",
  84   "shell-escape-always",
  85   "c",
  86   "c-maybe",
  87   "escape",
  88   "locale",
  89   "clocale",
  90   0
  91 };
  92 
  93 /* Correspondences to quoting style names.  */
  94 enum quoting_style const quoting_style_vals[] =
  95 {
  96   literal_quoting_style,
  97   shell_quoting_style,
  98   shell_always_quoting_style,
  99   shell_escape_quoting_style,
 100   shell_escape_always_quoting_style,
 101   c_quoting_style,
 102   c_maybe_quoting_style,
 103   escape_quoting_style,
 104   locale_quoting_style,
 105   clocale_quoting_style
 106 };
 107 
 108 /* The default quoting options.  */
 109 static struct quoting_options default_quoting_options;
 110 
 111 /* Allocate a new set of quoting options, with contents initially identical
 112    to O if O is not null, or to the default if O is null.
 113    It is the caller's responsibility to free the result.  */
 114 struct quoting_options *
 115 clone_quoting_options (struct quoting_options *o)
     /* [previous][next][first][last][top][bottom][index][help] */
 116 {
 117   int e = errno;
 118   struct quoting_options *p = xmemdup (o ? o : &default_quoting_options,
 119                                        sizeof *o);
 120   errno = e;
 121   return p;
 122 }
 123 
 124 /* Get the value of O's quoting style.  If O is null, use the default.  */
 125 enum quoting_style
 126 get_quoting_style (struct quoting_options const *o)
     /* [previous][next][first][last][top][bottom][index][help] */
 127 {
 128   return (o ? o : &default_quoting_options)->style;
 129 }
 130 
 131 /* In O (or in the default if O is null),
 132    set the value of the quoting style to S.  */
 133 void
 134 set_quoting_style (struct quoting_options *o, enum quoting_style s)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136   (o ? o : &default_quoting_options)->style = s;
 137 }
 138 
 139 /* In O (or in the default if O is null),
 140    set the value of the quoting options for character C to I.
 141    Return the old value.  Currently, the only values defined for I are
 142    0 (the default) and 1 (which means to quote the character even if
 143    it would not otherwise be quoted).  */
 144 int
 145 set_char_quoting (struct quoting_options *o, char c, int i)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147   unsigned char uc = c;
 148   unsigned int *p =
 149     (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
 150   int shift = uc % INT_BITS;
 151   int r = (*p >> shift) & 1;
 152   *p ^= ((i & 1) ^ r) << shift;
 153   return r;
 154 }
 155 
 156 /* In O (or in the default if O is null),
 157    set the value of the quoting options flag to I, which can be a
 158    bitwise combination of enum quoting_flags, or 0 for default
 159    behavior.  Return the old value.  */
 160 int
 161 set_quoting_flags (struct quoting_options *o, int i)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163   int r;
 164   if (!o)
 165     o = &default_quoting_options;
 166   r = o->flags;
 167   o->flags = i;
 168   return r;
 169 }
 170 
 171 void
 172 set_custom_quoting (struct quoting_options *o,
     /* [previous][next][first][last][top][bottom][index][help] */
 173                     char const *left_quote, char const *right_quote)
 174 {
 175   if (!o)
 176     o = &default_quoting_options;
 177   o->style = custom_quoting_style;
 178   if (!left_quote || !right_quote)
 179     abort ();
 180   o->left_quote = left_quote;
 181   o->right_quote = right_quote;
 182 }
 183 
 184 /* Return quoting options for STYLE, with no extra quoting.  */
 185 static struct quoting_options /* NOT PURE!! */
 186 quoting_options_from_style (enum quoting_style style)
     /* [previous][next][first][last][top][bottom][index][help] */
 187 {
 188   struct quoting_options o = { literal_quoting_style, 0, { 0 }, NULL, NULL };
 189   if (style == custom_quoting_style)
 190     abort ();
 191   o.style = style;
 192   return o;
 193 }
 194 
 195 /* MSGID approximates a quotation mark.  Return its translation if it
 196    has one; otherwise, return either it or "\"", depending on S.
 197 
 198    S is either clocale_quoting_style or locale_quoting_style.  */
 199 static char const *
 200 gettext_quote (char const *msgid, enum quoting_style s)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202   char const *translation = _(msgid);
 203   char const *locale_code;
 204 
 205   if (translation != msgid)
 206     return translation;
 207 
 208   /* For UTF-8 and GB-18030, use single quotes U+2018 and U+2019.
 209      Here is a list of other locales that include U+2018 and U+2019:
 210 
 211         ISO-8859-7   0xA1                 KOI8-T       0x91
 212         CP869        0x8B                 CP874        0x91
 213         CP932        0x81 0x65            CP936        0xA1 0xAE
 214         CP949        0xA1 0xAE            CP950        0xA1 0xA5
 215         CP1250       0x91                 CP1251       0x91
 216         CP1252       0x91                 CP1253       0x91
 217         CP1254       0x91                 CP1255       0x91
 218         CP1256       0x91                 CP1257       0x91
 219         EUC-JP       0xA1 0xC6            EUC-KR       0xA1 0xAE
 220         EUC-TW       0xA1 0xE4            BIG5         0xA1 0xA5
 221         BIG5-HKSCS   0xA1 0xA5            EUC-CN       0xA1 0xAE
 222         GBK          0xA1 0xAE            Georgian-PS  0x91
 223         PT154        0x91
 224 
 225      None of these is still in wide use; using iconv is overkill.  */
 226   locale_code = locale_charset ();
 227   if (STRCASEEQ (locale_code, "UTF-8", 'U','T','F','-','8',0,0,0,0))
 228     return msgid[0] == '`' ? "\xe2\x80\x98": "\xe2\x80\x99";
 229   if (STRCASEEQ (locale_code, "GB18030", 'G','B','1','8','0','3','0',0,0))
 230     return msgid[0] == '`' ? "\xa1\ae": "\xa1\xaf";
 231 
 232   return (s == clocale_quoting_style ? "\"" : "'");
 233 }
 234 
 235 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
 236    argument ARG (of size ARGSIZE), using QUOTING_STYLE, FLAGS, and
 237    QUOTE_THESE_TOO to control quoting.
 238    Terminate the output with a null character, and return the written
 239    size of the output, not counting the terminating null.
 240    If BUFFERSIZE is too small to store the output string, return the
 241    value that would have been returned had BUFFERSIZE been large enough.
 242    If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE.
 243 
 244    This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
 245    ARGSIZE, O), except it breaks O into its component pieces and is
 246    not careful about errno.  */
 247 
 248 static size_t
 249 quotearg_buffer_restyled (char *buffer, size_t buffersize,
     /* [previous][next][first][last][top][bottom][index][help] */
 250                           char const *arg, size_t argsize,
 251                           enum quoting_style quoting_style, int flags,
 252                           unsigned int const *quote_these_too,
 253                           char const *left_quote,
 254                           char const *right_quote)
 255 {
 256   size_t i;
 257   size_t len = 0;
 258   size_t orig_buffersize = 0;
 259   char const *quote_string = 0;
 260   size_t quote_string_len = 0;
 261   bool backslash_escapes = false;
 262   bool unibyte_locale = MB_CUR_MAX == 1;
 263   bool elide_outer_quotes = (flags & QA_ELIDE_OUTER_QUOTES) != 0;
 264   bool pending_shell_escape_end = false;
 265   bool encountered_single_quote = false;
 266   bool all_c_and_shell_quote_compat = true;
 267 
 268 #define STORE(c) \
 269     do \
 270       { \
 271         if (len < buffersize) \
 272           buffer[len] = (c); \
 273         len++; \
 274       } \
 275     while (0)
 276 
 277 #define START_ESC() \
 278     do \
 279       { \
 280         if (elide_outer_quotes) \
 281           goto force_outer_quoting_style; \
 282         escaping = true; \
 283         if (quoting_style == shell_always_quoting_style \
 284             && ! pending_shell_escape_end) \
 285           { \
 286             STORE ('\''); \
 287             STORE ('$'); \
 288             STORE ('\''); \
 289             pending_shell_escape_end = true; \
 290           } \
 291         STORE ('\\'); \
 292       } \
 293     while (0)
 294 
 295 #define END_ESC() \
 296     do \
 297       { \
 298         if (pending_shell_escape_end && ! escaping) \
 299           { \
 300             STORE ('\''); \
 301             STORE ('\''); \
 302             pending_shell_escape_end = false; \
 303           } \
 304       } \
 305     while (0)
 306 
 307  process_input:
 308 
 309   switch (quoting_style)
 310     {
 311     case c_maybe_quoting_style:
 312       quoting_style = c_quoting_style;
 313       elide_outer_quotes = true;
 314       FALLTHROUGH;
 315     case c_quoting_style:
 316       if (!elide_outer_quotes)
 317         STORE ('"');
 318       backslash_escapes = true;
 319       quote_string = "\"";
 320       quote_string_len = 1;
 321       break;
 322 
 323     case escape_quoting_style:
 324       backslash_escapes = true;
 325       elide_outer_quotes = false;
 326       break;
 327 
 328     case locale_quoting_style:
 329     case clocale_quoting_style:
 330     case custom_quoting_style:
 331       {
 332         if (quoting_style != custom_quoting_style)
 333           {
 334             /* TRANSLATORS:
 335                Get translations for open and closing quotation marks.
 336                The message catalog should translate "`" to a left
 337                quotation mark suitable for the locale, and similarly for
 338                "'".  For example, a French Unicode local should translate
 339                these to U+00AB (LEFT-POINTING DOUBLE ANGLE
 340                QUOTATION MARK), and U+00BB (RIGHT-POINTING DOUBLE ANGLE
 341                QUOTATION MARK), respectively.
 342 
 343                If the catalog has no translation, we will try to
 344                use Unicode U+2018 (LEFT SINGLE QUOTATION MARK) and
 345                Unicode U+2019 (RIGHT SINGLE QUOTATION MARK).  If the
 346                current locale is not Unicode, locale_quoting_style
 347                will quote 'like this', and clocale_quoting_style will
 348                quote "like this".  You should always include translations
 349                for "`" and "'" even if U+2018 and U+2019 are appropriate
 350                for your locale.
 351 
 352                If you don't know what to put here, please see
 353                <https://en.wikipedia.org/wiki/Quotation_marks_in_other_languages>
 354                and use glyphs suitable for your language.  */
 355             left_quote = gettext_quote (N_("`"), quoting_style);
 356             right_quote = gettext_quote (N_("'"), quoting_style);
 357           }
 358         if (!elide_outer_quotes)
 359           for (quote_string = left_quote; *quote_string; quote_string++)
 360             STORE (*quote_string);
 361         backslash_escapes = true;
 362         quote_string = right_quote;
 363         quote_string_len = strlen (quote_string);
 364       }
 365       break;
 366 
 367     case shell_escape_quoting_style:
 368       backslash_escapes = true;
 369       FALLTHROUGH;
 370     case shell_quoting_style:
 371       elide_outer_quotes = true;
 372       FALLTHROUGH;
 373     case shell_escape_always_quoting_style:
 374       if (!elide_outer_quotes)
 375         backslash_escapes = true;
 376       FALLTHROUGH;
 377     case shell_always_quoting_style:
 378       quoting_style = shell_always_quoting_style;
 379       if (!elide_outer_quotes)
 380         STORE ('\'');
 381       quote_string = "'";
 382       quote_string_len = 1;
 383       break;
 384 
 385     case literal_quoting_style:
 386       elide_outer_quotes = false;
 387       break;
 388 
 389     default:
 390       abort ();
 391     }
 392 
 393   for (i = 0;  ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize);  i++)
 394     {
 395       unsigned char c;
 396       unsigned char esc;
 397       bool is_right_quote = false;
 398       bool escaping = false;
 399       bool c_and_shell_quote_compat = false;
 400 
 401       if (backslash_escapes
 402           && quoting_style != shell_always_quoting_style
 403           && quote_string_len
 404           && (i + quote_string_len
 405               <= (argsize == SIZE_MAX && 1 < quote_string_len
 406                   /* Use strlen only if we must: when argsize is SIZE_MAX,
 407                      and when the quote string is more than 1 byte long.
 408                      If we do call strlen, save the result.  */
 409                   ? (argsize = strlen (arg)) : argsize))
 410           && memcmp (arg + i, quote_string, quote_string_len) == 0)
 411         {
 412           if (elide_outer_quotes)
 413             goto force_outer_quoting_style;
 414           is_right_quote = true;
 415         }
 416 
 417       c = arg[i];
 418       switch (c)
 419         {
 420         case '\0':
 421           if (backslash_escapes)
 422             {
 423               START_ESC ();
 424               /* If quote_string were to begin with digits, we'd need to
 425                  test for the end of the arg as well.  However, it's
 426                  hard to imagine any locale that would use digits in
 427                  quotes, and set_custom_quoting is documented not to
 428                  accept them.  Use only a single \0 with shell-escape
 429                  as currently digits are not printed within $'...'  */
 430               if (quoting_style != shell_always_quoting_style
 431                   && i + 1 < argsize && '0' <= arg[i + 1] && arg[i + 1] <= '9')
 432                 {
 433                   STORE ('0');
 434                   STORE ('0');
 435                 }
 436               c = '0';
 437               /* We don't have to worry that this last '0' will be
 438                  backslash-escaped because, again, quote_string should
 439                  not start with it and because quote_these_too is
 440                  documented as not accepting it.  */
 441             }
 442           else if (flags & QA_ELIDE_NULL_BYTES)
 443             continue;
 444           break;
 445 
 446         case '?':
 447           switch (quoting_style)
 448             {
 449             case shell_always_quoting_style:
 450               if (elide_outer_quotes)
 451                 goto force_outer_quoting_style;
 452               break;
 453 
 454             case c_quoting_style:
 455               if ((flags & QA_SPLIT_TRIGRAPHS)
 456                   && i + 2 < argsize && arg[i + 1] == '?')
 457                 switch (arg[i + 2])
 458                   {
 459                   case '!': case '\'':
 460                   case '(': case ')': case '-': case '/':
 461                   case '<': case '=': case '>':
 462                     /* Escape the second '?' in what would otherwise be
 463                        a trigraph.  */
 464                     if (elide_outer_quotes)
 465                       goto force_outer_quoting_style;
 466                     c = arg[i + 2];
 467                     i += 2;
 468                     STORE ('?');
 469                     STORE ('"');
 470                     STORE ('"');
 471                     STORE ('?');
 472                     break;
 473 
 474                   default:
 475                     break;
 476                   }
 477               break;
 478 
 479             default:
 480               break;
 481             }
 482           break;
 483 
 484         case '\a': esc = 'a'; goto c_escape;
 485         case '\b': esc = 'b'; goto c_escape;
 486         case '\f': esc = 'f'; goto c_escape;
 487         case '\n': esc = 'n'; goto c_and_shell_escape;
 488         case '\r': esc = 'r'; goto c_and_shell_escape;
 489         case '\t': esc = 't'; goto c_and_shell_escape;
 490         case '\v': esc = 'v'; goto c_escape;
 491         case '\\': esc = c;
 492           /* Never need to escape '\' in shell case.  */
 493           if (quoting_style == shell_always_quoting_style)
 494             {
 495               if (elide_outer_quotes)
 496                 goto force_outer_quoting_style;
 497               goto store_c;
 498             }
 499 
 500           /* No need to escape the escape if we are trying to elide
 501              outer quotes and nothing else is problematic.  */
 502           if (backslash_escapes && elide_outer_quotes && quote_string_len)
 503             goto store_c;
 504 
 505         c_and_shell_escape:
 506           if (quoting_style == shell_always_quoting_style
 507               && elide_outer_quotes)
 508             goto force_outer_quoting_style;
 509           /* fall through */
 510         c_escape:
 511           if (backslash_escapes)
 512             {
 513               c = esc;
 514               goto store_escape;
 515             }
 516           break;
 517 
 518         case '{': case '}': /* sometimes special if isolated */
 519           if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1))
 520             break;
 521           FALLTHROUGH;
 522         case '#': case '~':
 523           if (i != 0)
 524             break;
 525           FALLTHROUGH;
 526         case ' ':
 527           c_and_shell_quote_compat = true;
 528           FALLTHROUGH;
 529         case '!': /* special in bash */
 530         case '"': case '$': case '&':
 531         case '(': case ')': case '*': case ';':
 532         case '<':
 533         case '=': /* sometimes special in 0th or (with "set -k") later args */
 534         case '>': case '[':
 535         case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
 536         case '`': case '|':
 537           /* A shell special character.  In theory, '$' and '`' could
 538              be the first bytes of multibyte characters, which means
 539              we should check them with mbrtowc, but in practice this
 540              doesn't happen so it's not worth worrying about.  */
 541           if (quoting_style == shell_always_quoting_style
 542               && elide_outer_quotes)
 543             goto force_outer_quoting_style;
 544           break;
 545 
 546         case '\'':
 547           encountered_single_quote = true;
 548           c_and_shell_quote_compat = true;
 549           if (quoting_style == shell_always_quoting_style)
 550             {
 551               if (elide_outer_quotes)
 552                 goto force_outer_quoting_style;
 553 
 554               if (buffersize && ! orig_buffersize)
 555                 {
 556                   /* Just scan string to see if supports a more concise
 557                      representation, rather than writing a longer string
 558                      but returning the length of the more concise form.  */
 559                   orig_buffersize = buffersize;
 560                   buffersize = 0;
 561                 }
 562 
 563               STORE ('\'');
 564               STORE ('\\');
 565               STORE ('\'');
 566               pending_shell_escape_end = false;
 567             }
 568           break;
 569 
 570         case '%': case '+': case ',': case '-': case '.': case '/':
 571         case '0': case '1': case '2': case '3': case '4': case '5':
 572         case '6': case '7': case '8': case '9': case ':':
 573         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
 574         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
 575         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
 576         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
 577         case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
 578         case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
 579         case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
 580         case 'o': case 'p': case 'q': case 'r': case 's': case 't':
 581         case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
 582           /* These characters don't cause problems, no matter what the
 583              quoting style is.  They cannot start multibyte sequences.
 584              A digit or a special letter would cause trouble if it
 585              appeared at the beginning of quote_string because we'd then
 586              escape by prepending a backslash.  However, it's hard to
 587              imagine any locale that would use digits or letters as
 588              quotes, and set_custom_quoting is documented not to accept
 589              them.  Also, a digit or a special letter would cause
 590              trouble if it appeared in quote_these_too, but that's also
 591              documented as not accepting them.  */
 592           c_and_shell_quote_compat = true;
 593           break;
 594 
 595         default:
 596           /* If we have a multibyte sequence, copy it until we reach
 597              its end, find an error, or come back to the initial shift
 598              state.  For C-like styles, if the sequence has
 599              unprintable characters, escape the whole sequence, since
 600              we can't easily escape single characters within it.  */
 601           {
 602             /* Length of multibyte sequence found so far.  */
 603             size_t m;
 604 
 605             bool printable;
 606 
 607             if (unibyte_locale)
 608               {
 609                 m = 1;
 610                 printable = isprint (c) != 0;
 611               }
 612             else
 613               {
 614                 mbstate_t mbstate;
 615                 memset (&mbstate, 0, sizeof mbstate);
 616 
 617                 m = 0;
 618                 printable = true;
 619                 if (argsize == SIZE_MAX)
 620                   argsize = strlen (arg);
 621 
 622                 do
 623                   {
 624                     wchar_t w;
 625                     size_t bytes = mbrtowc (&w, &arg[i + m],
 626                                             argsize - (i + m), &mbstate);
 627                     if (bytes == 0)
 628                       break;
 629                     else if (bytes == (size_t) -1)
 630                       {
 631                         printable = false;
 632                         break;
 633                       }
 634                     else if (bytes == (size_t) -2)
 635                       {
 636                         printable = false;
 637                         while (i + m < argsize && arg[i + m])
 638                           m++;
 639                         break;
 640                       }
 641                     else
 642                       {
 643                         /* Work around a bug with older shells that "see" a '\'
 644                            that is really the 2nd byte of a multibyte character.
 645                            In practice the problem is limited to ASCII
 646                            chars >= '@' that are shell special chars.  */
 647                         if ('[' == 0x5b && elide_outer_quotes
 648                             && quoting_style == shell_always_quoting_style)
 649                           {
 650                             size_t j;
 651                             for (j = 1; j < bytes; j++)
 652                               switch (arg[i + m + j])
 653                                 {
 654                                 case '[': case '\\': case '^':
 655                                 case '`': case '|':
 656                                   goto force_outer_quoting_style;
 657 
 658                                 default:
 659                                   break;
 660                                 }
 661                           }
 662 
 663                         if (! iswprint (w))
 664                           printable = false;
 665                         m += bytes;
 666                       }
 667                   }
 668                 while (! mbsinit (&mbstate));
 669               }
 670 
 671             c_and_shell_quote_compat = printable;
 672 
 673             if (1 < m || (backslash_escapes && ! printable))
 674               {
 675                 /* Output a multibyte sequence, or an escaped
 676                    unprintable unibyte character.  */
 677                 size_t ilim = i + m;
 678 
 679                 for (;;)
 680                   {
 681                     if (backslash_escapes && ! printable)
 682                       {
 683                         START_ESC ();
 684                         STORE ('0' + (c >> 6));
 685                         STORE ('0' + ((c >> 3) & 7));
 686                         c = '0' + (c & 7);
 687                       }
 688                     else if (is_right_quote)
 689                       {
 690                         STORE ('\\');
 691                         is_right_quote = false;
 692                       }
 693                     if (ilim <= i + 1)
 694                       break;
 695                     END_ESC ();
 696                     STORE (c);
 697                     c = arg[++i];
 698                   }
 699 
 700                 goto store_c;
 701               }
 702           }
 703         }
 704 
 705       if (! (((backslash_escapes && quoting_style != shell_always_quoting_style)
 706               || elide_outer_quotes)
 707              && quote_these_too
 708              && quote_these_too[c / INT_BITS] >> (c % INT_BITS) & 1)
 709           && !is_right_quote)
 710         goto store_c;
 711 
 712     store_escape:
 713       START_ESC ();
 714 
 715     store_c:
 716       END_ESC ();
 717       STORE (c);
 718 
 719       if (! c_and_shell_quote_compat)
 720         all_c_and_shell_quote_compat = false;
 721     }
 722 
 723   if (len == 0 && quoting_style == shell_always_quoting_style
 724       && elide_outer_quotes)
 725     goto force_outer_quoting_style;
 726 
 727   /* Single shell quotes (') are commonly enough used as an apostrophe,
 728      that we attempt to minimize the quoting in this case.  Note itʼs
 729      better to use the apostrophe modifier "\u02BC" if possible, as that
 730      renders better and works with the word match regex \W+ etc.  */
 731   if (quoting_style == shell_always_quoting_style && ! elide_outer_quotes
 732       && encountered_single_quote)
 733     {
 734       if (all_c_and_shell_quote_compat)
 735         return quotearg_buffer_restyled (buffer, orig_buffersize, arg, argsize,
 736                                          c_quoting_style,
 737                                          flags, quote_these_too,
 738                                          left_quote, right_quote);
 739       else if (! buffersize && orig_buffersize)
 740         {
 741           /* Disable read-only scan, and reprocess to write quoted string.  */
 742           buffersize = orig_buffersize;
 743           len = 0;
 744           goto process_input;
 745         }
 746     }
 747 
 748   if (quote_string && !elide_outer_quotes)
 749     for (; *quote_string; quote_string++)
 750       STORE (*quote_string);
 751 
 752   if (len < buffersize)
 753     buffer[len] = '\0';
 754   return len;
 755 
 756  force_outer_quoting_style:
 757   /* Don't reuse quote_these_too, since the addition of outer quotes
 758      sufficiently quotes the specified characters.  */
 759   if (quoting_style == shell_always_quoting_style && backslash_escapes)
 760     quoting_style = shell_escape_always_quoting_style;
 761   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
 762                                    quoting_style,
 763                                    flags & ~QA_ELIDE_OUTER_QUOTES, NULL,
 764                                    left_quote, right_quote);
 765 }
 766 
 767 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
 768    argument ARG (of size ARGSIZE), using O to control quoting.
 769    If O is null, use the default.
 770    Terminate the output with a null character, and return the written
 771    size of the output, not counting the terminating null.
 772    If BUFFERSIZE is too small to store the output string, return the
 773    value that would have been returned had BUFFERSIZE been large enough.
 774    If ARGSIZE is SIZE_MAX, use the string length of the argument for
 775    ARGSIZE.  */
 776 size_t
 777 quotearg_buffer (char *buffer, size_t buffersize,
     /* [previous][next][first][last][top][bottom][index][help] */
 778                  char const *arg, size_t argsize,
 779                  struct quoting_options const *o)
 780 {
 781   struct quoting_options const *p = o ? o : &default_quoting_options;
 782   int e = errno;
 783   size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
 784                                        p->style, p->flags, p->quote_these_too,
 785                                        p->left_quote, p->right_quote);
 786   errno = e;
 787   return r;
 788 }
 789 
 790 char *
 791 quotearg_alloc (char const *arg, size_t argsize,
     /* [previous][next][first][last][top][bottom][index][help] */
 792                 struct quoting_options const *o)
 793 {
 794   return quotearg_alloc_mem (arg, argsize, NULL, o);
 795 }
 796 
 797 /* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
 798    allocated storage containing the quoted string, and store the
 799    resulting size into *SIZE, if non-NULL.  The result can contain
 800    embedded null bytes only if ARGSIZE is not SIZE_MAX, SIZE is not
 801    NULL, and set_quoting_flags has not set the null byte elision
 802    flag.  */
 803 char *
 804 quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size,
     /* [previous][next][first][last][top][bottom][index][help] */
 805                     struct quoting_options const *o)
 806 {
 807   struct quoting_options const *p = o ? o : &default_quoting_options;
 808   int e = errno;
 809   /* Elide embedded null bytes if we can't return a size.  */
 810   int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES);
 811   size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style,
 812                                              flags, p->quote_these_too,
 813                                              p->left_quote,
 814                                              p->right_quote) + 1;
 815   char *buf = xcharalloc (bufsize);
 816   quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags,
 817                             p->quote_these_too,
 818                             p->left_quote, p->right_quote);
 819   errno = e;
 820   if (size)
 821     *size = bufsize - 1;
 822   return buf;
 823 }
 824 
 825 /* A storage slot with size and pointer to a value.  */
 826 struct slotvec
 827 {
 828   size_t size;
 829   char *val;
 830 };
 831 
 832 /* Preallocate a slot 0 buffer, so that the caller can always quote
 833    one small component of a "memory exhausted" message in slot 0.  */
 834 static char slot0[256];
 835 static int nslots = 1;
 836 static struct slotvec slotvec0 = {sizeof slot0, slot0};
 837 static struct slotvec *slotvec = &slotvec0;
 838 
 839 void
 840 quotearg_free (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 841 {
 842   struct slotvec *sv = slotvec;
 843   int i;
 844   for (i = 1; i < nslots; i++)
 845     free (sv[i].val);
 846   if (sv[0].val != slot0)
 847     {
 848       free (sv[0].val);
 849       slotvec0.size = sizeof slot0;
 850       slotvec0.val = slot0;
 851     }
 852   if (sv != &slotvec0)
 853     {
 854       free (sv);
 855       slotvec = &slotvec0;
 856     }
 857   nslots = 1;
 858 }
 859 
 860 /* Use storage slot N to return a quoted version of argument ARG.
 861    ARG is of size ARGSIZE, but if that is SIZE_MAX, ARG is a
 862    null-terminated string.
 863    OPTIONS specifies the quoting options.
 864    The returned value points to static storage that can be
 865    reused by the next call to this function with the same value of N.
 866    N must be nonnegative; it is typically small, and must be
 867    less than MIN (INT_MAX, IDX_MAX).  The type of N is signed
 868    to allow for future extensions (using negative values).  */
 869 static char *
 870 quotearg_n_options (int n, char const *arg, size_t argsize,
     /* [previous][next][first][last][top][bottom][index][help] */
 871                     struct quoting_options const *options)
 872 {
 873   int e = errno;
 874 
 875   struct slotvec *sv = slotvec;
 876 
 877   int nslots_max = MIN (INT_MAX, IDX_MAX);
 878   if (! (0 <= n && n < nslots_max))
 879     abort ();
 880 
 881   if (nslots <= n)
 882     {
 883       bool preallocated = (sv == &slotvec0);
 884       idx_t new_nslots = nslots;
 885 
 886       slotvec = sv = xpalloc (preallocated ? NULL : sv, &new_nslots,
 887                               n - nslots + 1, nslots_max, sizeof *sv);
 888       if (preallocated)
 889         *sv = slotvec0;
 890       memset (sv + nslots, 0, (new_nslots - nslots) * sizeof *sv);
 891       nslots = new_nslots;
 892     }
 893 
 894   {
 895     size_t size = sv[n].size;
 896     char *val = sv[n].val;
 897     /* Elide embedded null bytes since we don't return a size.  */
 898     int flags = options->flags | QA_ELIDE_NULL_BYTES;
 899     size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize,
 900                                              options->style, flags,
 901                                              options->quote_these_too,
 902                                              options->left_quote,
 903                                              options->right_quote);
 904 
 905     if (size <= qsize)
 906       {
 907         sv[n].size = size = qsize + 1;
 908         if (val != slot0)
 909           free (val);
 910         sv[n].val = val = xcharalloc (size);
 911         quotearg_buffer_restyled (val, size, arg, argsize, options->style,
 912                                   flags, options->quote_these_too,
 913                                   options->left_quote,
 914                                   options->right_quote);
 915       }
 916 
 917     errno = e;
 918     return val;
 919   }
 920 }
 921 
 922 char *
 923 quotearg_n (int n, char const *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 924 {
 925   return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options);
 926 }
 927 
 928 char *
 929 quotearg_n_mem (int n, char const *arg, size_t argsize)
     /* [previous][next][first][last][top][bottom][index][help] */
 930 {
 931   return quotearg_n_options (n, arg, argsize, &default_quoting_options);
 932 }
 933 
 934 char *
 935 quotearg (char const *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 936 {
 937   return quotearg_n (0, arg);
 938 }
 939 
 940 char *
 941 quotearg_mem (char const *arg, size_t argsize)
     /* [previous][next][first][last][top][bottom][index][help] */
 942 {
 943   return quotearg_n_mem (0, arg, argsize);
 944 }
 945 
 946 char *
 947 quotearg_n_style (int n, enum quoting_style s, char const *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 948 {
 949   struct quoting_options const o = quoting_options_from_style (s);
 950   return quotearg_n_options (n, arg, SIZE_MAX, &o);
 951 }
 952 
 953 char *
 954 quotearg_n_style_mem (int n, enum quoting_style s,
     /* [previous][next][first][last][top][bottom][index][help] */
 955                       char const *arg, size_t argsize)
 956 {
 957   struct quoting_options const o = quoting_options_from_style (s);
 958   return quotearg_n_options (n, arg, argsize, &o);
 959 }
 960 
 961 char *
 962 quotearg_style (enum quoting_style s, char const *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 963 {
 964   return quotearg_n_style (0, s, arg);
 965 }
 966 
 967 char *
 968 quotearg_style_mem (enum quoting_style s, char const *arg, size_t argsize)
     /* [previous][next][first][last][top][bottom][index][help] */
 969 {
 970   return quotearg_n_style_mem (0, s, arg, argsize);
 971 }
 972 
 973 char *
 974 quotearg_char_mem (char const *arg, size_t argsize, char ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 975 {
 976   struct quoting_options options;
 977   options = default_quoting_options;
 978   set_char_quoting (&options, ch, 1);
 979   return quotearg_n_options (0, arg, argsize, &options);
 980 }
 981 
 982 char *
 983 quotearg_char (char const *arg, char ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 984 {
 985   return quotearg_char_mem (arg, SIZE_MAX, ch);
 986 }
 987 
 988 char *
 989 quotearg_colon (char const *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 990 {
 991   return quotearg_char (arg, ':');
 992 }
 993 
 994 char *
 995 quotearg_colon_mem (char const *arg, size_t argsize)
     /* [previous][next][first][last][top][bottom][index][help] */
 996 {
 997   return quotearg_char_mem (arg, argsize, ':');
 998 }
 999 
1000 char *
1001 quotearg_n_style_colon (int n, enum quoting_style s, char const *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1002 {
1003   struct quoting_options options;
1004   options = quoting_options_from_style (s);
1005   set_char_quoting (&options, ':', 1);
1006   return quotearg_n_options (n, arg, SIZE_MAX, &options);
1007 }
1008 
1009 char *
1010 quotearg_n_custom (int n, char const *left_quote,
     /* [previous][next][first][last][top][bottom][index][help] */
1011                    char const *right_quote, char const *arg)
1012 {
1013   return quotearg_n_custom_mem (n, left_quote, right_quote, arg,
1014                                 SIZE_MAX);
1015 }
1016 
1017 char *
1018 quotearg_n_custom_mem (int n, char const *left_quote,
     /* [previous][next][first][last][top][bottom][index][help] */
1019                        char const *right_quote,
1020                        char const *arg, size_t argsize)
1021 {
1022   struct quoting_options o = default_quoting_options;
1023   set_custom_quoting (&o, left_quote, right_quote);
1024   return quotearg_n_options (n, arg, argsize, &o);
1025 }
1026 
1027 char *
1028 quotearg_custom (char const *left_quote, char const *right_quote,
     /* [previous][next][first][last][top][bottom][index][help] */
1029                  char const *arg)
1030 {
1031   return quotearg_n_custom (0, left_quote, right_quote, arg);
1032 }
1033 
1034 char *
1035 quotearg_custom_mem (char const *left_quote, char const *right_quote,
     /* [previous][next][first][last][top][bottom][index][help] */
1036                      char const *arg, size_t argsize)
1037 {
1038   return quotearg_n_custom_mem (0, left_quote, right_quote, arg,
1039                                 argsize);
1040 }
1041 
1042 
1043 /* The quoting option used by the functions of quote.h.  */
1044 struct quoting_options quote_quoting_options =
1045   {
1046     locale_quoting_style,
1047     0,
1048     { 0 },
1049     NULL, NULL
1050   };
1051 
1052 char const *
1053 quote_n_mem (int n, char const *arg, size_t argsize)
     /* [previous][next][first][last][top][bottom][index][help] */
1054 {
1055   return quotearg_n_options (n, arg, argsize, &quote_quoting_options);
1056 }
1057 
1058 char const *
1059 quote_mem (char const *arg, size_t argsize)
     /* [previous][next][first][last][top][bottom][index][help] */
1060 {
1061   return quote_n_mem (0, arg, argsize);
1062 }
1063 
1064 char const *
1065 quote_n (int n, char const *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1066 {
1067   return quote_n_mem (n, arg, SIZE_MAX);
1068 }
1069 
1070 char const *
1071 quote (char const *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1072 {
1073   return quote_n (0, arg);
1074 }
1075 
1076 /*
1077  * Hey Emacs!
1078  * Local Variables:
1079  * coding: utf-8
1080  * End:
1081  */

/* [previous][next][first][last][top][bottom][index][help] */