1 /* Test of quotearg family of functions.
2 Copyright (C) 2008-2013 Free Software Foundation, Inc.
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)
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.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>. */
17 /* Written by Eric Blake <ebb9@byu.net>, 2008. */
29 #include "localcharset.h"
32 #include "zerosize-ptr.h"
34 #include "test-quotearg.h"
36 static struct result_groups results_g[] = {
37 /* literal_quoting_style */
38 { { "", "\0""1\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
40 { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
42 { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
45 /* shell_quoting_style */
46 { { "''", "\0""1\0", 3, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b",
47 "'a\\b'", LQ RQ, LQ RQ },
48 { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b",
49 "'a\\b'", LQ RQ, LQ RQ },
50 { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
51 "'a\\b'", LQ RQ, LQ RQ } },
53 /* shell_always_quoting_style */
54 { { "''", "'\0""1\0'", 5, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
55 "'a\\b'", "'" LQ RQ "'", "'" LQ RQ "'" },
56 { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
57 "'a\\b'", "'" LQ RQ "'", "'" LQ RQ "'" },
58 { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
59 "'a\\b'", "'" LQ RQ "'", "'" LQ RQ "'" } },
62 { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
63 "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
64 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
65 { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
66 "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
67 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
68 { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
69 "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
70 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } },
72 /* c_maybe_quoting_style */
73 { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
74 "a:b", "a\\b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
75 { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
76 "a:b", "a\\b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
77 { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
78 "\"a:b\"", "a\\b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ } },
80 /* escape_quoting_style */
81 { { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b",
82 "a\\\\b", LQ_ENC RQ_ENC, LQ RQ },
83 { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b",
84 "a\\\\b", LQ_ENC RQ_ENC, LQ RQ },
85 { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a\\:b",
86 "a\\\\b", LQ_ENC RQ_ENC, LQ RQ } },
88 /* locale_quoting_style */
89 { { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
90 "'a:b'", "'a\\\\b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
91 { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
92 "'a:b'", "'a\\\\b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
93 { "''", "'\\0001\\0'", 9, "'simple'", "' \\t\\n\\'\"\\033?""?/\\\\'",
94 "'a\\:b'", "'a\\\\b'", "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" } },
96 /* clocale_quoting_style */
97 { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
98 "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
99 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
100 { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
101 "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
102 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
103 { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
104 "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
105 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } }
108 static struct result_groups flag_results[] = {
109 /* literal_quoting_style and QA_ELIDE_NULL_BYTES */
110 { { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", LQ RQ,
112 { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", LQ RQ,
114 { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", LQ RQ,
117 /* c_quoting_style and QA_ELIDE_OUTER_QUOTES */
118 { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
119 "a:b", "a\\b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
120 { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
121 "a:b", "a\\b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ },
122 { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
123 "\"a:b\"", "a\\b", "\"" LQ_ENC RQ_ENC "\"", LQ RQ } },
125 /* c_quoting_style and QA_SPLIT_TRIGRAPHS */
126 { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
127 "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
128 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
129 { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
130 "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
131 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" },
132 { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
133 "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
134 "\"" LQ_ENC RQ_ENC "\"", "\"" LQ RQ "\"" } }
137 static char const *custom_quotes[][2] = {
147 static struct result_groups custom_results[] = {
148 /* left_quote = right_quote = "" */
149 { { "", "\\0001\\0", 7, "simple",
150 " \\t\\n'\"\\033?""?/\\\\", "a:b", "a\\\\b",
151 LQ_ENC RQ_ENC, LQ RQ },
152 { "", "\\0001\\0", 7, "simple",
153 " \\t\\n'\"\\033?""?/\\\\", "a:b", "a\\\\b",
154 LQ_ENC RQ_ENC, LQ RQ },
155 { "", "\\0001\\0", 7, "simple",
156 " \\t\\n'\"\\033?""?/\\\\", "a\\:b", "a\\\\b",
157 LQ_ENC RQ_ENC, LQ RQ } },
159 /* left_quote = right_quote = "'" */
160 { { "''", "'\\0001\\0'", 9, "'simple'",
161 "' \\t\\n\\'\"\\033?""?/\\\\'", "'a:b'", "'a\\\\b'",
162 "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
163 { "''", "'\\0001\\0'", 9, "'simple'",
164 "' \\t\\n\\'\"\\033?""?/\\\\'", "'a:b'", "'a\\\\b'",
165 "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" },
166 { "''", "'\\0001\\0'", 9, "'simple'",
167 "' \\t\\n\\'\"\\033?""?/\\\\'", "'a\\:b'", "'a\\\\b'",
168 "'" LQ_ENC RQ_ENC "'", "'" LQ RQ "'" } },
170 /* left_quote = "(" and right_quote = ")" */
171 { { "()", "(\\0001\\0)", 9, "(simple)",
172 "( \\t\\n'\"\\033?""?/\\\\)", "(a:b)", "(a\\\\b)",
173 "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" },
174 { "()", "(\\0001\\0)", 9, "(simple)",
175 "( \\t\\n'\"\\033?""?/\\\\)", "(a:b)", "(a\\\\b)",
176 "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" },
177 { "()", "(\\0001\\0)", 9, "(simple)",
178 "( \\t\\n'\"\\033?""?/\\\\)", "(a\\:b)", "(a\\\\b)",
179 "(" LQ_ENC RQ_ENC ")", "(" LQ RQ ")" } },
181 /* left_quote = ":" and right_quote = " " */
182 { { ": ", ":\\0001\\0 ", 9, ":simple ",
183 ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a:b ", ":a\\\\b ",
184 ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " },
185 { ": ", ":\\0001\\0 ", 9, ":simple ",
186 ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a:b ", ":a\\\\b ",
187 ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " },
188 { ": ", ":\\0001\\0 ", 9, ":simple ",
189 ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a\\:b ", ":a\\\\b ",
190 ":" LQ_ENC RQ_ENC " ", ":" LQ RQ " " } },
192 /* left_quote = " " and right_quote = ":" */
193 { { " :", " \\0001\\0:", 9, " simple:",
194 " \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
195 " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" },
196 { " :", " \\0001\\0:", 9, " simple:",
197 " \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
198 " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" },
199 { " :", " \\0001\\0:", 9, " simple:",
200 " \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
201 " " LQ_ENC RQ_ENC ":", " " LQ RQ ":" } },
203 /* left_quote = "# " and right_quote = "\n" */
204 { { "# \n", "# \\0001\\0\n", 10, "# simple\n",
205 "# \\t\\n'\"\\033?""?/\\\\\n", "# a:b\n", "# a\\\\b\n",
206 "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" },
207 { "# \n", "# \\0001\\0\n", 10, "# simple\n",
208 "# \\t\\n'\"\\033?""?/\\\\\n", "# a:b\n", "# a\\\\b\n",
209 "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" },
210 { "# \n", "# \\0001\\0\n", 10, "# simple\n",
211 "# \\t\\n'\"\\033?""?/\\\\\n", "# a\\:b\n", "# a\\\\b\n",
212 "# " LQ_ENC RQ_ENC "\n", "# " LQ RQ "\n" } },
214 /* left_quote = "\"'" and right_quote = "'\"" */
215 { { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
216 "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a:b'\"", "\"'a\\\\b'\"",
217 "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" },
218 { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
219 "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a:b'\"", "\"'a\\\\b'\"",
220 "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" },
221 { "\"''\"", "\"'\\0001\\0'\"", 11, "\"'simple'\"",
222 "\"' \\t\\n\\'\"\\033?""?/\\\\'\"", "\"'a\\:b'\"", "\"'a\\\\b'\"",
223 "\"'" LQ_ENC RQ_ENC "'\"", "\"'" LQ RQ "'\"" } }
227 main (int argc _GL_UNUSED, char *argv[])
230 bool ascii_only = MB_CUR_MAX == 1 && !isprint ((unsigned char) LQ[0]);
232 set_program_name (argv[0]);
234 /* This part of the program is hard-wired to the C locale since it
235 does not call setlocale. However, according to POSIX, the use of
236 8-bit bytes in a character context in the C locale gives
237 unspecified results (that is, the C locale charset is allowed to
238 be unibyte with 8-bit bytes rejected [ASCII], unibyte with 8-bit
239 bytes being characters [often ISO-8859-1], or multibyte [often
240 UTF-8]). We assume that the latter two cases will be
241 indistinguishable in this test - that is, the LQ and RQ sequences
242 will pass through unchanged in either type of charset. So when
243 testing for quoting of str7, use the ascii_only flag to decide
244 what to expect for the 8-bit data being quoted. */
245 ASSERT (!isprint ('\033'));
246 for (i = literal_quoting_style; i <= clocale_quoting_style; i++)
248 set_quoting_style (NULL, (enum quoting_style) i);
249 if (!(i == locale_quoting_style || i == clocale_quoting_style)
250 || (strcmp (locale_charset (), "ASCII") == 0
251 || strcmp (locale_charset (), "ANSI_X3.4-1968") == 0))
253 compare_strings (use_quotearg_buffer, &results_g[i].group1,
255 compare_strings (use_quotearg, &results_g[i].group2,
257 if (i == c_quoting_style)
258 compare_strings (use_quote_double_quotes, &results_g[i].group2,
260 compare_strings (use_quotearg_colon, &results_g[i].group3,
265 set_quoting_style (NULL, literal_quoting_style);
266 ASSERT (set_quoting_flags (NULL, QA_ELIDE_NULL_BYTES) == 0);
267 compare_strings (use_quotearg_buffer, &flag_results[0].group1, ascii_only);
268 compare_strings (use_quotearg, &flag_results[0].group2, ascii_only);
269 compare_strings (use_quotearg_colon, &flag_results[0].group3, ascii_only);
271 set_quoting_style (NULL, c_quoting_style);
272 ASSERT (set_quoting_flags (NULL, QA_ELIDE_OUTER_QUOTES)
273 == QA_ELIDE_NULL_BYTES);
274 compare_strings (use_quotearg_buffer, &flag_results[1].group1, ascii_only);
275 compare_strings (use_quotearg, &flag_results[1].group2, ascii_only);
276 compare_strings (use_quote_double_quotes, &flag_results[1].group2,
278 compare_strings (use_quotearg_colon, &flag_results[1].group3, ascii_only);
280 ASSERT (set_quoting_flags (NULL, QA_SPLIT_TRIGRAPHS)
281 == QA_ELIDE_OUTER_QUOTES);
282 compare_strings (use_quotearg_buffer, &flag_results[2].group1, ascii_only);
283 compare_strings (use_quotearg, &flag_results[2].group2, ascii_only);
284 compare_strings (use_quote_double_quotes, &flag_results[2].group2,
286 compare_strings (use_quotearg_colon, &flag_results[2].group3, ascii_only);
288 ASSERT (set_quoting_flags (NULL, 0) == QA_SPLIT_TRIGRAPHS);
290 for (i = 0; i < sizeof custom_quotes / sizeof *custom_quotes; ++i)
292 set_custom_quoting (NULL,
293 custom_quotes[i][0], custom_quotes[i][1]);
294 compare_strings (use_quotearg_buffer, &custom_results[i].group1,
296 compare_strings (use_quotearg, &custom_results[i].group2, ascii_only);
297 compare_strings (use_quotearg_colon, &custom_results[i].group3,
302 /* Trigger the bug whereby quotearg_buffer would read beyond the NUL
303 that defines the end of the string being quoted. Use an input
304 string whose NUL is the last byte before an unreadable page. */
305 char *z = zerosize_ptr ();
310 char *q = malloc (q_len + 1);
312 memset (q, 'Q', q_len);
315 /* Z points to the boundary between a readable/writable page
316 and one that is neither readable nor writable. Position
317 our string so its NUL is at the end of the writable one. */
318 char const *str = "____";
319 size_t s_len = strlen (str);
321 memcpy (z, str, s_len + 1);
323 set_custom_quoting (NULL, q, q);
324 /* Whether this actually triggers a SEGV depends on the
325 implementation of memcmp: whether it compares only byte-at-
326 a-time, and from left to right (no SEGV) or some other way. */
327 size_t n = quotearg_buffer (buf, sizeof buf, z, SIZE_MAX, NULL);
328 ASSERT (n == s_len + 2 * q_len);
329 ASSERT (memcmp (buf, q, sizeof buf) == 0);