1 /* Test for wchar_t/multi-byte conversion and precision in vfprintf.
2    Copyright (C) 2017-2021 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.  */
46 enum { 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.  */
56 static void
make_random_string(char ** mbs,wchar_t ** wide,size_t ** length)57 make_random_string (char **mbs, wchar_t **wide, size_t **length)
58 {
59   struct str str;
60   str_init (&str);
61   struct wstr wstr;
62   wstr_init (&wstr);
63   struct len len;
64   len_init (&len);
65 
66   for (int i = 0; i < WIDE_STRING_LENGTH; ++i)
67     {
68       len_add (&len, str_size (&str));
69       /* Cover some multi-byte UTF-8 sequences.  Avoid the null
70          character.  */
71       uint32_t ch = 1 + (rand () % 521);
72       wstr_add (&wstr, ch);
73 
74       /* Limited UTF-8 conversion.  */
75       if (ch <= 127)
76         str_add (&str, 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 (&str, 0xC0 | first);
83           str_add (&str, 0x80 | (ch & 0x3f));
84         }
85     }
86   len_add (&len, str_size (&str));
87   wstr_add (&wstr, L'\0');
88   str_add (&str, '\0');
89 
90   *mbs = str_finalize (&str, NULL);
91   TEST_VERIFY_EXIT (*mbs != NULL);
92   *wide = wstr_finalize (&wstr, NULL);
93   TEST_VERIFY_EXIT (*wide != NULL);
94   *length = len_finalize (&len, NULL);
95   TEST_VERIFY_EXIT (*length != NULL);
96 }
97 
98 /* snprintf tests (multi-byte result).  */
99 static void
test_mbs_result(void)100 test_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).  */
235 static void
test_wide_result(void)236 test_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.  */
357 static void
test_mbs_long(const char * mbs,const wchar_t * wide,const size_t * length)358 test_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 (buf, sizeof (buf), "%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 (buf, sizeof (buf), "%-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 (buf, sizeof (buf), "%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 ("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 (buf, sizeof (buf), "%.*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 ("info: %s: left-justified\n", __func__);
418       ret = snprintf (buf, sizeof (buf), "%-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 ("info: %s: right-justified\n", __func__);
429       ret = snprintf (buf, sizeof (buf), "%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.  */
441 static void
test_wide_long(const char * mbs,const wchar_t * wide,const size_t * length)442 test_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 (buf, sizeof (buf), 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 (buf, sizeof (buf), 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 (buf, sizeof (buf), 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 ("info: %s: wide_len=%d actual_wide_len=%zu\n",
485                 __func__, wide_len, actual_wide_len);
486 
487       int ret = swprintf (buf, sizeof (buf), 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 (buf, sizeof (buf), 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 (buf, sizeof (buf), 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 
514 static int
do_test(void)515 do_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, &wide, &length);
530   TEST_VERIFY (strlen (mbs) == length[WIDE_STRING_LENGTH]);
531   if (test_verbose > 0)
532     printf ("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 (mbs);
537   free (wide);
538   free (length);
539 
540   return 0;
541 }
542 
543 #include <support/test-driver.c>
544