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