LCOV - code coverage report
Current view: top level - lib - quotearg.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 171 326 52.5 %
Date: 2018-01-30 Functions: 13 25 52.0 %

          Line data    Source code
       1             : /* quotearg.c - quote arguments for output
       2             : 
       3             :    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007,
       4             :    2008 Free Software Foundation, Inc.
       5             : 
       6             :    This program is free software: you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      18             : 
      19             : /* Written by Paul Eggert <eggert@twinsun.com> */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #include "quotearg.h"
      24             : 
      25             : #include "xalloc.h"
      26             : 
      27             : #include <ctype.h>
      28             : #include <errno.h>
      29             : #include <limits.h>
      30             : #include <stdbool.h>
      31             : #include <stdlib.h>
      32             : #include <string.h>
      33             : #include <wchar.h>
      34             : #include <wctype.h>
      35             : 
      36             : #include "gettext.h"
      37             : #define _(msgid) gettext (msgid)
      38             : #define N_(msgid) msgid
      39             : 
      40             : #if !HAVE_MBRTOWC
      41             : /* Disable multibyte processing entirely.  Since MB_CUR_MAX is 1, the
      42             :    other macros are defined only for documentation and to satisfy C
      43             :    syntax.  */
      44             : # undef MB_CUR_MAX
      45             : # define MB_CUR_MAX 1
      46             : # undef mbstate_t
      47             : # define mbstate_t int
      48             : # define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
      49             : # define iswprint(wc) isprint ((unsigned char) (wc))
      50             : # undef HAVE_MBSINIT
      51             : #endif
      52             : 
      53             : #if !defined mbsinit && !HAVE_MBSINIT
      54             : # define mbsinit(ps) 1
      55             : #endif
      56             : 
      57             : #ifndef SIZE_MAX
      58             : # define SIZE_MAX ((size_t) -1)
      59             : #endif
      60             : 
      61             : #define INT_BITS (sizeof (int) * CHAR_BIT)
      62             : 
      63             : struct quoting_options
      64             : {
      65             :   /* Basic quoting style.  */
      66             :   enum quoting_style style;
      67             : 
      68             :   /* Additional flags.  Bitwise combination of enum quoting_flags.  */
      69             :   int flags;
      70             : 
      71             :   /* Quote the characters indicated by this bit vector even if the
      72             :      quoting style would not normally require them to be quoted.  */
      73             :   unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
      74             : };
      75             : 
      76             : /* Names of quoting styles.  */
      77             : char const *const quoting_style_args[] =
      78             : {
      79             :   "literal",
      80             :   "shell",
      81             :   "shell-always",
      82             :   "c",
      83             :   "c-maybe",
      84             :   "escape",
      85             :   "locale",
      86             :   "clocale",
      87             :   0
      88             : };
      89             : 
      90             : /* Correspondences to quoting style names.  */
      91             : enum quoting_style const quoting_style_vals[] =
      92             : {
      93             :   literal_quoting_style,
      94             :   shell_quoting_style,
      95             :   shell_always_quoting_style,
      96             :   c_quoting_style,
      97             :   c_maybe_quoting_style,
      98             :   escape_quoting_style,
      99             :   locale_quoting_style,
     100             :   clocale_quoting_style
     101             : };
     102             : 
     103             : /* The default quoting options.  */
     104             : static struct quoting_options default_quoting_options;
     105             : 
     106             : /* Allocate a new set of quoting options, with contents initially identical
     107             :    to O if O is not null, or to the default if O is null.
     108             :    It is the caller's responsibility to free the result.  */
     109             : struct quoting_options *
     110           0 : clone_quoting_options (struct quoting_options *o)
     111             : {
     112           0 :   int e = errno;
     113           0 :   struct quoting_options *p = xmemdup (o ? o : &default_quoting_options,
     114             :                                        sizeof *o);
     115           0 :   errno = e;
     116           0 :   return p;
     117             : }
     118             : 
     119             : /* Get the value of O's quoting style.  If O is null, use the default.  */
     120             : enum quoting_style
     121           0 : get_quoting_style (struct quoting_options *o)
     122             : {
     123           0 :   return (o ? o : &default_quoting_options)->style;
     124             : }
     125             : 
     126             : /* In O (or in the default if O is null),
     127             :    set the value of the quoting style to S.  */
     128             : void
     129          18 : set_quoting_style (struct quoting_options *o, enum quoting_style s)
     130             : {
     131          18 :   (o ? o : &default_quoting_options)->style = s;
     132          18 : }
     133             : 
     134             : /* In O (or in the default if O is null),
     135             :    set the value of the quoting options for character C to I.
     136             :    Return the old value.  Currently, the only values defined for I are
     137             :    0 (the default) and 1 (which means to quote the character even if
     138             :    it would not otherwise be quoted).  */
     139             : int
     140         188 : set_char_quoting (struct quoting_options *o, char c, int i)
     141             : {
     142         188 :   unsigned char uc = c;
     143         188 :   unsigned int *p =
     144         188 :     (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
     145         188 :   int shift = uc % INT_BITS;
     146         188 :   int r = (*p >> shift) & 1;
     147         188 :   *p ^= ((i & 1) ^ r) << shift;
     148         188 :   return r;
     149             : }
     150             : 
     151             : /* In O (or in the default if O is null),
     152             :    set the value of the quoting options flag to I, which can be a
     153             :    bitwise combination of enum quoting_flags, or 0 for default
     154             :    behavior.  Return the old value.  */
     155             : int
     156           0 : set_quoting_flags (struct quoting_options *o, int i)
     157             : {
     158             :   int r;
     159           0 :   if (!o)
     160           0 :     o = &default_quoting_options;
     161           0 :   r = o->flags;
     162           0 :   o->flags = i;
     163           0 :   return r;
     164             : }
     165             : 
     166             : /* Return quoting options for STYLE, with no extra quoting.  */
     167             : static struct quoting_options
     168      408534 : quoting_options_from_style (enum quoting_style style)
     169             : {
     170             :   struct quoting_options o;
     171      408534 :   o.style = style;
     172      408534 :   o.flags = 0;
     173      408534 :   memset (o.quote_these_too, 0, sizeof o.quote_these_too);
     174      408534 :   return o;
     175             : }
     176             : 
     177             : /* MSGID approximates a quotation mark.  Return its translation if it
     178             :    has one; otherwise, return either it or "\"", depending on S.  */
     179             : static char const *
     180      817366 : gettext_quote (char const *msgid, enum quoting_style s)
     181             : {
     182      817366 :   char const *translation = _(msgid);
     183      817366 :   if (translation == msgid && s == clocale_quoting_style)
     184           0 :     translation = "\"";
     185      817366 :   return translation;
     186             : }
     187             : 
     188             : /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
     189             :    argument ARG (of size ARGSIZE), using QUOTING_STYLE, FLAGS, and
     190             :    QUOTE_THESE_TOO to control quoting.
     191             :    Terminate the output with a null character, and return the written
     192             :    size of the output, not counting the terminating null.
     193             :    If BUFFERSIZE is too small to store the output string, return the
     194             :    value that would have been returned had BUFFERSIZE been large enough.
     195             :    If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE.
     196             : 
     197             :    This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
     198             :    ARGSIZE, O), except it breaks O into its component pieces and is
     199             :    not careful about errno.  */
     200             : 
     201             : static size_t
     202      408885 : quotearg_buffer_restyled (char *buffer, size_t buffersize,
     203             :                           char const *arg, size_t argsize,
     204             :                           enum quoting_style quoting_style, int flags,
     205             :                           unsigned int const *quote_these_too)
     206             : {
     207             :   size_t i;
     208      408885 :   size_t len = 0;
     209      408885 :   char const *quote_string = 0;
     210      408885 :   size_t quote_string_len = 0;
     211      408885 :   bool backslash_escapes = false;
     212      408885 :   bool unibyte_locale = MB_CUR_MAX == 1;
     213      408885 :   bool elide_outer_quotes = (flags & QA_ELIDE_OUTER_QUOTES) != 0;
     214             : 
     215             : #define STORE(c) \
     216             :     do \
     217             :       { \
     218             :         if (len < buffersize) \
     219             :           buffer[len] = (c); \
     220             :         len++; \
     221             :       } \
     222             :     while (0)
     223             : 
     224      408885 :   switch (quoting_style)
     225             :     {
     226           0 :     case c_maybe_quoting_style:
     227           0 :       quoting_style = c_quoting_style;
     228           0 :       elide_outer_quotes = true;
     229             :       /* Fall through.  */
     230           0 :     case c_quoting_style:
     231           0 :       if (!elide_outer_quotes)
     232           0 :         STORE ('"');
     233           0 :       backslash_escapes = true;
     234           0 :       quote_string = "\"";
     235           0 :       quote_string_len = 1;
     236           0 :       break;
     237             : 
     238          18 :     case escape_quoting_style:
     239          18 :       backslash_escapes = true;
     240          18 :       elide_outer_quotes = false;
     241          18 :       break;
     242             : 
     243      408683 :     case locale_quoting_style:
     244             :     case clocale_quoting_style:
     245             :       {
     246             :         /* TRANSLATORS:
     247             :            Get translations for open and closing quotation marks.
     248             : 
     249             :            The message catalog should translate "`" to a left
     250             :            quotation mark suitable for the locale, and similarly for
     251             :            "'".  If the catalog has no translation,
     252             :            locale_quoting_style quotes `like this', and
     253             :            clocale_quoting_style quotes "like this".
     254             : 
     255             :            For example, an American English Unicode locale should
     256             :            translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and
     257             :            should translate "'" to U+201D (RIGHT DOUBLE QUOTATION
     258             :            MARK).  A British English Unicode locale should instead
     259             :            translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and
     260             :            U+2019 (RIGHT SINGLE QUOTATION MARK), respectively.
     261             : 
     262             :            If you don't know what to put here, please see
     263             :            <http://en.wikipedia.org/wiki/Quotation_mark#Glyphs>
     264             :            and use glyphs suitable for your language.  */
     265             : 
     266      408683 :         char const *left = gettext_quote (N_("`"), quoting_style);
     267      408683 :         char const *right = gettext_quote (N_("'"), quoting_style);
     268      408683 :         if (!elide_outer_quotes)
     269      817366 :           for (quote_string = left; *quote_string; quote_string++)
     270      408683 :             STORE (*quote_string);
     271      408683 :         backslash_escapes = true;
     272      408683 :         quote_string = right;
     273      408683 :         quote_string_len = strlen (quote_string);
     274             :       }
     275      408683 :       break;
     276             : 
     277           4 :     case shell_quoting_style:
     278           4 :       quoting_style = shell_always_quoting_style;
     279           4 :       elide_outer_quotes = true;
     280             :       /* Fall through.  */
     281           4 :     case shell_always_quoting_style:
     282           4 :       if (!elide_outer_quotes)
     283           0 :         STORE ('\'');
     284           4 :       quote_string = "'";
     285           4 :       quote_string_len = 1;
     286           4 :       break;
     287             : 
     288         180 :     case literal_quoting_style:
     289         180 :       elide_outer_quotes = false;
     290         180 :       break;
     291             : 
     292           0 :     default:
     293           0 :       abort ();
     294             :     }
     295             : 
     296    16417439 :   for (i = 0;  ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize);  i++)
     297             :     {
     298             :       unsigned char c;
     299             :       unsigned char esc;
     300             : 
     301    16008554 :       if (backslash_escapes
     302    16007786 :           && quote_string_len
     303    16007741 :           && i + quote_string_len <= argsize
     304    16007741 :           && memcmp (arg + i, quote_string, quote_string_len) == 0)
     305             :         {
     306         295 :           if (elide_outer_quotes)
     307           0 :             goto force_outer_quoting_style;
     308         295 :           STORE ('\\');
     309             :         }
     310             : 
     311    16008554 :       c = arg[i];
     312    16008554 :       switch (c)
     313             :         {
     314           0 :         case '\0':
     315           0 :           if (backslash_escapes)
     316             :             {
     317           0 :               if (elide_outer_quotes)
     318           0 :                 goto force_outer_quoting_style;
     319           0 :               STORE ('\\');
     320           0 :               if (i + 1 < argsize && '0' <= arg[i + 1] && arg[i + 1] <= '9')
     321             :                 {
     322           0 :                   STORE ('0');
     323           0 :                   STORE ('0');
     324             :                 }
     325           0 :               c = '0';
     326             :             }
     327           0 :           else if (flags & QA_ELIDE_NULL_BYTES)
     328           0 :             continue;
     329           0 :           break;
     330             : 
     331          67 :         case '?':
     332          67 :           switch (quoting_style)
     333             :             {
     334           0 :             case shell_always_quoting_style:
     335           0 :               if (elide_outer_quotes)
     336           0 :                 goto force_outer_quoting_style;
     337           0 :               break;
     338             : 
     339           0 :             case c_quoting_style:
     340           0 :               if ((flags & QA_SPLIT_TRIGRAPHS)
     341           0 :                   && i + 2 < argsize && arg[i + 1] == '?')
     342           0 :                 switch (arg[i + 2])
     343             :                   {
     344           0 :                   case '!': case '\'':
     345             :                   case '(': case ')': case '-': case '/':
     346             :                   case '<': case '=': case '>':
     347             :                     /* Escape the second '?' in what would otherwise be
     348             :                        a trigraph.  */
     349           0 :                     if (elide_outer_quotes)
     350           0 :                       goto force_outer_quoting_style;
     351           0 :                     c = arg[i + 2];
     352           0 :                     i += 2;
     353           0 :                     STORE ('?');
     354           0 :                     STORE ('"');
     355           0 :                     STORE ('"');
     356           0 :                     STORE ('?');
     357           0 :                     break;
     358             : 
     359           0 :                   default:
     360           0 :                     break;
     361             :                   }
     362           0 :               break;
     363             : 
     364          67 :             default:
     365          67 :               break;
     366             :             }
     367          67 :           break;
     368             : 
     369          11 :         case '\a': esc = 'a'; goto c_escape;
     370          59 :         case '\b': esc = 'b'; goto c_escape;
     371          59 :         case '\f': esc = 'f'; goto c_escape;
     372          12 :         case '\n': esc = 'n'; goto c_and_shell_escape;
     373          70 :         case '\r': esc = 'r'; goto c_and_shell_escape;
     374         121 :         case '\t': esc = 't'; goto c_and_shell_escape;
     375          76 :         case '\v': esc = 'v'; goto c_escape;
     376         104 :         case '\\': esc = c;
     377             :           /* No need to escape the escape if we are trying to elide
     378             :              outer quotes and nothing else is problematic.  */
     379         104 :           if (backslash_escapes && elide_outer_quotes && quote_string_len)
     380           0 :             goto store_c;
     381             : 
     382         104 :         c_and_shell_escape:
     383         307 :           if (quoting_style == shell_always_quoting_style
     384           0 :               && elide_outer_quotes)
     385           0 :             goto force_outer_quoting_style;
     386             :           /* Fall through.  */
     387         307 :         c_escape:
     388         512 :           if (backslash_escapes)
     389             :             {
     390         495 :               c = esc;
     391         495 :               goto store_escape;
     392             :             }
     393          17 :           break;
     394             : 
     395          59 :         case '{': case '}': /* sometimes special if isolated */
     396          59 :           if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1))
     397          22 :             break;
     398             :           /* Fall through.  */
     399             :         case '#': case '~':
     400         145 :           if (i != 0)
     401          75 :             break;
     402             :           /* Fall through.  */
     403             :         case ' ':
     404             :         case '!': /* special in bash */
     405             :         case '"': case '$': case '&':
     406             :         case '(': case ')': case '*': case ';':
     407             :         case '<':
     408             :         case '=': /* sometimes special in 0th or (with "set -k") later args */
     409             :         case '>': case '[':
     410             :         case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
     411             :         case '`': case '|':
     412             :           /* A shell special character.  In theory, '$' and '`' could
     413             :              be the first bytes of multibyte characters, which means
     414             :              we should check them with mbrtowc, but in practice this
     415             :              doesn't happen so it's not worth worrying about.  */
     416         790 :           if (quoting_style == shell_always_quoting_style
     417           0 :               && elide_outer_quotes)
     418           0 :             goto force_outer_quoting_style;
     419         790 :           break;
     420             : 
     421         297 :         case '\'':
     422         297 :           if (quoting_style == shell_always_quoting_style)
     423             :             {
     424           0 :               if (elide_outer_quotes)
     425           0 :                 goto force_outer_quoting_style;
     426           0 :               STORE ('\'');
     427           0 :               STORE ('\\');
     428           0 :               STORE ('\'');
     429             :             }
     430         297 :           break;
     431             : 
     432    16006243 :         case '%': case '+': case ',': case '-': case '.': case '/':
     433             :         case '0': case '1': case '2': case '3': case '4': case '5':
     434             :         case '6': case '7': case '8': case '9': case ':':
     435             :         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
     436             :         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
     437             :         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
     438             :         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
     439             :         case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
     440             :         case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
     441             :         case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
     442             :         case 'o': case 'p': case 'q': case 'r': case 's': case 't':
     443             :         case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
     444             :           /* These characters don't cause problems, no matter what the
     445             :              quoting style is.  They cannot start multibyte sequences.  */
     446    16006243 :           break;
     447             : 
     448         548 :         default:
     449             :           /* If we have a multibyte sequence, copy it until we reach
     450             :              its end, find an error, or come back to the initial shift
     451             :              state.  For C-like styles, if the sequence has
     452             :              unprintable characters, escape the whole sequence, since
     453             :              we can't easily escape single characters within it.  */
     454             :           {
     455             :             /* Length of multibyte sequence found so far.  */
     456             :             size_t m;
     457             : 
     458             :             bool printable;
     459             : 
     460         548 :             if (unibyte_locale)
     461             :               {
     462         548 :                 m = 1;
     463         548 :                 printable = isprint (c) != 0;
     464             :               }
     465             :             else
     466             :               {
     467             :                 mbstate_t mbstate;
     468           0 :                 memset (&mbstate, 0, sizeof mbstate);
     469             : 
     470           0 :                 m = 0;
     471           0 :                 printable = true;
     472           0 :                 if (argsize == SIZE_MAX)
     473           0 :                   argsize = strlen (arg);
     474             : 
     475             :                 do
     476             :                   {
     477             :                     wchar_t w;
     478           0 :                     size_t bytes = mbrtowc (&w, &arg[i + m],
     479           0 :                                             argsize - (i + m), &mbstate);
     480           0 :                     if (bytes == 0)
     481           0 :                       break;
     482           0 :                     else if (bytes == (size_t) -1)
     483             :                       {
     484           0 :                         printable = false;
     485           0 :                         break;
     486             :                       }
     487           0 :                     else if (bytes == (size_t) -2)
     488             :                       {
     489           0 :                         printable = false;
     490           0 :                         while (i + m < argsize && arg[i + m])
     491           0 :                           m++;
     492           0 :                         break;
     493             :                       }
     494             :                     else
     495             :                       {
     496             :                         /* Work around a bug with older shells that "see" a '\'
     497             :                            that is really the 2nd byte of a multibyte character.
     498             :                            In practice the problem is limited to ASCII
     499             :                            chars >= '@' that are shell special chars.  */
     500           0 :                         if ('[' == 0x5b && elide_outer_quotes
     501           0 :                             && quoting_style == shell_always_quoting_style)
     502             :                           {
     503             :                             size_t j;
     504           0 :                             for (j = 1; j < bytes; j++)
     505           0 :                               switch (arg[i + m + j])
     506             :                                 {
     507           0 :                                 case '[': case '\\': case '^':
     508             :                                 case '`': case '|':
     509           0 :                                   goto force_outer_quoting_style;
     510             : 
     511           0 :                                 default:
     512           0 :                                   break;
     513             :                                 }
     514             :                           }
     515             : 
     516           0 :                         if (! iswprint (w))
     517           0 :                           printable = false;
     518           0 :                         m += bytes;
     519             :                       }
     520             :                   }
     521           0 :                 while (! mbsinit (&mbstate));
     522             :               }
     523             : 
     524         548 :             if (1 < m || (backslash_escapes && ! printable))
     525             :               {
     526             :                 /* Output a multibyte sequence, or an escaped
     527             :                    unprintable unibyte character.  */
     528         352 :                 size_t ilim = i + m;
     529             : 
     530             :                 for (;;)
     531             :                   {
     532         352 :                     if (backslash_escapes && ! printable)
     533             :                       {
     534         352 :                         if (elide_outer_quotes)
     535           0 :                           goto force_outer_quoting_style;
     536         352 :                         STORE ('\\');
     537         352 :                         STORE ('0' + (c >> 6));
     538         352 :                         STORE ('0' + ((c >> 3) & 7));
     539         352 :                         c = '0' + (c & 7);
     540             :                       }
     541         352 :                     if (ilim <= i + 1)
     542         352 :                       break;
     543           0 :                     STORE (c);
     544           0 :                     c = arg[++i];
     545             :                   }
     546             : 
     547         352 :                 goto store_c;
     548             :               }
     549             :           }
     550             :         }
     551             : 
     552    32014654 :       if (! ((backslash_escapes || elide_outer_quotes)
     553    16006947 :              && quote_these_too
     554    16006947 :              && quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
     555             :         goto store_c;
     556             : 
     557           1 :     store_escape:
     558         496 :       if (elide_outer_quotes)
     559           0 :         goto force_outer_quoting_style;
     560         496 :       STORE ('\\');
     561             : 
     562    32016260 :     store_c:
     563    16008554 :       STORE (c);
     564             :     }
     565             : 
     566      408885 :   if (len == 0 && quoting_style == shell_always_quoting_style
     567           0 :       && elide_outer_quotes)
     568           0 :     goto force_outer_quoting_style;
     569             : 
     570      408885 :   if (quote_string && !elide_outer_quotes)
     571      817366 :     for (; *quote_string; quote_string++)
     572      408683 :       STORE (*quote_string);
     573             : 
     574      408885 :   if (len < buffersize)
     575      408732 :     buffer[len] = '\0';
     576      408885 :   return len;
     577             : 
     578           0 :  force_outer_quoting_style:
     579             :   /* Don't reuse quote_these_too, since the addition of outer quotes
     580             :      sufficiently quotes the specified characters.  */
     581           0 :   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
     582             :                                    quoting_style,
     583             :                                    flags & ~QA_ELIDE_OUTER_QUOTES, NULL);
     584             : }
     585             : 
     586             : /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
     587             :    argument ARG (of size ARGSIZE), using O to control quoting.
     588             :    If O is null, use the default.
     589             :    Terminate the output with a null character, and return the written
     590             :    size of the output, not counting the terminating null.
     591             :    If BUFFERSIZE is too small to store the output string, return the
     592             :    value that would have been returned had BUFFERSIZE been large enough.
     593             :    If ARGSIZE is SIZE_MAX, use the string length of the argument for
     594             :    ARGSIZE.  */
     595             : size_t
     596           0 : quotearg_buffer (char *buffer, size_t buffersize,
     597             :                  char const *arg, size_t argsize,
     598             :                  struct quoting_options const *o)
     599             : {
     600           0 :   struct quoting_options const *p = o ? o : &default_quoting_options;
     601           0 :   int e = errno;
     602           0 :   size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
     603           0 :                                        p->style, p->flags, p->quote_these_too);
     604           0 :   errno = e;
     605           0 :   return r;
     606             : }
     607             : 
     608             : /* Equivalent to quotearg_alloc (ARG, ARGSIZE, NULL, O).  */
     609             : char *
     610           0 : quotearg_alloc (char const *arg, size_t argsize,
     611             :                 struct quoting_options const *o)
     612             : {
     613           0 :   return quotearg_alloc_mem (arg, argsize, NULL, o);
     614             : }
     615             : 
     616             : /* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
     617             :    allocated storage containing the quoted string, and store the
     618             :    resulting size into *SIZE, if non-NULL.  The result can contain
     619             :    embedded null bytes only if ARGSIZE is not SIZE_MAX, SIZE is not
     620             :    NULL, and set_quoting_flags has not set the null byte elision
     621             :    flag.  */
     622             : char *
     623           0 : quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size,
     624             :                     struct quoting_options const *o)
     625             : {
     626           0 :   struct quoting_options const *p = o ? o : &default_quoting_options;
     627           0 :   int e = errno;
     628             :   /* Elide embedded null bytes if we can't return a size.  */
     629           0 :   int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES);
     630           0 :   size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style,
     631           0 :                                              flags, p->quote_these_too) + 1;
     632           0 :   char *buf = xcharalloc (bufsize);
     633           0 :   quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags,
     634           0 :                             p->quote_these_too);
     635           0 :   errno = e;
     636           0 :   if (size)
     637           0 :     *size = bufsize - 1;
     638           0 :   return buf;
     639             : }
     640             : 
     641             : /* A storage slot with size and pointer to a value.  */
     642             : struct slotvec
     643             : {
     644             :   size_t size;
     645             :   char *val;
     646             : };
     647             : 
     648             : /* Preallocate a slot 0 buffer, so that the caller can always quote
     649             :    one small component of a "memory exhausted" message in slot 0.  */
     650             : static char slot0[256];
     651             : static unsigned int nslots = 1;
     652             : static struct slotvec slotvec0 = {sizeof slot0, slot0};
     653             : static struct slotvec *slotvec = &slotvec0;
     654             : 
     655             : void
     656           0 : quotearg_free (void)
     657             : {
     658           0 :   struct slotvec *sv = slotvec;
     659             :   unsigned int i;
     660           0 :   for (i = 1; i < nslots; i++)
     661           0 :     free (sv[i].val);
     662           0 :   if (sv[0].val != slot0)
     663             :     {
     664           0 :       free (sv[0].val);
     665           0 :       slotvec0.size = sizeof slot0;
     666           0 :       slotvec0.val = slot0;
     667             :     }
     668           0 :   if (sv != &slotvec0)
     669             :     {
     670           0 :       free (sv);
     671           0 :       slotvec = &slotvec0;
     672             :     }
     673           0 :   nslots = 1;
     674           0 : }
     675             : 
     676             : /* Use storage slot N to return a quoted version of argument ARG.
     677             :    ARG is of size ARGSIZE, but if that is SIZE_MAX, ARG is a
     678             :    null-terminated string.
     679             :    OPTIONS specifies the quoting options.
     680             :    The returned value points to static storage that can be
     681             :    reused by the next call to this function with the same value of N.
     682             :    N must be nonnegative.  N is deliberately declared with type "int"
     683             :    to allow for future extensions (using negative values).  */
     684             : static char *
     685      408732 : quotearg_n_options (int n, char const *arg, size_t argsize,
     686             :                     struct quoting_options const *options)
     687             : {
     688      408732 :   int e = errno;
     689             : 
     690      408732 :   unsigned int n0 = n;
     691      408732 :   struct slotvec *sv = slotvec;
     692             : 
     693      408732 :   if (n < 0)
     694           0 :     abort ();
     695             : 
     696      408732 :   if (nslots <= n0)
     697             :     {
     698             :       /* FIXME: technically, the type of n1 should be `unsigned int',
     699             :          but that evokes an unsuppressible warning from gcc-4.0.1 and
     700             :          older.  If gcc ever provides an option to suppress that warning,
     701             :          revert to the original type, so that the test in xalloc_oversized
     702             :          is once again performed only at compile time.  */
     703         153 :       size_t n1 = n0 + 1;
     704         153 :       bool preallocated = (sv == &slotvec0);
     705             : 
     706         153 :       if (xalloc_oversized (n1, sizeof *sv))
     707           0 :         xalloc_die ();
     708             : 
     709         153 :       slotvec = sv = xrealloc (preallocated ? NULL : sv, n1 * sizeof *sv);
     710         153 :       if (preallocated)
     711         153 :         *sv = slotvec0;
     712         153 :       memset (sv + nslots, 0, (n1 - nslots) * sizeof *sv);
     713         153 :       nslots = n1;
     714             :     }
     715             : 
     716             :   {
     717      408732 :     size_t size = sv[n].size;
     718      408732 :     char *val = sv[n].val;
     719             :     /* Elide embedded null bytes since we don't return a size.  */
     720      408732 :     int flags = options->flags | QA_ELIDE_NULL_BYTES;
     721      408732 :     size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize,
     722             :                                              options->style, flags,
     723      408732 :                                              options->quote_these_too);
     724             : 
     725      408732 :     if (size <= qsize)
     726             :       {
     727         153 :         sv[n].size = size = qsize + 1;
     728         153 :         if (val != slot0)
     729         153 :           free (val);
     730         153 :         sv[n].val = val = xcharalloc (size);
     731         153 :         quotearg_buffer_restyled (val, size, arg, argsize, options->style,
     732         153 :                                   flags, options->quote_these_too);
     733             :       }
     734             : 
     735      408732 :     errno = e;
     736      408732 :     return val;
     737             :   }
     738             : }
     739             : 
     740             : char *
     741          10 : quotearg_n (int n, char const *arg)
     742             : {
     743          10 :   return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options);
     744             : }
     745             : 
     746             : char *
     747           0 : quotearg_n_mem (int n, char const *arg, size_t argsize)
     748             : {
     749           0 :   return quotearg_n_options (n, arg, argsize, &default_quoting_options);
     750             : }
     751             : 
     752             : char *
     753          10 : quotearg (char const *arg)
     754             : {
     755          10 :   return quotearg_n (0, arg);
     756             : }
     757             : 
     758             : char *
     759           0 : quotearg_mem (char const *arg, size_t argsize)
     760             : {
     761           0 :   return quotearg_n_mem (0, arg, argsize);
     762             : }
     763             : 
     764             : char *
     765      408526 : quotearg_n_style (int n, enum quoting_style s, char const *arg)
     766             : {
     767      408526 :   struct quoting_options const o = quoting_options_from_style (s);
     768      408526 :   return quotearg_n_options (n, arg, SIZE_MAX, &o);
     769             : }
     770             : 
     771             : char *
     772           8 : quotearg_n_style_mem (int n, enum quoting_style s,
     773             :                       char const *arg, size_t argsize)
     774             : {
     775           8 :   struct quoting_options const o = quoting_options_from_style (s);
     776           8 :   return quotearg_n_options (n, arg, argsize, &o);
     777             : }
     778             : 
     779             : char *
     780           0 : quotearg_style (enum quoting_style s, char const *arg)
     781             : {
     782           0 :   return quotearg_n_style (0, s, arg);
     783             : }
     784             : 
     785             : char *
     786           0 : quotearg_style_mem (enum quoting_style s, char const *arg, size_t argsize)
     787             : {
     788           0 :   return quotearg_n_style_mem (0, s, arg, argsize);
     789             : }
     790             : 
     791             : char *
     792         188 : quotearg_char_mem (char const *arg, size_t argsize, char ch)
     793             : {
     794             :   struct quoting_options options;
     795         188 :   options = default_quoting_options;
     796         188 :   set_char_quoting (&options, ch, 1);
     797         188 :   return quotearg_n_options (0, arg, argsize, &options);
     798             : }
     799             : 
     800             : char *
     801         188 : quotearg_char (char const *arg, char ch)
     802             : {
     803         188 :   return quotearg_char_mem (arg, SIZE_MAX, ch);
     804             : }
     805             : 
     806             : char *
     807         188 : quotearg_colon (char const *arg)
     808             : {
     809         188 :   return quotearg_char (arg, ':');
     810             : }
     811             : 
     812             : char *
     813           0 : quotearg_colon_mem (char const *arg, size_t argsize)
     814             : {
     815           0 :   return quotearg_char_mem (arg, argsize, ':');
     816             : }

Generated by: LCOV version 1.10