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