]>
Commit | Line | Data |
---|---|---|
e2390be8 | 1 | /* Test for user-defined types in vfprintf. |
688903eb | 2 | Copyright (C) 2017-2018 Free Software Foundation, Inc. |
e2390be8 FW |
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 | <http://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 <locale.h> | |
25 | #include <printf.h> | |
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | #include <support/check.h> | |
30 | #include <support/support.h> | |
31 | #include <support/test-driver.h> | |
84d8c5bc | 32 | #include <wchar.h> |
e2390be8 FW |
33 | |
34 | /* Initialized by do_test using register_printf_type. */ | |
35 | static int user_type; | |
36 | ||
37 | struct two_argument | |
38 | { | |
39 | long i; | |
40 | double d; | |
41 | }; | |
42 | ||
43 | static void | |
44 | my_va_arg_function (void *mem, va_list *ap) | |
45 | { | |
46 | if (test_verbose > 0) | |
47 | printf ("info: %s (%p) called\n", __func__, mem); | |
48 | ||
49 | struct two_argument *pair = mem; | |
50 | pair->i = va_arg (*ap, long); | |
51 | pair->d = va_arg (*ap, double); | |
52 | } | |
53 | ||
54 | static int | |
55 | my_printf_function (FILE *fp, const struct printf_info *info, | |
56 | const void *const *args) | |
57 | { | |
58 | if (test_verbose > 0) | |
84d8c5bc FW |
59 | printf ("info: %s (%p, %p, {%p}@%p) called for %%%lc (prec %d)\n", |
60 | __func__, fp, info, args[0], args, (wint_t) info->spec, | |
61 | info->prec); | |
e2390be8 FW |
62 | |
63 | TEST_VERIFY (info->spec == 'P'); | |
64 | size_t nargs; | |
65 | int printed; | |
66 | if (info->prec >= 0) | |
67 | { | |
68 | if (fputc ('{', fp) < 0) | |
69 | return -1; | |
70 | nargs = info->prec; | |
71 | printed = 1; | |
72 | } | |
73 | else | |
74 | { | |
75 | nargs = 1; | |
76 | printed = 0; | |
77 | } | |
78 | ||
79 | for (size_t i = 0; i < nargs; ++i) | |
80 | { | |
81 | if (i != 0) | |
82 | { | |
83 | if (fputc (',', fp) < 0) | |
84 | return -1; | |
85 | ++printed; | |
86 | } | |
87 | ||
88 | /* NB: Triple pointer indirection. ARGS is an array of void *, | |
89 | and those pointers point to a pointer to the memory area | |
90 | supplied to my_va_arg_function. */ | |
91 | struct two_argument *pair = *(void **) args[i]; | |
92 | int ret = fprintf (fp, "(%ld, %f)", pair->i, pair->d); | |
93 | if (ret < 0) | |
94 | return -1; | |
95 | printed += ret; | |
96 | } | |
97 | if (info->prec >= 0) | |
98 | { | |
99 | if (fputc ('}', fp) < 0) | |
100 | return -1; | |
101 | ++printed; | |
102 | } | |
103 | return printed; | |
104 | } | |
105 | ||
106 | static int | |
107 | my_arginfo_function (const struct printf_info *info, | |
108 | size_t n, int *argtypes, int *size) | |
109 | { | |
110 | /* Avoid recursion. */ | |
111 | if (info->spec != 'P') | |
112 | return -1; | |
113 | if (test_verbose > 0) | |
84d8c5bc FW |
114 | printf ("info: %s (%p, %zu, %p, %p) called for %%%lc (prec %d)\n", |
115 | __func__, info, n, argtypes, size, (wint_t) info->spec, | |
116 | info->prec); | |
e2390be8 FW |
117 | |
118 | TEST_VERIFY_EXIT (n >= 1); | |
119 | size_t nargs; | |
120 | if (info->prec >= 0) | |
121 | nargs = info->prec; | |
122 | else | |
123 | nargs = 1; | |
124 | ||
125 | size_t to_fill = nargs; | |
126 | if (to_fill > n) | |
127 | to_fill = n; | |
128 | for (size_t i = 0; i < to_fill; ++i) | |
129 | { | |
130 | argtypes[i] = user_type; | |
131 | size[i] = sizeof (struct two_argument); | |
132 | } | |
133 | if (test_verbose > 0) | |
134 | printf ("info: %s return value: %zu\n", __func__, nargs); | |
135 | return nargs; | |
136 | } | |
137 | ||
138 | static int | |
139 | do_test (void) | |
140 | { | |
141 | user_type = register_printf_type (my_va_arg_function); | |
142 | if (test_verbose > 0) | |
143 | printf ("info: allocated user type: %d\n", user_type); | |
144 | TEST_VERIFY_EXIT (user_type >= PA_LAST); | |
145 | TEST_VERIFY_EXIT (register_printf_specifier | |
146 | ('P', my_printf_function, my_arginfo_function) >= 0); | |
147 | ||
148 | /* Alias declaration for asprintf, to avoid the format string | |
149 | attribute and the associated warning. */ | |
150 | extern int asprintf_alias (char **, const char *, ...) __asm__ ("asprintf"); | |
151 | TEST_VERIFY (asprintf_alias == asprintf); | |
152 | char *str = NULL; | |
153 | TEST_VERIFY (asprintf_alias (&str, "[[%P]]", 123L, 456.0) >= 0); | |
154 | if (test_verbose > 0) | |
155 | printf ("info: %s\n", str); | |
156 | TEST_VERIFY (strcmp (str, "[[(123, 456.000000)]]") == 0); | |
157 | free (str); | |
158 | ||
159 | str = NULL; | |
160 | TEST_VERIFY (asprintf_alias (&str, "[[%1$P %1$P]]", 123L, 457.0) >= 0); | |
161 | if (test_verbose > 0) | |
162 | printf ("info: %s\n", str); | |
163 | TEST_VERIFY (strcmp (str, "[[(123, 457.000000) (123, 457.000000)]]") == 0); | |
164 | free (str); | |
165 | ||
166 | str = NULL; | |
167 | TEST_VERIFY (asprintf_alias (&str, "[[%.1P]]", 1L, 2.0) >= 0); | |
168 | if (test_verbose > 0) | |
169 | printf ("info: %s\n", str); | |
170 | TEST_VERIFY (strcmp (str, "[[{(1, 2.000000)}]]") == 0); | |
171 | free (str); | |
172 | ||
173 | str = NULL; | |
174 | TEST_VERIFY (asprintf_alias (&str, "[[%.2P]]", 1L, 2.0, 3L, 4.0) >= 0); | |
175 | if (test_verbose > 0) | |
176 | printf ("info: %s\n", str); | |
177 | TEST_VERIFY (strcmp (str, "[[{(1, 2.000000),(3, 4.000000)}]]") == 0); | |
178 | free (str); | |
179 | ||
180 | str = NULL; | |
181 | TEST_VERIFY (asprintf_alias | |
182 | (&str, "[[%.2P | %.3P]]", | |
183 | /* argument 1: */ 1L, 2.0, 3L, 4.0, | |
184 | /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0) | |
185 | >= 0); | |
186 | if (test_verbose > 0) | |
187 | printf ("info: %s\n", str); | |
188 | TEST_VERIFY (strcmp (str, | |
189 | "[[" | |
190 | "{(1, 2.000000),(3, 4.000000)}" | |
191 | " | " | |
192 | "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}" | |
193 | "]]") == 0); | |
194 | free (str); | |
195 | ||
196 | /* The following subtest fails due to bug 21534. */ | |
197 | #if 0 | |
198 | str = NULL; | |
199 | TEST_VERIFY (asprintf_alias | |
200 | (&str, "[[%1$.2P | %2$.3P | %1$.2P]]", | |
201 | /* argument 1: */ 1L, 2.0, 3L, 4.0, | |
202 | /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0) | |
203 | >= 0); | |
204 | if (test_verbose > 0) | |
205 | printf ("info: %s\n", str); | |
206 | TEST_VERIFY (strcmp (str, | |
207 | "[[" | |
208 | "{(1, 2.000000),(3, 4.000000)}" | |
209 | " | " | |
210 | "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}" | |
211 | " | " | |
212 | "{(1, 2.000000),(3, 4.000000)}" | |
213 | "]]") == 0); | |
214 | free (str); | |
215 | #endif | |
216 | ||
217 | return 0; | |
218 | } | |
219 | ||
220 | #include <support/test-driver.c> |