(root)/
m4-1.4.19/
tests/
test-quotearg-simple.c
       1  /* Test of quotearg family of functions.
       2     Copyright (C) 2008-2021 Free Software Foundation, Inc.
       3  
       4     This program is free software; you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation; either version 3, or (at your option)
       7     any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Eric Blake <ebb9@byu.net>, 2008.  */
      18  
      19  #include <config.h>
      20  
      21  #include "quotearg.h"
      22  
      23  #include <ctype.h>
      24  #include <stdbool.h>
      25  #include <stdint.h>
      26  #include <stdlib.h>
      27  #include <string.h>
      28  
      29  #include "localcharset.h"
      30  #include "macros.h"
      31  #include "zerosize-ptr.h"
      32  
      33  #include "test-quotearg.h"
      34  
      35  static struct result_groups results_g[] = {
      36    /* literal_quoting_style */
      37    { { "", "\0""1\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
      38        "a' b", LQ RQ, LQ RQ },
      39      { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
      40        "a' b", LQ RQ, LQ RQ },
      41      { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
      42        "a' b", LQ RQ, LQ RQ } },
      43  
      44    /* shell_quoting_style */
      45    { { "''", "\0""1\0", 3, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b",
      46        "'a\\b'", "\"a' b\"", LQ RQ, LQ RQ },
      47      { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b",
      48        "'a\\b'", "\"a' b\"", LQ RQ, LQ RQ },
      49      { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
      50        "'a\\b'", "\"a' b\"", LQ RQ, LQ RQ } },
      51  
      52    /* shell_always_quoting_style */
      53    { { "''", "'\0""1\0'", 5, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
      54        "'a\\b'", "\"a' b\"", "'" LQ RQ "'", "'" LQ RQ "'" },
      55      { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
      56        "'a\\b'", "\"a' b\"", "'" LQ RQ "'", "'" LQ RQ "'" },
      57      { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
      58        "'a\\b'", "\"a' b\"", "'" LQ RQ "'", "'" LQ RQ "'" } },
      59  
      60    /* shell_escape_quoting_style */
      61    { { "''", "''$'\\0''1'$'\\0'", 15, "simple",
      62        "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "a:b",
      63        "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", LQ RQ },
      64      { "''", "''$'\\0''1'$'\\0'", 15, "simple",
      65        "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "a:b",
      66        "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", LQ RQ },
      67      { "''", "''$'\\0''1'$'\\0'", 15, "simple",
      68        "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "'a:b'",
      69        "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", LQ RQ } },
      70  
      71    /* shell_escape_always_quoting_style */
      72    { { "''", "''$'\\0''1'$'\\0'", 15, "'simple'",
      73        "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "'a:b'",
      74        "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
      75      { "''", "''$'\\0''1'$'\\0'", 15, "'simple'",
      76        "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "'a:b'",
      77        "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
      78      { "''", "''$'\\0''1'$'\\0'", 15, "'simple'",
      79        "' '$'\\t\\n'\\''\"'$'\\033''?""?/\\'", "'a:b'",
      80        "'a\\b'", "\"a' b\"", "''$'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" } },
      81  
      82    /* c_quoting_style */
      83    { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
      84        "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
      85        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
      86      { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
      87        "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
      88        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
      89      { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
      90        "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
      91        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } },
      92  
      93    /* c_maybe_quoting_style */
      94    { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
      95        "a:b", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
      96      { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
      97        "a:b", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
      98      { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
      99        "\"a:b\"", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ } },
     100  
     101    /* escape_quoting_style */
     102    { { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b",
     103        "a\\\\b", "a' b", LQ_ENC RQ_ENC, LQ RQ },
     104      { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b",
     105        "a\\\\b", "a' b", LQ_ENC RQ_ENC, LQ RQ },
     106      { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a\\:b",
     107        "a\\\\b", "a' b", LQ_ENC RQ_ENC, LQ RQ } },
     108  
     109    /* locale_quoting_style */
     110    { { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
     111        "'a:b'", "'a\\\\b'", "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
     112      { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
     113        "'a:b'", "'a\\\\b'", "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
     114      { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
     115        "'a\\:b'", "'a\\\\b'", "'a\\' b'",
     116        "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" } },
     117  
     118    /* clocale_quoting_style */
     119    { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
     120        "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
     121        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
     122      { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
     123        "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
     124        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
     125      { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
     126        "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
     127        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } }
     128  };
     129  
     130  static struct result_groups flag_results[] = {
     131    /* literal_quoting_style and QA_ELIDE_NULL_BYTES */
     132    { { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", "a' b",
     133        LQ RQ, LQ RQ },
     134      { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", "a' b",
     135        LQ RQ, LQ RQ },
     136      { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", "a' b",
     137        LQ RQ, LQ RQ } },
     138  
     139    /* c_quoting_style and QA_ELIDE_OUTER_QUOTES */
     140    { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
     141        "a:b", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
     142      { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
     143        "a:b", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
     144      { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
     145        "\"a:b\"", "a\\b", "a' b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ } },
     146  
     147    /* c_quoting_style and QA_SPLIT_TRIGRAPHS */
     148    { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
     149        "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
     150        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
     151      { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
     152        "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
     153        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
     154      { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
     155        "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
     156        "\"a' b\"", "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } }
     157  };
     158  
     159  static char const *custom_quotes[][2] = {
     160    { "", ""  },
     161    { "'", "'"  },
     162    { "(", ")"  },
     163    { ":", " "  },
     164    { " ", ":"  },
     165    { "# ", "\n" },
     166    { "\"'", "'\"" }
     167  };
     168  
     169  static struct result_groups custom_results[] = {
     170    /* left_quote = right_quote = "" */
     171    { { "", "\\0001\\0", 7, "simple",
     172        " \\t\\n'\"\\033?""?/\\\\", "a:b", "a\\\\b",
     173        "a' b", LQ_ENC RQ_ENC, LQ RQ },
     174      { "", "\\0001\\0", 7, "simple",
     175        " \\t\\n'\"\\033?""?/\\\\", "a:b", "a\\\\b",
     176        "a' b", LQ_ENC RQ_ENC, LQ RQ },
     177      { "", "\\0001\\0", 7, "simple",
     178        " \\t\\n'\"\\033?""?/\\\\", "a\\:b", "a\\\\b",
     179        "a' b", LQ_ENC RQ_ENC, LQ RQ } },
     180  
     181    /* left_quote = right_quote = "'" */
     182    { { "''", "'\\0001\\0'", 9, "'simple'",
     183        "' \\t\\n\\'\"\\033?""?/\\\\'", "'a:b'", "'a\\\\b'",
     184        "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
     185      { "''", "'\\0001\\0'", 9, "'simple'",
     186        "' \\t\\n\\'\"\\033?""?/\\\\'", "'a:b'", "'a\\\\b'",
     187        "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
     188      { "''", "'\\0001\\0'", 9, "'simple'",
     189        "' \\t\\n\\'\"\\033?""?/\\\\'", "'a\\:b'", "'a\\\\b'",
     190        "'a\\' b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" } },
     191  
     192    /* left_quote = "(" and right_quote = ")" */
     193    { { "()", "(\\0001\\0)", 9, "(simple)",
     194        "( \\t\\n'\"\\033?""?/\\\\)", "(a:b)", "(a\\\\b)",
     195        "(a' b)", "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" },
     196      { "()", "(\\0001\\0)", 9, "(simple)",
     197        "( \\t\\n'\"\\033?""?/\\\\)", "(a:b)", "(a\\\\b)",
     198        "(a' b)", "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" },
     199      { "()", "(\\0001\\0)", 9, "(simple)",
     200        "( \\t\\n'\"\\033?""?/\\\\)", "(a\\:b)", "(a\\\\b)",
     201        "(a' b)", "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" } },
     202  
     203    /* left_quote = ":" and right_quote = " " */
     204    { { ": ", ":\\0001\\0 ", 9, ":simple ",
     205        ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a:b ", ":a\\\\b ",
     206        ":a'\\ b ", ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " },
     207      { ": ", ":\\0001\\0 ", 9, ":simple ",
     208        ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a:b ", ":a\\\\b ",
     209        ":a'\\ b ", ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " },
     210      { ": ", ":\\0001\\0 ", 9, ":simple ",
     211        ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a\\:b ", ":a\\\\b ",
     212        ":a'\\ b ", ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " } },
     213  
     214    /* left_quote = " " and right_quote = ":" */
     215    { { " :", " \\0001\\0:", 9, " simple:",
     216        "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
     217        " a' b:", " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" },
     218      { " :", " \\0001\\0:", 9, " simple:",
     219        "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
     220        " a' b:", " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" },
     221      { " :", " \\0001\\0:", 9, " simple:",
     222        "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
     223        " a' b:", " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" } },
     224  
     225    /* left_quote = "# " and right_quote = "\n" */
     226    { { "# \n", "# \\0001\\0\n", 10, "# simple\n",
     227        "#  \\t\\n'\"\\033?""?/\\\\\n", "# a:b\n", "# a\\\\b\n",
     228        "# a' b\n", "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" },
     229      { "# \n", "# \\0001\\0\n", 10, "# simple\n",
     230        "#  \\t\\n'\"\\033?""?/\\\\\n", "# a:b\n", "# a\\\\b\n",
     231        "# a' b\n", "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" },
     232      { "# \n", "# \\0001\\0\n", 10, "# simple\n",
     233        "#  \\t\\n'\"\\033?""?/\\\\\n", "# a\\:b\n", "# a\\\\b\n",
     234        "# a' b\n", "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" } },
     235  
     236    /* left_quote = "\"'" and right_quote = "'\"" */
     237    { { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
     238        "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a:b'\"", "\"'a\\\\b'\"",
     239        "\"'a' b'\"", "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" },
     240      { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
     241        "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a:b'\"", "\"'a\\\\b'\"",
     242        "\"'a' b'\"", "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" },
     243      { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
     244        "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a\\:b'\"", "\"'a\\\\b'\"",
     245        "\"'a' b'\"", "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" } }
     246  };
     247  
     248  static char *
     249  use_quote_double_quotes (const char *str, size_t *len)
     250  {
     251    char *p = *len == SIZE_MAX ? quotearg_char (str, '"')
     252                                 : quotearg_char_mem (str, *len, '"');
     253    *len = strlen (p);
     254    return p;
     255  }
     256  
     257  int
     258  main (int argc _GL_UNUSED, char *argv[])
     259  {
     260    int i;
     261    bool ascii_only = MB_CUR_MAX == 1 && !isprint ((unsigned char) LQ[0]);
     262  
     263    /* This part of the program is hard-wired to the C locale since it
     264       does not call setlocale.  However, according to POSIX, the use of
     265       8-bit bytes in a character context in the C locale gives
     266       unspecified results (that is, the C locale charset is allowed to
     267       be unibyte with 8-bit bytes rejected [ASCII], unibyte with 8-bit
     268       bytes being characters [often ISO-8859-1], or multibyte [often
     269       UTF-8]).  We assume that the latter two cases will be
     270       indistinguishable in this test - that is, the LQ and RQ sequences
     271       will pass through unchanged in either type of charset.  So when
     272       testing for quoting of str7, use the ascii_only flag to decide
     273       what to expect for the 8-bit data being quoted.  */
     274    ASSERT (!isprint ('\033'));
     275    for (i = literal_quoting_style; i <= clocale_quoting_style; i++)
     276      {
     277        set_quoting_style (NULL, (enum quoting_style) i);
     278        if (!(i == locale_quoting_style || i == clocale_quoting_style)
     279            || (strcmp (locale_charset (), "ASCII") == 0
     280                || strcmp (locale_charset (), "ANSI_X3.4-1968") == 0))
     281          {
     282            compare_strings (use_quotearg_buffer, &results_g[i].group1,
     283                             ascii_only);
     284            compare_strings (use_quotearg, &results_g[i].group2,
     285                             ascii_only);
     286            if (i == c_quoting_style)
     287              compare_strings (use_quote_double_quotes, &results_g[i].group2,
     288                               ascii_only);
     289            compare_strings (use_quotearg_colon, &results_g[i].group3,
     290                             ascii_only);
     291          }
     292      }
     293  
     294    set_quoting_style (NULL, literal_quoting_style);
     295    ASSERT (set_quoting_flags (NULL, QA_ELIDE_NULL_BYTES) == 0);
     296    compare_strings (use_quotearg_buffer, &flag_results[0].group1, ascii_only);
     297    compare_strings (use_quotearg, &flag_results[0].group2, ascii_only);
     298    compare_strings (use_quotearg_colon, &flag_results[0].group3, ascii_only);
     299  
     300    set_quoting_style (NULL, c_quoting_style);
     301    ASSERT (set_quoting_flags (NULL, QA_ELIDE_OUTER_QUOTES)
     302            == QA_ELIDE_NULL_BYTES);
     303    compare_strings (use_quotearg_buffer, &flag_results[1].group1, ascii_only);
     304    compare_strings (use_quotearg, &flag_results[1].group2, ascii_only);
     305    compare_strings (use_quote_double_quotes, &flag_results[1].group2,
     306                     ascii_only);
     307    compare_strings (use_quotearg_colon, &flag_results[1].group3, ascii_only);
     308  
     309    ASSERT (set_quoting_flags (NULL, QA_SPLIT_TRIGRAPHS)
     310            == QA_ELIDE_OUTER_QUOTES);
     311    compare_strings (use_quotearg_buffer, &flag_results[2].group1, ascii_only);
     312    compare_strings (use_quotearg, &flag_results[2].group2, ascii_only);
     313    compare_strings (use_quote_double_quotes, &flag_results[2].group2,
     314                     ascii_only);
     315    compare_strings (use_quotearg_colon, &flag_results[2].group3, ascii_only);
     316  
     317    ASSERT (set_quoting_flags (NULL, 0) == QA_SPLIT_TRIGRAPHS);
     318  
     319    for (i = 0; i < sizeof custom_quotes / sizeof *custom_quotes; ++i)
     320      {
     321        set_custom_quoting (NULL,
     322                            custom_quotes[i][0], custom_quotes[i][1]);
     323        compare_strings (use_quotearg_buffer, &custom_results[i].group1,
     324                         ascii_only);
     325        compare_strings (use_quotearg, &custom_results[i].group2, ascii_only);
     326        compare_strings (use_quotearg_colon, &custom_results[i].group3,
     327                         ascii_only);
     328      }
     329  
     330    {
     331      /* Trigger the bug whereby quotearg_buffer would read beyond the NUL
     332         that defines the end of the string being quoted.  Use an input
     333         string whose NUL is the last byte before an unreadable page.  */
     334      char *z = zerosize_ptr ();
     335  
     336      if (z)
     337        {
     338          size_t q_len = 1024;
     339          char *q = malloc (q_len + 1);
     340          char buf[10];
     341          memset (q, 'Q', q_len);
     342          q[q_len] = 0;
     343  
     344          /* Z points to the boundary between a readable/writable page
     345             and one that is neither readable nor writable.  Position
     346             our string so its NUL is at the end of the writable one.  */
     347          char const *str = "____";
     348          size_t s_len = strlen (str);
     349          z -= s_len + 1;
     350          memcpy (z, str, s_len + 1);
     351  
     352          set_custom_quoting (NULL, q, q);
     353          /* Whether this actually triggers a SEGV depends on the
     354             implementation of memcmp: whether it compares only byte-at-
     355             a-time, and from left to right (no SEGV) or some other way.  */
     356          size_t n = quotearg_buffer (buf, sizeof buf, z, SIZE_MAX, NULL);
     357          ASSERT (n == s_len + 2 * q_len);
     358          ASSERT (memcmp (buf, q, sizeof buf) == 0);
     359          free (q);
     360        }
     361    }
     362  
     363    quotearg_free ();
     364  
     365    return 0;
     366  }