1/* Test for user-defined types in vfprintf.
2 Copyright (C) 2017-2024 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/* This test contains a printf format specifier, %P, with a custom
20 type which is a long/double pair. If a precision is specified,
21 this indicates the number of such pairs which constitute the
22 argument. */
23
24#include <array_length.h>
25#include <locale.h>
26#include <printf.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <support/check.h>
31#include <support/support.h>
32#include <support/test-driver.h>
33#include <wchar.h>
34
35/* Initialized by do_test using register_printf_type. */
36static int user_type;
37
38struct two_argument
39{
40 long i;
41 double d;
42};
43
44static void
45my_va_arg_function (void *mem, va_list *ap)
46{
47 if (test_verbose > 0)
48 printf (format: "info: %s (%p) called\n", __func__, mem);
49
50 struct two_argument *pair = mem;
51 pair->i = va_arg (*ap, long);
52 pair->d = va_arg (*ap, double);
53}
54
55static int
56my_printf_function (FILE *fp, const struct printf_info *info,
57 const void *const *args)
58{
59 if (test_verbose > 0)
60 printf (format: "info: %s (%p, %p, {%p}@%p) called for %%%lc (prec %d)\n",
61 __func__, fp, info, args[0], args, (wint_t) info->spec,
62 info->prec);
63
64 TEST_COMPARE (info->wide, fwide (fp, 0) > 0);
65
66 TEST_VERIFY (info->spec == 'P');
67 size_t nargs;
68 int printed;
69 if (info->prec >= 0)
70 {
71 if (info->wide)
72 {
73 if (fputwc (wc: L'{', stream: fp) < 0)
74 return -1;
75 }
76 else
77 {
78 if (fputc (c: '{', stream: fp) < 0)
79 return -1;
80 }
81 nargs = info->prec;
82 printed = 1;
83 }
84 else
85 {
86 nargs = 1;
87 printed = 0;
88 }
89
90 for (size_t i = 0; i < nargs; ++i)
91 {
92 if (i != 0)
93 {
94 if (info->wide)
95 {
96 if (fputwc (wc: L',', stream: fp) < 0)
97 return -1;
98 }
99 else
100 {
101 if (fputc (c: ',', stream: fp) < 0)
102 return -1;
103 }
104 ++printed;
105 }
106
107 /* NB: Triple pointer indirection. ARGS is an array of void *,
108 and those pointers point to a pointer to the memory area
109 supplied to my_va_arg_function. */
110 struct two_argument *pair = *(void **) args[i];
111 int ret;
112 if (info->wide)
113 ret = fwprintf (stream: fp, format: L"(%ld, %f)", pair->i, pair->d);
114 else
115 ret = fprintf (fp, "(%ld, %f)", pair->i, pair->d);
116 if (ret < 0)
117 return -1;
118 printed += ret;
119 }
120 if (info->prec >= 0)
121 {
122 if (info->wide)
123 {
124 if (fputwc (wc: L'}', stream: fp) < 0)
125 return -1;
126 }
127 else
128 {
129 if (fputc (c: '}', stream: fp) < 0)
130 return -1;
131 }
132 ++printed;
133 }
134 return printed;
135}
136
137static int
138my_arginfo_function (const struct printf_info *info,
139 size_t n, int *argtypes, int *size)
140{
141 /* Avoid recursion. */
142 if (info->spec != 'P')
143 return -1;
144 if (test_verbose > 0)
145 printf (format: "info: %s (%p, %zu, %p, %p) called for %%%lc (prec %d)\n",
146 __func__, info, n, argtypes, size, (wint_t) info->spec,
147 info->prec);
148
149 TEST_VERIFY_EXIT (n >= 1);
150 size_t nargs;
151 if (info->prec >= 0)
152 nargs = info->prec;
153 else
154 nargs = 1;
155
156 size_t to_fill = nargs;
157 if (to_fill > n)
158 to_fill = n;
159 for (size_t i = 0; i < to_fill; ++i)
160 {
161 argtypes[i] = user_type;
162 size[i] = sizeof (struct two_argument);
163 }
164 if (test_verbose > 0)
165 printf (format: "info: %s return value: %zu\n", __func__, nargs);
166 return nargs;
167}
168
169static int
170do_test (void)
171{
172 user_type = register_printf_type (fct: my_va_arg_function);
173 if (test_verbose > 0)
174 printf (format: "info: allocated user type: %d\n", user_type);
175 TEST_VERIFY_EXIT (user_type >= PA_LAST);
176 TEST_VERIFY_EXIT (register_printf_specifier
177 ('P', my_printf_function, my_arginfo_function) >= 0);
178
179 /* Alias declaration for asprintf, to avoid the format string
180 attribute and the associated warning. */
181#if __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
182 extern int asprintf_alias (char **, const char *, ...) __asm__ ("__asprintfieee128");
183#else
184 extern int asprintf_alias (char **, const char *, ...) __asm__ ("asprintf");
185#endif
186 TEST_VERIFY (asprintf_alias == asprintf);
187 char *str = NULL;
188 TEST_VERIFY (asprintf_alias (&str, "[[%P]]", 123L, 456.0) >= 0);
189 TEST_COMPARE_STRING (str, "[[(123, 456.000000)]]");
190 free (ptr: str);
191
192 str = NULL;
193 TEST_VERIFY (asprintf_alias (&str, "[[%1$P %1$P]]", 123L, 457.0) >= 0);
194 TEST_COMPARE_STRING (str, "[[(123, 457.000000) (123, 457.000000)]]");
195 free (ptr: str);
196
197 str = NULL;
198 TEST_VERIFY (asprintf_alias (&str, "%1$P %2$P %3$P %4$P %5$P %6$P",
199 1L, 1.0,
200 2L, 2.0,
201 3L, 3.0,
202 4L, 4.0,
203 5L, 6.0,
204 6L, 6.0)
205 >= 0);
206 free (ptr: str);
207
208 str = NULL;
209 TEST_VERIFY (asprintf_alias (&str, "%1$P %2$P %3$P %4$P %5$P %6$P"
210 "%7$P %8$P %9$P %10$P %11$P %12$P",
211 1L, 1.0,
212 2L, 2.0,
213 3L, 3.0,
214 4L, 4.0,
215 5L, 6.0,
216 6L, 6.0,
217 7L, 7.0,
218 8L, 8.0,
219 9L, 9.0,
220 10L, 10.0,
221 11L, 11.0,
222 12L, 12.0)
223 >= 0);
224 free (ptr: str);
225
226 str = NULL;
227 TEST_VERIFY (asprintf_alias (&str, "%1$P %2$P %3$P %4$P %5$P %6$P"
228 "%7$P %8$P %9$P %10$P %11$P %12$P"
229 "%13$P %14$P %15$P %16$P %17$P %18$P",
230 1L, 1.0,
231 2L, 2.0,
232 3L, 3.0,
233 4L, 4.0,
234 5L, 6.0,
235 6L, 6.0,
236 7L, 7.0,
237 8L, 8.0,
238 9L, 9.0,
239 10L, 10.0,
240 11L, 11.0,
241 12L, 12.0,
242 13L, 13.0,
243 14L, 14.0,
244 15L, 15.0,
245 16L, 16.0,
246 17L, 17.0,
247 18L, 18.0)
248 >= 0);
249 free (ptr: str);
250
251 str = NULL;
252 TEST_VERIFY (asprintf_alias (&str, "%1$P %2$P %3$P %4$P %5$P %6$P"
253 "%7$P %8$P %9$P %10$P %11$P %12$P"
254 "%13$P %14$P %15$P %16$P %17$P %18$P"
255 "%19$P %20$P %21$P %22$P %23$P %24$P",
256 1L, 1.0,
257 2L, 2.0,
258 3L, 3.0,
259 4L, 4.0,
260 5L, 6.0,
261 6L, 6.0,
262 7L, 7.0,
263 8L, 8.0,
264 9L, 9.0,
265 10L, 10.0,
266 11L, 11.0,
267 12L, 12.0,
268 13L, 13.0,
269 14L, 14.0,
270 15L, 15.0,
271 16L, 16.0,
272 17L, 17.0,
273 18L, 18.0,
274 19L, 19.0,
275 20L, 20.0,
276 21L, 21.0,
277 22L, 22.0,
278 23L, 23.0,
279 24L, 24.0)
280 >= 0);
281 free (ptr: str);
282
283 str = NULL;
284 TEST_VERIFY (asprintf_alias (&str, "%1$P %2$P %3$P %4$P %5$P %6$P"
285 "%7$P %8$P %9$P %10$P %11$P %12$P"
286 "%13$P %14$P %15$P %16$P %17$P %18$P"
287 "%19$P %20$P %21$P %22$P %23$P %24$P"
288 "%25$P %26$P %27$P %28$P %29$P %30$P",
289 1L, 1.0,
290 2L, 2.0,
291 3L, 3.0,
292 4L, 4.0,
293 5L, 6.0,
294 6L, 6.0,
295 7L, 7.0,
296 8L, 8.0,
297 9L, 9.0,
298 10L, 10.0,
299 11L, 11.0,
300 12L, 12.0,
301 13L, 13.0,
302 14L, 14.0,
303 15L, 15.0,
304 16L, 16.0,
305 17L, 17.0,
306 18L, 18.0,
307 19L, 19.0,
308 20L, 20.0,
309 21L, 21.0,
310 22L, 22.0,
311 23L, 23.0,
312 24L, 34.0,
313 25L, 25.0,
314 26L, 26.0,
315 27L, 27.0,
316 28L, 28.0,
317 29L, 29.0,
318 30, 30.0)
319 >= 0);
320 free (ptr: str);
321
322 str = NULL;
323 TEST_VERIFY (asprintf_alias (&str, "[[%1$P %1$P]]", 123L, 457.0) >= 0);
324 TEST_COMPARE_STRING (str, "[[(123, 457.000000) (123, 457.000000)]]");
325 free (ptr: str);
326
327 str = NULL;
328 TEST_VERIFY (asprintf_alias (&str, "[[%.1P]]", 1L, 2.0) >= 0);
329 TEST_COMPARE_STRING (str, "[[{(1, 2.000000)}]]");
330 free (ptr: str);
331
332 str = NULL;
333 TEST_VERIFY (asprintf_alias (&str, "[[%.2P]]", 1L, 2.0, 3L, 4.0) >= 0);
334 TEST_COMPARE_STRING (str, "[[{(1, 2.000000),(3, 4.000000)}]]");
335 free (ptr: str);
336
337 str = NULL;
338 TEST_VERIFY (asprintf_alias
339 (&str, "[[%.2P | %.3P]]",
340 /* argument 1: */ 1L, 2.0, 3L, 4.0,
341 /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0)
342 >= 0);
343 TEST_COMPARE_STRING (str,
344 "[["
345 "{(1, 2.000000),(3, 4.000000)}"
346 " | "
347 "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}"
348 "]]");
349 free (ptr: str);
350
351 /* The following subtest fails due to bug 21534. */
352#if 0
353 str = NULL;
354 TEST_VERIFY (asprintf_alias
355 (&str, "[[%1$.2P | %2$.3P | %1$.2P]]",
356 /* argument 1: */ 1L, 2.0, 3L, 4.0,
357 /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0)
358 >= 0);
359 TEST_COMPARE_STRING (str,
360 "[["
361 "{(1, 2.000000),(3, 4.000000)}"
362 " | "
363 "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}"
364 " | "
365 "{(1, 2.000000),(3, 4.000000)}"
366 "]]");
367 free (str);
368#endif
369
370 /* Wide variants of the tests above. */
371
372 wchar_t buf[200];
373 TEST_VERIFY (swprintf (buf, array_length (buf), L"[[%P]]", 123L, 456.0)
374 >= 0);
375 TEST_COMPARE_STRING_WIDE (buf, L"[[(123, 456.000000)]]");
376
377 TEST_VERIFY (swprintf (buf, array_length (buf), L"[[%1$P %1$P]]",
378 123L, 457.0) >= 0);
379 TEST_COMPARE_STRING_WIDE (buf, L"[[(123, 457.000000) (123, 457.000000)]]");
380
381 TEST_VERIFY (swprintf (buf, array_length (buf), L"[[%.1P]]", 1L, 2.0) >= 0);
382 TEST_COMPARE_STRING_WIDE (buf, L"[[{(1, 2.000000)}]]");
383
384 TEST_VERIFY (swprintf (buf, array_length (buf), L"[[%.2P]]",
385 1L, 2.0, 3L, 4.0) >= 0);
386 TEST_COMPARE_STRING_WIDE (buf, L"[[{(1, 2.000000),(3, 4.000000)}]]");
387
388 TEST_VERIFY (swprintf
389 (buf, array_length (buf), L"[[%.2P | %.3P]]",
390 /* argument 1: */ 1L, 2.0, 3L, 4.0,
391 /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0)
392 >= 0);
393 TEST_COMPARE_STRING_WIDE (buf,
394 L"[["
395 "{(1, 2.000000),(3, 4.000000)}"
396 " | "
397 "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}"
398 "]]");
399
400 /* The following subtest fails due to bug 21534. */
401#if 0
402 TEST_VERIFY (swprintf
403 (&buf, array_length (buf), L"[[%1$.2P | %2$.3P | %1$.2P]]",
404 /* argument 1: */ 1L, 2.0, 3L, 4.0,
405 /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0)
406 >= 0);
407 TEST_COMPARE_STRING_WIDE (buf,
408 L"[["
409 "{(1, 2.000000),(3, 4.000000)}"
410 " | "
411 "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}"
412 " | "
413 "{(1, 2.000000),(3, 4.000000)}"
414 "]]");
415#endif
416
417 return 0;
418}
419
420#include <support/test-driver.c>
421

source code of glibc/stdio-common/tst-vfprintf-user-type.c