OLD | NEW |
(Empty) | |
| 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 clone_quoting_options (struct quoting_options *o) |
| 111 { |
| 112 int e = errno; |
| 113 struct quoting_options *p = xmemdup (o ? o : &default_quoting_options, |
| 114 sizeof *o); |
| 115 errno = e; |
| 116 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 get_quoting_style (struct quoting_options *o) |
| 122 { |
| 123 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 set_quoting_style (struct quoting_options *o, enum quoting_style s) |
| 130 { |
| 131 (o ? o : &default_quoting_options)->style = s; |
| 132 } |
| 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 set_char_quoting (struct quoting_options *o, char c, int i) |
| 141 { |
| 142 unsigned char uc = c; |
| 143 unsigned int *p = |
| 144 (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS; |
| 145 int shift = uc % INT_BITS; |
| 146 int r = (*p >> shift) & 1; |
| 147 *p ^= ((i & 1) ^ r) << shift; |
| 148 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 set_quoting_flags (struct quoting_options *o, int i) |
| 157 { |
| 158 int r; |
| 159 if (!o) |
| 160 o = &default_quoting_options; |
| 161 r = o->flags; |
| 162 o->flags = i; |
| 163 return r; |
| 164 } |
| 165 |
| 166 /* Return quoting options for STYLE, with no extra quoting. */ |
| 167 static struct quoting_options |
| 168 quoting_options_from_style (enum quoting_style style) |
| 169 { |
| 170 struct quoting_options o; |
| 171 o.style = style; |
| 172 o.flags = 0; |
| 173 memset (o.quote_these_too, 0, sizeof o.quote_these_too); |
| 174 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 gettext_quote (char const *msgid, enum quoting_style s) |
| 181 { |
| 182 char const *translation = _(msgid); |
| 183 if (translation == msgid && s == clocale_quoting_style) |
| 184 translation = "\""; |
| 185 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 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 size_t len = 0; |
| 209 char const *quote_string = 0; |
| 210 size_t quote_string_len = 0; |
| 211 bool backslash_escapes = false; |
| 212 bool unibyte_locale = MB_CUR_MAX == 1; |
| 213 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 switch (quoting_style) |
| 225 { |
| 226 case c_maybe_quoting_style: |
| 227 quoting_style = c_quoting_style; |
| 228 elide_outer_quotes = true; |
| 229 /* Fall through. */ |
| 230 case c_quoting_style: |
| 231 if (!elide_outer_quotes) |
| 232 STORE ('"'); |
| 233 backslash_escapes = true; |
| 234 quote_string = "\""; |
| 235 quote_string_len = 1; |
| 236 break; |
| 237 |
| 238 case escape_quoting_style: |
| 239 backslash_escapes = true; |
| 240 elide_outer_quotes = false; |
| 241 break; |
| 242 |
| 243 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 char const *left = gettext_quote (N_("`"), quoting_style); |
| 267 char const *right = gettext_quote (N_("'"), quoting_style); |
| 268 if (!elide_outer_quotes) |
| 269 for (quote_string = left; *quote_string; quote_string++) |
| 270 STORE (*quote_string); |
| 271 backslash_escapes = true; |
| 272 quote_string = right; |
| 273 quote_string_len = strlen (quote_string); |
| 274 } |
| 275 break; |
| 276 |
| 277 case shell_quoting_style: |
| 278 quoting_style = shell_always_quoting_style; |
| 279 elide_outer_quotes = true; |
| 280 /* Fall through. */ |
| 281 case shell_always_quoting_style: |
| 282 if (!elide_outer_quotes) |
| 283 STORE ('\''); |
| 284 quote_string = "'"; |
| 285 quote_string_len = 1; |
| 286 break; |
| 287 |
| 288 case literal_quoting_style: |
| 289 elide_outer_quotes = false; |
| 290 break; |
| 291 |
| 292 default: |
| 293 abort (); |
| 294 } |
| 295 |
| 296 for (i = 0; ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize); i++) |
| 297 { |
| 298 unsigned char c; |
| 299 unsigned char esc; |
| 300 |
| 301 if (backslash_escapes |
| 302 && quote_string_len |
| 303 && i + quote_string_len <= argsize |
| 304 && memcmp (arg + i, quote_string, quote_string_len) == 0) |
| 305 { |
| 306 if (elide_outer_quotes) |
| 307 goto force_outer_quoting_style; |
| 308 STORE ('\\'); |
| 309 } |
| 310 |
| 311 c = arg[i]; |
| 312 switch (c) |
| 313 { |
| 314 case '\0': |
| 315 if (backslash_escapes) |
| 316 { |
| 317 if (elide_outer_quotes) |
| 318 goto force_outer_quoting_style; |
| 319 STORE ('\\'); |
| 320 if (i + 1 < argsize && '0' <= arg[i + 1] && arg[i + 1] <= '9') |
| 321 { |
| 322 STORE ('0'); |
| 323 STORE ('0'); |
| 324 } |
| 325 c = '0'; |
| 326 } |
| 327 else if (flags & QA_ELIDE_NULL_BYTES) |
| 328 continue; |
| 329 break; |
| 330 |
| 331 case '?': |
| 332 switch (quoting_style) |
| 333 { |
| 334 case shell_always_quoting_style: |
| 335 if (elide_outer_quotes) |
| 336 goto force_outer_quoting_style; |
| 337 break; |
| 338 |
| 339 case c_quoting_style: |
| 340 if ((flags & QA_SPLIT_TRIGRAPHS) |
| 341 && i + 2 < argsize && arg[i + 1] == '?') |
| 342 switch (arg[i + 2]) |
| 343 { |
| 344 case '!': case '\'': |
| 345 case '(': case ')': case '-': case '/': |
| 346 case '<': case '=': case '>': |
| 347 /* Escape the second '?' in what would otherwise be |
| 348 a trigraph. */ |
| 349 if (elide_outer_quotes) |
| 350 goto force_outer_quoting_style; |
| 351 c = arg[i + 2]; |
| 352 i += 2; |
| 353 STORE ('?'); |
| 354 STORE ('"'); |
| 355 STORE ('"'); |
| 356 STORE ('?'); |
| 357 break; |
| 358 |
| 359 default: |
| 360 break; |
| 361 } |
| 362 break; |
| 363 |
| 364 default: |
| 365 break; |
| 366 } |
| 367 break; |
| 368 |
| 369 case '\a': esc = 'a'; goto c_escape; |
| 370 case '\b': esc = 'b'; goto c_escape; |
| 371 case '\f': esc = 'f'; goto c_escape; |
| 372 case '\n': esc = 'n'; goto c_and_shell_escape; |
| 373 case '\r': esc = 'r'; goto c_and_shell_escape; |
| 374 case '\t': esc = 't'; goto c_and_shell_escape; |
| 375 case '\v': esc = 'v'; goto c_escape; |
| 376 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 if (backslash_escapes && elide_outer_quotes && quote_string_len) |
| 380 goto store_c; |
| 381 |
| 382 c_and_shell_escape: |
| 383 if (quoting_style == shell_always_quoting_style |
| 384 && elide_outer_quotes) |
| 385 goto force_outer_quoting_style; |
| 386 /* Fall through. */ |
| 387 c_escape: |
| 388 if (backslash_escapes) |
| 389 { |
| 390 c = esc; |
| 391 goto store_escape; |
| 392 } |
| 393 break; |
| 394 |
| 395 case '{': case '}': /* sometimes special if isolated */ |
| 396 if (! (argsize == SIZE_MAX ? arg[1] == '\0' : argsize == 1)) |
| 397 break; |
| 398 /* Fall through. */ |
| 399 case '#': case '~': |
| 400 if (i != 0) |
| 401 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 if (quoting_style == shell_always_quoting_style |
| 417 && elide_outer_quotes) |
| 418 goto force_outer_quoting_style; |
| 419 break; |
| 420 |
| 421 case '\'': |
| 422 if (quoting_style == shell_always_quoting_style) |
| 423 { |
| 424 if (elide_outer_quotes) |
| 425 goto force_outer_quoting_style; |
| 426 STORE ('\''); |
| 427 STORE ('\\'); |
| 428 STORE ('\''); |
| 429 } |
| 430 break; |
| 431 |
| 432 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 break; |
| 447 |
| 448 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 if (unibyte_locale) |
| 461 { |
| 462 m = 1; |
| 463 printable = isprint (c) != 0; |
| 464 } |
| 465 else |
| 466 { |
| 467 mbstate_t mbstate; |
| 468 memset (&mbstate, 0, sizeof mbstate); |
| 469 |
| 470 m = 0; |
| 471 printable = true; |
| 472 if (argsize == SIZE_MAX) |
| 473 argsize = strlen (arg); |
| 474 |
| 475 do |
| 476 { |
| 477 wchar_t w; |
| 478 size_t bytes = mbrtowc (&w, &arg[i + m], |
| 479 argsize - (i + m), &mbstate); |
| 480 if (bytes == 0) |
| 481 break; |
| 482 else if (bytes == (size_t) -1) |
| 483 { |
| 484 printable = false; |
| 485 break; |
| 486 } |
| 487 else if (bytes == (size_t) -2) |
| 488 { |
| 489 printable = false; |
| 490 while (i + m < argsize && arg[i + m]) |
| 491 m++; |
| 492 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 if ('[' == 0x5b && elide_outer_quotes |
| 501 && quoting_style == shell_always_quoting_style) |
| 502 { |
| 503 size_t j; |
| 504 for (j = 1; j < bytes; j++) |
| 505 switch (arg[i + m + j]) |
| 506 { |
| 507 case '[': case '\\': case '^': |
| 508 case '`': case '|': |
| 509 goto force_outer_quoting_style; |
| 510 |
| 511 default: |
| 512 break; |
| 513 } |
| 514 } |
| 515 |
| 516 if (! iswprint (w)) |
| 517 printable = false; |
| 518 m += bytes; |
| 519 } |
| 520 } |
| 521 while (! mbsinit (&mbstate)); |
| 522 } |
| 523 |
| 524 if (1 < m || (backslash_escapes && ! printable)) |
| 525 { |
| 526 /* Output a multibyte sequence, or an escaped |
| 527 unprintable unibyte character. */ |
| 528 size_t ilim = i + m; |
| 529 |
| 530 for (;;) |
| 531 { |
| 532 if (backslash_escapes && ! printable) |
| 533 { |
| 534 if (elide_outer_quotes) |
| 535 goto force_outer_quoting_style; |
| 536 STORE ('\\'); |
| 537 STORE ('0' + (c >> 6)); |
| 538 STORE ('0' + ((c >> 3) & 7)); |
| 539 c = '0' + (c & 7); |
| 540 } |
| 541 if (ilim <= i + 1) |
| 542 break; |
| 543 STORE (c); |
| 544 c = arg[++i]; |
| 545 } |
| 546 |
| 547 goto store_c; |
| 548 } |
| 549 } |
| 550 } |
| 551 |
| 552 if (! ((backslash_escapes || elide_outer_quotes) |
| 553 && quote_these_too |
| 554 && quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))) |
| 555 goto store_c; |
| 556 |
| 557 store_escape: |
| 558 if (elide_outer_quotes) |
| 559 goto force_outer_quoting_style; |
| 560 STORE ('\\'); |
| 561 |
| 562 store_c: |
| 563 STORE (c); |
| 564 } |
| 565 |
| 566 if (len == 0 && quoting_style == shell_always_quoting_style |
| 567 && elide_outer_quotes) |
| 568 goto force_outer_quoting_style; |
| 569 |
| 570 if (quote_string && !elide_outer_quotes) |
| 571 for (; *quote_string; quote_string++) |
| 572 STORE (*quote_string); |
| 573 |
| 574 if (len < buffersize) |
| 575 buffer[len] = '\0'; |
| 576 return len; |
| 577 |
| 578 force_outer_quoting_style: |
| 579 /* Don't reuse quote_these_too, since the addition of outer quotes |
| 580 sufficiently quotes the specified characters. */ |
| 581 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 quotearg_buffer (char *buffer, size_t buffersize, |
| 597 char const *arg, size_t argsize, |
| 598 struct quoting_options const *o) |
| 599 { |
| 600 struct quoting_options const *p = o ? o : &default_quoting_options; |
| 601 int e = errno; |
| 602 size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize, |
| 603 p->style, p->flags, p->quote_these_too); |
| 604 errno = e; |
| 605 return r; |
| 606 } |
| 607 |
| 608 /* Equivalent to quotearg_alloc (ARG, ARGSIZE, NULL, O). */ |
| 609 char * |
| 610 quotearg_alloc (char const *arg, size_t argsize, |
| 611 struct quoting_options const *o) |
| 612 { |
| 613 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 quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size, |
| 624 struct quoting_options const *o) |
| 625 { |
| 626 struct quoting_options const *p = o ? o : &default_quoting_options; |
| 627 int e = errno; |
| 628 /* Elide embedded null bytes if we can't return a size. */ |
| 629 int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES); |
| 630 size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style, |
| 631 flags, p->quote_these_too) + 1; |
| 632 char *buf = xcharalloc (bufsize); |
| 633 quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags, |
| 634 p->quote_these_too); |
| 635 errno = e; |
| 636 if (size) |
| 637 *size = bufsize - 1; |
| 638 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 quotearg_free (void) |
| 657 { |
| 658 struct slotvec *sv = slotvec; |
| 659 unsigned int i; |
| 660 for (i = 1; i < nslots; i++) |
| 661 free (sv[i].val); |
| 662 if (sv[0].val != slot0) |
| 663 { |
| 664 free (sv[0].val); |
| 665 slotvec0.size = sizeof slot0; |
| 666 slotvec0.val = slot0; |
| 667 } |
| 668 if (sv != &slotvec0) |
| 669 { |
| 670 free (sv); |
| 671 slotvec = &slotvec0; |
| 672 } |
| 673 nslots = 1; |
| 674 } |
| 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 quotearg_n_options (int n, char const *arg, size_t argsize, |
| 686 struct quoting_options const *options) |
| 687 { |
| 688 int e = errno; |
| 689 |
| 690 unsigned int n0 = n; |
| 691 struct slotvec *sv = slotvec; |
| 692 |
| 693 if (n < 0) |
| 694 abort (); |
| 695 |
| 696 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 size_t n1 = n0 + 1; |
| 704 bool preallocated = (sv == &slotvec0); |
| 705 |
| 706 if (xalloc_oversized (n1, sizeof *sv)) |
| 707 xalloc_die (); |
| 708 |
| 709 slotvec = sv = xrealloc (preallocated ? NULL : sv, n1 * sizeof *sv); |
| 710 if (preallocated) |
| 711 *sv = slotvec0; |
| 712 memset (sv + nslots, 0, (n1 - nslots) * sizeof *sv); |
| 713 nslots = n1; |
| 714 } |
| 715 |
| 716 { |
| 717 size_t size = sv[n].size; |
| 718 char *val = sv[n].val; |
| 719 /* Elide embedded null bytes since we don't return a size. */ |
| 720 int flags = options->flags | QA_ELIDE_NULL_BYTES; |
| 721 size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize, |
| 722 options->style, flags, |
| 723 options->quote_these_too); |
| 724 |
| 725 if (size <= qsize) |
| 726 { |
| 727 sv[n].size = size = qsize + 1; |
| 728 if (val != slot0) |
| 729 free (val); |
| 730 sv[n].val = val = xcharalloc (size); |
| 731 quotearg_buffer_restyled (val, size, arg, argsize, options->style, |
| 732 flags, options->quote_these_too); |
| 733 } |
| 734 |
| 735 errno = e; |
| 736 return val; |
| 737 } |
| 738 } |
| 739 |
| 740 char * |
| 741 quotearg_n (int n, char const *arg) |
| 742 { |
| 743 return quotearg_n_options (n, arg, SIZE_MAX, &default_quoting_options); |
| 744 } |
| 745 |
| 746 char * |
| 747 quotearg_n_mem (int n, char const *arg, size_t argsize) |
| 748 { |
| 749 return quotearg_n_options (n, arg, argsize, &default_quoting_options); |
| 750 } |
| 751 |
| 752 char * |
| 753 quotearg (char const *arg) |
| 754 { |
| 755 return quotearg_n (0, arg); |
| 756 } |
| 757 |
| 758 char * |
| 759 quotearg_mem (char const *arg, size_t argsize) |
| 760 { |
| 761 return quotearg_n_mem (0, arg, argsize); |
| 762 } |
| 763 |
| 764 char * |
| 765 quotearg_n_style (int n, enum quoting_style s, char const *arg) |
| 766 { |
| 767 struct quoting_options const o = quoting_options_from_style (s); |
| 768 return quotearg_n_options (n, arg, SIZE_MAX, &o); |
| 769 } |
| 770 |
| 771 char * |
| 772 quotearg_n_style_mem (int n, enum quoting_style s, |
| 773 char const *arg, size_t argsize) |
| 774 { |
| 775 struct quoting_options const o = quoting_options_from_style (s); |
| 776 return quotearg_n_options (n, arg, argsize, &o); |
| 777 } |
| 778 |
| 779 char * |
| 780 quotearg_style (enum quoting_style s, char const *arg) |
| 781 { |
| 782 return quotearg_n_style (0, s, arg); |
| 783 } |
| 784 |
| 785 char * |
| 786 quotearg_style_mem (enum quoting_style s, char const *arg, size_t argsize) |
| 787 { |
| 788 return quotearg_n_style_mem (0, s, arg, argsize); |
| 789 } |
| 790 |
| 791 char * |
| 792 quotearg_char_mem (char const *arg, size_t argsize, char ch) |
| 793 { |
| 794 struct quoting_options options; |
| 795 options = default_quoting_options; |
| 796 set_char_quoting (&options, ch, 1); |
| 797 return quotearg_n_options (0, arg, argsize, &options); |
| 798 } |
| 799 |
| 800 char * |
| 801 quotearg_char (char const *arg, char ch) |
| 802 { |
| 803 return quotearg_char_mem (arg, SIZE_MAX, ch); |
| 804 } |
| 805 |
| 806 char * |
| 807 quotearg_colon (char const *arg) |
| 808 { |
| 809 return quotearg_char (arg, ':'); |
| 810 } |
| 811 |
| 812 char * |
| 813 quotearg_colon_mem (char const *arg, size_t argsize) |
| 814 { |
| 815 return quotearg_char_mem (arg, argsize, ':'); |
| 816 } |
OLD | NEW |