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