1/* Test for wchar_t/multi-byte conversion and precision in vfprintf.
2 Copyright (C) 2017-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <locale.h>
20#include <stdbool.h>
21#include <stdint.h>
22#include <stdio.h>
23#include <string.h>
24#include <support/check.h>
25#include <support/test-driver.h>
26#include <wchar.h>
27
28#define DYNARRAY_STRUCT str
29#define DYNARRAY_ELEMENT char
30#define DYNARRAY_PREFIX str_
31#include <malloc/dynarray-skeleton.c>
32
33#define DYNARRAY_STRUCT wstr
34#define DYNARRAY_ELEMENT wchar_t
35#define DYNARRAY_PREFIX wstr_
36#include <malloc/dynarray-skeleton.c>
37
38#define DYNARRAY_STRUCT len
39#define DYNARRAY_ELEMENT size_t
40#define DYNARRAY_PREFIX len_
41#include <malloc/dynarray-skeleton.c>
42
43/* This should be larger than the internal buffer in vfprintf. The
44 constant needs to be kept in sync with the format strings in
45 test_mbs_long and test_wide_long. */
46enum { WIDE_STRING_LENGTH = 1000 };
47
48/* Creates two large, random strings used for truncation testing.
49 After the call, *MBS will be encoded in UTF-8, and *WIDE will
50 contain the same string in the internal UCS-32 encoding. Both
51 strings are null-terminated. The array *LENGTH counts the number
52 of multi-byte characters for each prefix string of *WIDE: The first
53 N wide characters of *WIDE correspond the first (*LENGTH)[N] bytes
54 of *MBS. The caller should deallocate all three arrays using
55 free. */
56static void
57make_random_string (char **mbs, wchar_t **wide, size_t **length)
58{
59 struct str str;
60 str_init (list: &str);
61 struct wstr wstr;
62 wstr_init (list: &wstr);
63 struct len len;
64 len_init (list: &len);
65
66 for (int i = 0; i < WIDE_STRING_LENGTH; ++i)
67 {
68 len_add (list: &len, item: str_size (list: &str));
69 /* Cover some multi-byte UTF-8 sequences. Avoid the null
70 character. */
71 uint32_t ch = 1 + (rand () % 521);
72 wstr_add (list: &wstr, item: ch);
73
74 /* Limited UTF-8 conversion. */
75 if (ch <= 127)
76 str_add (list: &str, item: ch);
77 else
78 {
79 /* We only implement two-byte sequences. */
80 uint32_t first = ch >> 6;
81 TEST_VERIFY (first < 32);
82 str_add (list: &str, item: 0xC0 | first);
83 str_add (list: &str, item: 0x80 | (ch & 0x3f));
84 }
85 }
86 len_add (list: &len, item: str_size (list: &str));
87 wstr_add (list: &wstr, item: L'\0');
88 str_add (list: &str, item: '\0');
89
90 *mbs = str_finalize (list: &str, NULL);
91 TEST_VERIFY_EXIT (*mbs != NULL);
92 *wide = wstr_finalize (list: &wstr, NULL);
93 TEST_VERIFY_EXIT (*wide != NULL);
94 *length = len_finalize (list: &len, NULL);
95 TEST_VERIFY_EXIT (*length != NULL);
96}
97
98/* snprintf tests (multi-byte result). */
99static void
100test_mbs_result (void)
101{
102 char buf[200];
103
104 /* ASCII wide string. */
105 memset (buf, '@', sizeof (buf));
106 TEST_VERIFY (snprintf (buf, sizeof (buf), "%ls", L"xyz") == 3);
107 TEST_VERIFY (strcmp (buf, "xyz") == 0);
108
109 /* Unicode wide string. */
110 memset (buf, '@', sizeof (buf));
111 TEST_VERIFY (snprintf (buf, sizeof (buf), "%ls", L"x\u00DFz") == 4);
112 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
113
114 /* Varying precisions. */
115 memset (buf, '@', sizeof (buf));
116 TEST_VERIFY (snprintf (buf, sizeof (buf), "%.1ls", L"x\u00DFz") == 1);
117 TEST_VERIFY (strcmp (buf, "x") == 0);
118 memset (buf, '@', sizeof (buf));
119 TEST_VERIFY (snprintf (buf, sizeof (buf), "%.2ls", L"x\u00DFz") == 1);
120 TEST_VERIFY (strcmp (buf, "x") == 0);
121 memset (buf, '@', sizeof (buf));
122 TEST_VERIFY (snprintf (buf, sizeof (buf), "%.3ls", L"x\u00DFz") == 3);
123 TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
124 memset (buf, '@', sizeof (buf));
125 TEST_VERIFY (snprintf (buf, sizeof (buf), "%.4ls", L"x\u00DFz") == 4);
126 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
127 memset (buf, '@', sizeof (buf));
128 TEST_VERIFY (snprintf (buf, sizeof (buf), "%.5ls", L"x\u00DFz") == 4);
129 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
130
131 /* Varying precisions with width 2, right-justified. */
132 memset (buf, '@', sizeof (buf));
133 TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.1ls", L"x\u00DFz") == 2);
134 TEST_VERIFY (strcmp (buf, " x") == 0);
135 memset (buf, '@', sizeof (buf));
136 TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.2ls", L"x\u00DFz") == 2);
137 TEST_VERIFY (strcmp (buf, " x") == 0);
138 memset (buf, '@', sizeof (buf));
139 TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.3ls", L"x\u00DFz") == 3);
140 TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
141 memset (buf, '@', sizeof (buf));
142 TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.4ls", L"x\u00DFz") == 4);
143 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
144 memset (buf, '@', sizeof (buf));
145 TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.5ls", L"x\u00DFz") == 4);
146 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
147
148 /* Varying precisions with width 2, left-justified. */
149 memset (buf, '@', sizeof (buf));
150 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.1ls", L"x\u00DFz") == 2);
151 TEST_VERIFY (strcmp (buf, "x ") == 0);
152 memset (buf, '@', sizeof (buf));
153 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.2ls", L"x\u00DFz") == 2);
154 TEST_VERIFY (strcmp (buf, "x ") == 0);
155 memset (buf, '@', sizeof (buf));
156 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.3ls", L"x\u00DFz") == 3);
157 TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
158 memset (buf, '@', sizeof (buf));
159 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.4ls", L"x\u00DFz") == 4);
160 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
161 memset (buf, '@', sizeof (buf));
162 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.5ls", L"x\u00DFz") == 4);
163 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
164
165 /* Varying precisions with width 3, right-justified. */
166 memset (buf, '@', sizeof (buf));
167 TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.1ls", L"x\u00DFz") == 3);
168 TEST_VERIFY (strcmp (buf, " x") == 0);
169 memset (buf, '@', sizeof (buf));
170 TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.2ls", L"x\u00DFz") == 3);
171 TEST_VERIFY (strcmp (buf, " x") == 0);
172 memset (buf, '@', sizeof (buf));
173 TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.3ls", L"x\u00DFz") == 3);
174 TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
175 memset (buf, '@', sizeof (buf));
176 TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.4ls", L"x\u00DFz") == 4);
177 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
178 memset (buf, '@', sizeof (buf));
179 TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.5ls", L"x\u00DFz") == 4);
180 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
181
182 /* Varying precisions with width 3, left-justified. */
183 memset (buf, '@', sizeof (buf));
184 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.1ls", L"x\u00DFz") == 3);
185 TEST_VERIFY (strcmp (buf, "x ") == 0);
186 memset (buf, '@', sizeof (buf));
187 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.2ls", L"x\u00DFz") == 3);
188 TEST_VERIFY (strcmp (buf, "x ") == 0);
189 memset (buf, '@', sizeof (buf));
190 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.3ls", L"x\u00DFz") == 3);
191 TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
192 memset (buf, '@', sizeof (buf));
193 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.4ls", L"x\u00DFz") == 4);
194 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
195 memset (buf, '@', sizeof (buf));
196 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.5ls", L"x\u00DFz") == 4);
197 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
198
199 /* Varying precisions with width 4, right-justified. */
200 memset (buf, '@', sizeof (buf));
201 TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.1ls", L"x\u00DFz") == 4);
202 TEST_VERIFY (strcmp (buf, " x") == 0);
203 memset (buf, '@', sizeof (buf));
204 TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.2ls", L"x\u00DFz") == 4);
205 TEST_VERIFY (strcmp (buf, " x") == 0);
206 memset (buf, '@', sizeof (buf));
207 TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.3ls", L"x\u00DFz") == 4);
208 TEST_VERIFY (strcmp (buf, " x\xC3\x9F") == 0);
209 memset (buf, '@', sizeof (buf));
210 TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.4ls", L"x\u00DFz") == 4);
211 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
212 memset (buf, '@', sizeof (buf));
213 TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.5ls", L"x\u00DFz") == 4);
214 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
215
216 /* Varying precisions with width 4, left-justified. */
217 memset (buf, '@', sizeof (buf));
218 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.1ls", L"x\u00DFz") == 4);
219 TEST_VERIFY (strcmp (buf, "x ") == 0);
220 memset (buf, '@', sizeof (buf));
221 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.2ls", L"x\u00DFz") == 4);
222 TEST_VERIFY (strcmp (buf, "x ") == 0);
223 memset (buf, '@', sizeof (buf));
224 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.3ls", L"x\u00DFz") == 4);
225 TEST_VERIFY (strcmp (buf, "x\xC3\x9F ") == 0);
226 memset (buf, '@', sizeof (buf));
227 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.4ls", L"x\u00DFz") == 4);
228 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
229 memset (buf, '@', sizeof (buf));
230 TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.5ls", L"x\u00DFz") == 4);
231 TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
232}
233
234/* swprintf tests (wide string result). */
235static void
236test_wide_result (void)
237{
238 enum { size = 20 };
239 wchar_t buf[20];
240
241 /* ASCII wide string. */
242 wmemset (buf, '@', size);
243 TEST_VERIFY (swprintf (buf, size, L"%s", "xyz") == 3);
244 TEST_VERIFY (wcscmp (buf, L"xyz") == 0);
245
246 /* Unicode wide string. */
247 wmemset (buf, '@', size);
248 TEST_VERIFY (swprintf (buf, size, L"%s", "x\xC3\x9Fz") == 3);
249 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
250
251 /* Varying precisions. */
252 wmemset (buf, '@', size);
253 TEST_VERIFY (swprintf (buf, size, L"%.1s", "x\xC3\x9Fz") == 1);
254 TEST_VERIFY (wcscmp (buf, L"x") == 0);
255 wmemset (buf, '@', size);
256 TEST_VERIFY (swprintf (buf, size, L"%.2s", "x\xC3\x9Fz") == 2);
257 TEST_VERIFY (wcscmp (buf, L"x\u00DF") == 0);
258 wmemset (buf, '@', size);
259 TEST_VERIFY (swprintf (buf, size, L"%.3s", "x\xC3\x9Fz") == 3);
260 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
261 wmemset (buf, '@', size);
262 TEST_VERIFY (swprintf (buf, size, L"%.4s", "x\xC3\x9Fz") == 3);
263 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
264
265 /* Varying precisions with width 2, right-justified. */
266 wmemset (buf, '@', size);
267 TEST_VERIFY (swprintf (buf, size, L"%2.1s", "x\xC3\x9Fz") == 2);
268 TEST_VERIFY (wcscmp (buf, L" x") == 0);
269 wmemset (buf, '@', size);
270 TEST_VERIFY (swprintf (buf, size, L"%2.2s", "x\xC3\x9Fz") == 2);
271 TEST_VERIFY (wcscmp (buf, L"x\u00DF") == 0);
272 wmemset (buf, '@', size);
273 TEST_VERIFY (swprintf (buf, size, L"%2.3s", "x\xC3\x9Fz") == 3);
274 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
275 wmemset (buf, '@', size);
276 TEST_VERIFY (swprintf (buf, size, L"%2.4s", "x\xC3\x9Fz") == 3);
277 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
278
279 /* Varying precisions with width 2, left-justified. */
280 wmemset (buf, '@', size);
281 TEST_VERIFY (swprintf (buf, size, L"%-2.1s", "x\xC3\x9Fz") == 2);
282 TEST_VERIFY (wcscmp (buf, L"x ") == 0);
283 wmemset (buf, '@', size);
284 TEST_VERIFY (swprintf (buf, size, L"%-2.2s", "x\xC3\x9Fz") == 2);
285 TEST_VERIFY (wcscmp (buf, L"x\u00DF") == 0);
286 wmemset (buf, '@', size);
287 TEST_VERIFY (swprintf (buf, size, L"%-2.3s", "x\xC3\x9Fz") == 3);
288 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
289 wmemset (buf, '@', size);
290 TEST_VERIFY (swprintf (buf, size, L"%-2.4s", "x\xC3\x9Fz") == 3);
291 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
292
293 /* Varying precisions with width 3, right-justified. */
294 wmemset (buf, '@', size);
295 TEST_VERIFY (swprintf (buf, size, L"%3.1s", "x\xC3\x9Fz") == 3);
296 TEST_VERIFY (wcscmp (buf, L" x") == 0);
297 wmemset (buf, '@', size);
298 TEST_VERIFY (swprintf (buf, size, L"%3.2s", "x\xC3\x9Fz") == 3);
299 TEST_VERIFY (wcscmp (buf, L" x\u00DF") == 0);
300 wmemset (buf, '@', size);
301 TEST_VERIFY (swprintf (buf, size, L"%3.3s", "x\xC3\x9Fz") == 3);
302 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
303 wmemset (buf, '@', size);
304 TEST_VERIFY (swprintf (buf, size, L"%3.4s", "x\xC3\x9Fz") == 3);
305 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
306
307 /* Varying precisions with width 3, left-justified. */
308 wmemset (buf, '@', size);
309 TEST_VERIFY (swprintf (buf, size, L"%-3.1s", "x\xC3\x9Fz") == 3);
310 TEST_VERIFY (wcscmp (buf, L"x ") == 0);
311 wmemset (buf, '@', size);
312 TEST_VERIFY (swprintf (buf, size, L"%-3.2s", "x\xC3\x9Fz") == 3);
313 TEST_VERIFY (wcscmp (buf, L"x\u00DF ") == 0);
314 wmemset (buf, '@', size);
315 TEST_VERIFY (swprintf (buf, size, L"%-3.3s", "x\xC3\x9Fz") == 3);
316 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
317 wmemset (buf, '@', size);
318 TEST_VERIFY (swprintf (buf, size, L"%-3.4s", "x\xC3\x9Fz") == 3);
319 TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
320
321 /* Varying precisions with width 4, right-justified. */
322 wmemset (buf, '@', size);
323 TEST_VERIFY (swprintf (buf, size, L"%4.1s", "x\xC3\x9Fz") == 4);
324 TEST_VERIFY (wcscmp (buf, L" x") == 0);
325 wmemset (buf, '@', size);
326 TEST_VERIFY (swprintf (buf, size, L"%4.2s", "x\xC3\x9Fz") == 4);
327 TEST_VERIFY (wcscmp (buf, L" x\u00DF") == 0);
328 wmemset (buf, '@', size);
329 TEST_VERIFY (swprintf (buf, size, L"%4.3s", "x\xC3\x9Fz") == 4);
330 TEST_VERIFY (wcscmp (buf, L" x\u00DFz") == 0);
331 wmemset (buf, '@', size);
332 TEST_VERIFY (swprintf (buf, size, L"%4.4s", "x\xC3\x9Fz") == 4);
333 TEST_VERIFY (wcscmp (buf, L" x\u00DFz") == 0);
334 wmemset (buf, '@', size);
335 TEST_VERIFY (swprintf (buf, size, L"%4.5s", "x\xC3\x9Fz") == 4);
336 TEST_VERIFY (wcscmp (buf, L" x\u00DFz") == 0);
337
338 /* Varying precisions with width 4, left-justified. */
339 wmemset (buf, '@', size);
340 TEST_VERIFY (swprintf (buf, size, L"%-4.1s", "x\xC3\x9Fz") == 4);
341 TEST_VERIFY (wcscmp (buf, L"x ") == 0);
342 wmemset (buf, '@', size);
343 TEST_VERIFY (swprintf (buf, size, L"%-4.2s", "x\xC3\x9Fz") == 4);
344 TEST_VERIFY (wcscmp (buf, L"x\u00DF ") == 0);
345 wmemset (buf, '@', size);
346 TEST_VERIFY (swprintf (buf, size, L"%-4.3s", "x\xC3\x9Fz") == 4);
347 TEST_VERIFY (wcscmp (buf, L"x\u00DFz ") == 0);
348 wmemset (buf, '@', size);
349 TEST_VERIFY (swprintf (buf, size, L"%-4.4s", "x\xC3\x9Fz") == 4);
350 TEST_VERIFY (wcscmp (buf, L"x\u00DFz ") == 0);
351 wmemset (buf, '@', size);
352 TEST_VERIFY (swprintf (buf, size, L"%-4.5s", "x\xC3\x9Fz") == 4);
353 TEST_VERIFY (wcscmp (buf, L"x\u00DFz ") == 0);
354}
355
356/* Test with long strings and multi-byte result. */
357static void
358test_mbs_long (const char *mbs, const wchar_t *wide, const size_t *length)
359{
360 char buf[4000];
361 _Static_assert (sizeof (buf) > 3 * WIDE_STRING_LENGTH,
362 "buffer size consistent with string length");
363 const char *suffix = "||TERM";
364 TEST_VERIFY_EXIT (sizeof (buf)
365 > length[WIDE_STRING_LENGTH] + strlen (suffix));
366
367 /* Test formatting of the entire string. */
368 {
369 int ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%ls%s", wide, suffix);
370 TEST_VERIFY (ret == length[WIDE_STRING_LENGTH] + strlen (suffix));
371 TEST_VERIFY (memcmp (buf, mbs, length[WIDE_STRING_LENGTH]) == 0);
372 TEST_VERIFY (strcmp (buf + length[WIDE_STRING_LENGTH], suffix) == 0);
373
374 /* Left-justified string, printed in full. */
375 ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%-3500ls%s", wide, suffix);
376 TEST_VERIFY (ret == 3500 + strlen (suffix));
377 TEST_VERIFY (memcmp (buf, mbs, length[WIDE_STRING_LENGTH]) == 0);
378 for (size_t i = length[WIDE_STRING_LENGTH]; i < 3500; ++i)
379 TEST_VERIFY (buf[i] == ' ');
380 TEST_VERIFY (strcmp (buf + 3500, suffix) == 0);
381
382 /* Right-justified string, printed in full. */
383 ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%3500ls%s", wide, suffix);
384 TEST_VERIFY (ret == 3500 + strlen (suffix));
385 size_t padding = 3500 - length[WIDE_STRING_LENGTH];
386 for (size_t i = 0; i < padding; ++i)
387 TEST_VERIFY (buf[i] == ' ');
388 TEST_VERIFY (memcmp (buf + padding, mbs, length[WIDE_STRING_LENGTH]) == 0);
389 TEST_VERIFY (strcmp (buf + 3500, suffix) == 0);
390 }
391
392 size_t wide_characters_converted = 0;
393 for (int mbs_len = 0; mbs_len <= length[WIDE_STRING_LENGTH] + 1;
394 ++mbs_len)
395 {
396 if (wide_characters_converted < WIDE_STRING_LENGTH
397 && mbs_len >= length[wide_characters_converted + 1])
398 /* The requested prefix length contains room for another wide
399 character. */
400 ++wide_characters_converted;
401 if (test_verbose > 0)
402 printf (format: "info: %s: mbs_len=%d wide_chars_converted=%zu length=%zu\n",
403 __func__, mbs_len, wide_characters_converted,
404 length[wide_characters_converted]);
405 TEST_VERIFY (length[wide_characters_converted] <= mbs_len);
406 TEST_VERIFY (wide_characters_converted == 0
407 || length[wide_characters_converted - 1] < mbs_len);
408
409 int ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%.*ls%s", mbs_len, wide, suffix);
410 TEST_VERIFY (ret == length[wide_characters_converted] + strlen (suffix));
411 TEST_VERIFY (memcmp (buf, mbs, length[wide_characters_converted]) == 0);
412 TEST_VERIFY (strcmp (buf + length[wide_characters_converted],
413 suffix) == 0);
414
415 /* Left-justified string, printed in full. */
416 if (test_verbose)
417 printf (format: "info: %s: left-justified\n", __func__);
418 ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%-3500.*ls%s",
419 mbs_len, wide, suffix);
420 TEST_VERIFY (ret == 3500 + strlen (suffix));
421 TEST_VERIFY (memcmp (buf, mbs, length[wide_characters_converted]) == 0);
422 for (size_t i = length[wide_characters_converted]; i < 3500; ++i)
423 TEST_VERIFY (buf[i] == ' ');
424 TEST_VERIFY (strcmp (buf + 3500, suffix) == 0);
425
426 /* Right-justified string, printed in full. */
427 if (test_verbose)
428 printf (format: "info: %s: right-justified\n", __func__);
429 ret = snprintf (s: buf, maxlen: sizeof (buf), format: "%3500.*ls%s", mbs_len, wide, suffix);
430 TEST_VERIFY (ret == 3500 + strlen (suffix));
431 size_t padding = 3500 - length[wide_characters_converted];
432 for (size_t i = 0; i < padding; ++i)
433 TEST_VERIFY (buf[i] == ' ');
434 TEST_VERIFY (memcmp (buf + padding, mbs,
435 length[wide_characters_converted]) == 0);
436 TEST_VERIFY (strcmp (buf + 3500, suffix) == 0);
437 }
438}
439
440/* Test with long strings and wide string result. */
441static void
442test_wide_long (const char *mbs, const wchar_t *wide, const size_t *length)
443{
444 wchar_t buf[2000];
445 _Static_assert (sizeof (buf) > sizeof (wchar_t) * WIDE_STRING_LENGTH,
446 "buffer size consistent with string length");
447 const wchar_t *suffix = L"||TERM";
448 TEST_VERIFY_EXIT (sizeof (buf)
449 > length[WIDE_STRING_LENGTH] + wcslen (suffix));
450
451 /* Test formatting of the entire string. */
452 {
453 int ret = swprintf (s: buf, n: sizeof (buf), format: L"%s%ls", mbs, suffix);
454 TEST_VERIFY (ret == WIDE_STRING_LENGTH + wcslen (suffix));
455 TEST_VERIFY (wmemcmp (buf, wide, WIDE_STRING_LENGTH) == 0);
456 TEST_VERIFY (wcscmp (buf + WIDE_STRING_LENGTH, suffix) == 0);
457
458 /* Left-justified string, printed in full. */
459 ret = swprintf (s: buf, n: sizeof (buf), format: L"%-1500s%ls", mbs, suffix);
460 TEST_VERIFY (ret == 1500 + wcslen (suffix));
461 TEST_VERIFY (wmemcmp (buf, wide, WIDE_STRING_LENGTH) == 0);
462 for (size_t i = WIDE_STRING_LENGTH; i < 1500; ++i)
463 TEST_VERIFY (buf[i] == L' ');
464 TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0);
465
466 /* Right-justified string, printed in full. */
467 ret = swprintf (s: buf, n: sizeof (buf), format: L"%1500s%ls", mbs, suffix);
468 TEST_VERIFY (ret == 1500 + wcslen (suffix));
469 size_t padding = 1500 - WIDE_STRING_LENGTH;
470 for (size_t i = 0; i < padding; ++i)
471 TEST_VERIFY (buf[i] == ' ');
472 TEST_VERIFY (wmemcmp (buf + padding, wide, WIDE_STRING_LENGTH) == 0);
473 TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0);
474 }
475
476 for (int wide_len = 0; wide_len <= WIDE_STRING_LENGTH + 1; ++wide_len)
477 {
478 size_t actual_wide_len;
479 if (wide_len < WIDE_STRING_LENGTH)
480 actual_wide_len = wide_len;
481 else
482 actual_wide_len = WIDE_STRING_LENGTH;
483 if (test_verbose > 0)
484 printf (format: "info: %s: wide_len=%d actual_wide_len=%zu\n",
485 __func__, wide_len, actual_wide_len);
486
487 int ret = swprintf (s: buf, n: sizeof (buf), format: L"%.*s%ls",
488 wide_len, mbs, suffix);
489 TEST_VERIFY (ret == actual_wide_len + wcslen (suffix));
490 TEST_VERIFY (wmemcmp (buf, wide, actual_wide_len) == 0);
491 TEST_VERIFY (wcscmp (buf + actual_wide_len, suffix) == 0);
492
493 /* Left-justified string, printed in full. */
494 ret = swprintf (s: buf, n: sizeof (buf), format: L"%-1500.*s%ls",
495 wide_len, mbs, suffix);
496 TEST_VERIFY (ret == 1500 + wcslen (suffix));
497 TEST_VERIFY (wmemcmp (buf, wide, actual_wide_len) == 0);
498 for (size_t i = actual_wide_len; i < 1500; ++i)
499 TEST_VERIFY (buf[i] == L' ');
500 TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0);
501
502 /* Right-justified string, printed in full. */
503 ret = swprintf (s: buf, n: sizeof (buf), format: L"%1500.*s%ls",
504 wide_len, mbs, suffix);
505 TEST_VERIFY (ret == 1500 + wcslen (suffix));
506 size_t padding = 1500 - actual_wide_len;
507 for (size_t i = 0; i < padding; ++i)
508 TEST_VERIFY (buf[i] == L' ');
509 TEST_VERIFY (wmemcmp (buf + padding, wide, actual_wide_len) == 0);
510 TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0);
511 }
512}
513
514static int
515do_test (void)
516{
517 /* This test only covers UTF-8 as a multi-byte character set. A
518 locale with a multi-byte character set with shift state would be
519 a relevant test target as well, but glibc currently does not ship
520 such a locale. */
521 TEST_VERIFY (setlocale (LC_CTYPE, "de_DE.UTF-8") != NULL);
522
523 test_mbs_result ();
524 test_wide_result ();
525
526 char *mbs;
527 wchar_t *wide;
528 size_t *length;
529 make_random_string (mbs: &mbs, wide: &wide, length: &length);
530 TEST_VERIFY (strlen (mbs) == length[WIDE_STRING_LENGTH]);
531 if (test_verbose > 0)
532 printf (format: "info: long multi-byte string contains %zu characters\n",
533 length[WIDE_STRING_LENGTH]);
534 test_mbs_long (mbs, wide, length);
535 test_wide_long (mbs, wide, length);
536 free (ptr: mbs);
537 free (ptr: wide);
538 free (ptr: length);
539
540 return 0;
541}
542
543#include <support/test-driver.c>
544

source code of glibc/stdio-common/tst-vfprintf-mbs-prec.c