blob: b0f6a30e6c0ae7d98a34ec5b747eaf09169e1262 [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* Test gmp_printf and related functions.
2
3Copyright 2001-2003, 2015 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
19
20
21/* Usage: t-printf [-s]
22
23 -s Check the data against the system printf, where possible. This is
24 only an option since we don't want to fail if the system printf is
25 faulty or strange. */
26
27
28#include "config.h" /* needed for the HAVE_, could also move gmp incls */
29
30#include <stdarg.h>
31#include <stddef.h> /* for ptrdiff_t */
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35
36#if HAVE_OBSTACK_VPRINTF
37#define obstack_chunk_alloc tests_allocate
38#define obstack_chunk_free tests_free_nosize
39#include <obstack.h>
40#endif
41
42#if HAVE_INTTYPES_H
43# include <inttypes.h> /* for intmax_t */
44#else
45# if HAVE_STDINT_H
46# include <stdint.h>
47# endif
48#endif
49
50#if HAVE_UNISTD_H
51#include <unistd.h> /* for unlink */
52#endif
53
54#include "gmp-impl.h"
55#include "tests.h"
56
57
58int option_check_printf = 0;
59
60
61#define CHECK_VFPRINTF_FILENAME "t-printf.tmp"
62FILE *check_vfprintf_fp;
63
64
65/* From any of the tests run here. */
66#define MAX_OUTPUT 1024
67
68
69void
70check_plain (const char *want, const char *fmt_orig, ...)
71{
72 char got[MAX_OUTPUT];
73 int got_len, want_len;
74 size_t fmtsize;
75 char *fmt, *q;
76 const char *p;
77 va_list ap;
78 va_start (ap, fmt_orig);
79
80 if (! option_check_printf)
81 return;
82
83 fmtsize = strlen (fmt_orig) + 1;
84 fmt = (char *) (*__gmp_allocate_func) (fmtsize);
85
86 for (p = fmt_orig, q = fmt; *p != '\0'; p++)
87 {
88 switch (*p) {
89 case 'a':
90 case 'A':
91 /* The exact value of the exponent isn't guaranteed in glibc, and it
92 and gmp_printf do slightly different things, so don't compare
93 directly. */
94 goto done;
95 case 'F':
96 if (p > fmt_orig && *(p-1) == '.')
97 goto done; /* don't test the "all digits" cases */
98 /* discard 'F' type */
99 break;
100 case 'Z':
101 /* transmute */
102 *q++ = 'l';
103 break;
104 default:
105 *q++ = *p;
106 break;
107 }
108 }
109 *q = '\0';
110
111 want_len = strlen (want);
112 ASSERT_ALWAYS (want_len < sizeof(got));
113
114 got_len = vsprintf (got, fmt, ap);
115
116 if (got_len != want_len || strcmp (got, want) != 0)
117 {
118 printf ("wanted data doesn't match plain vsprintf\n");
119 printf (" fmt |%s|\n", fmt);
120 printf (" got |%s|\n", got);
121 printf (" want |%s|\n", want);
122 printf (" got_len %d\n", got_len);
123 printf (" want_len %d\n", want_len);
124 abort ();
125 }
126
127 done:
128 (*__gmp_free_func) (fmt, fmtsize);
129}
130
131void
132check_vsprintf (const char *want, const char *fmt, va_list ap)
133{
134 char got[MAX_OUTPUT];
135 int got_len, want_len;
136
137 want_len = strlen (want);
138 got_len = gmp_vsprintf (got, fmt, ap);
139
140 if (got_len != want_len || strcmp (got, want) != 0)
141 {
142 printf ("gmp_vsprintf wrong\n");
143 printf (" fmt |%s|\n", fmt);
144 printf (" got |%s|\n", got);
145 printf (" want |%s|\n", want);
146 printf (" got_len %d\n", got_len);
147 printf (" want_len %d\n", want_len);
148 abort ();
149 }
150}
151
152void
153check_vfprintf (const char *want, const char *fmt, va_list ap)
154{
155 char got[MAX_OUTPUT];
156 int got_len, want_len, fread_len;
157 long ftell_len;
158
159 want_len = strlen (want);
160
161 rewind (check_vfprintf_fp);
162 got_len = gmp_vfprintf (check_vfprintf_fp, fmt, ap);
163 ASSERT_ALWAYS (got_len != -1);
164 ASSERT_ALWAYS (fflush (check_vfprintf_fp) == 0);
165
166 ftell_len = ftell (check_vfprintf_fp);
167 ASSERT_ALWAYS (ftell_len != -1);
168
169 rewind (check_vfprintf_fp);
170 ASSERT_ALWAYS (ftell_len <= sizeof(got));
171 fread_len = fread (got, 1, ftell_len, check_vfprintf_fp);
172
173 if (got_len != want_len
174 || ftell_len != want_len
175 || fread_len != want_len
176 || memcmp (got, want, want_len) != 0)
177 {
178 printf ("gmp_vfprintf wrong\n");
179 printf (" fmt |%s|\n", fmt);
180 printf (" got |%.*s|\n", fread_len, got);
181 printf (" want |%s|\n", want);
182 printf (" got_len %d\n", got_len);
183 printf (" ftell_len %ld\n", ftell_len);
184 printf (" fread_len %d\n", fread_len);
185 printf (" want_len %d\n", want_len);
186 abort ();
187 }
188}
189
190void
191check_vsnprintf (const char *want, const char *fmt, va_list ap)
192{
193 char got[MAX_OUTPUT+1];
194 int ret, got_len, want_len;
195 size_t bufsize;
196
197 want_len = strlen (want);
198
199 bufsize = -1;
200 for (;;)
201 {
202 /* do 0 to 5, then want-5 to want+5 */
203 bufsize++;
204 if (bufsize > 5 && bufsize < want_len-5)
205 bufsize = want_len-5;
206 if (bufsize > want_len + 5)
207 break;
208 ASSERT_ALWAYS (bufsize+1 <= sizeof (got));
209
210 got[bufsize] = '!';
211 ret = gmp_vsnprintf (got, bufsize, fmt, ap);
212
213 got_len = MIN (MAX(1,bufsize)-1, want_len);
214
215 if (got[bufsize] != '!')
216 {
217 printf ("gmp_vsnprintf overwrote bufsize sentinel\n");
218 goto error;
219 }
220
221 if (ret != want_len)
222 {
223 printf ("gmp_vsnprintf return value wrong\n");
224 goto error;
225 }
226
227 if (bufsize > 0)
228 {
229 if (memcmp (got, want, got_len) != 0 || got[got_len] != '\0')
230 {
231 printf ("gmp_vsnprintf wrong result string\n");
232 error:
233 printf (" fmt |%s|\n", fmt);
234 printf (" bufsize %lu\n", (unsigned long) bufsize);
235 printf (" got |%s|\n", got);
236 printf (" want |%.*s|\n", got_len, want);
237 printf (" want full |%s|\n", want);
238 printf (" ret %d\n", ret);
239 printf (" want_len %d\n", want_len);
240 abort ();
241 }
242 }
243 }
244}
245
246void
247check_vasprintf (const char *want, const char *fmt, va_list ap)
248{
249 char *got;
250 int got_len, want_len;
251
252 want_len = strlen (want);
253 got_len = gmp_vasprintf (&got, fmt, ap);
254
255 if (got_len != want_len || strcmp (got, want) != 0)
256 {
257 printf ("gmp_vasprintf wrong\n");
258 printf (" fmt |%s|\n", fmt);
259 printf (" got |%s|\n", got);
260 printf (" want |%s|\n", want);
261 printf (" got_len %d\n", got_len);
262 printf (" want_len %d\n", want_len);
263 abort ();
264 }
265 (*__gmp_free_func) (got, strlen(got)+1);
266}
267
268void
269check_obstack_vprintf (const char *want, const char *fmt, va_list ap)
270{
271#if HAVE_OBSTACK_VPRINTF
272 struct obstack ob;
273 int got_len, want_len, ob_len;
274 char *got;
275
276 want_len = strlen (want);
277
278 obstack_init (&ob);
279 got_len = gmp_obstack_vprintf (&ob, fmt, ap);
280 got = (char *) obstack_base (&ob);
281 ob_len = obstack_object_size (&ob);
282
283 if (got_len != want_len
284 || ob_len != want_len
285 || memcmp (got, want, want_len) != 0)
286 {
287 printf ("gmp_obstack_vprintf wrong\n");
288 printf (" fmt |%s|\n", fmt);
289 printf (" got |%s|\n", got);
290 printf (" want |%s|\n", want);
291 printf (" got_len %d\n", got_len);
292 printf (" ob_len %d\n", ob_len);
293 printf (" want_len %d\n", want_len);
294 abort ();
295 }
296 obstack_free (&ob, NULL);
297#endif
298}
299
300
301void
302check_one (const char *want, const char *fmt, ...)
303{
304 va_list ap;
305 va_start (ap, fmt);
306
307 /* simplest first */
308 check_vsprintf (want, fmt, ap);
309 check_vfprintf (want, fmt, ap);
310 check_vsnprintf (want, fmt, ap);
311 check_vasprintf (want, fmt, ap);
312 check_obstack_vprintf (want, fmt, ap);
313}
314
315
316#define hex_or_octal_p(fmt) \
317 (strchr (fmt, 'x') != NULL \
318 || strchr (fmt, 'X') != NULL \
319 || strchr (fmt, 'o') != NULL)
320
321void
322check_z (void)
323{
324 static const struct {
325 const char *fmt;
326 const char *z;
327 const char *want;
328 } data[] = {
329 { "%Zd", "0", "0" },
330 { "%Zd", "1", "1" },
331 { "%Zd", "123", "123" },
332 { "%Zd", "-1", "-1" },
333 { "%Zd", "-123", "-123" },
334
335 { "%+Zd", "0", "+0" },
336 { "%+Zd", "123", "+123" },
337 { "%+Zd", "-123", "-123" },
338
339 { "%Zx", "123", "7b" },
340 { "%ZX", "123", "7B" },
341 { "%Zx", "-123", "-7b" },
342 { "%ZX", "-123", "-7B" },
343 { "%Zo", "123", "173" },
344 { "%Zo", "-123", "-173" },
345
346 { "%#Zx", "0", "0" },
347 { "%#ZX", "0", "0" },
348 { "%#Zx", "123", "0x7b" },
349 { "%#ZX", "123", "0X7B" },
350 { "%#Zx", "-123", "-0x7b" },
351 { "%#ZX", "-123", "-0X7B" },
352
353 { "%#Zo", "0", "0" },
354 { "%#Zo", "123", "0173" },
355 { "%#Zo", "-123", "-0173" },
356
357 { "%10Zd", "0", " 0" },
358 { "%10Zd", "123", " 123" },
359 { "%10Zd", "-123", " -123" },
360
361 { "%-10Zd", "0", "0 " },
362 { "%-10Zd", "123", "123 " },
363 { "%-10Zd", "-123", "-123 " },
364
365 { "%+10Zd", "123", " +123" },
366 { "%+-10Zd", "123", "+123 " },
367 { "%+10Zd", "-123", " -123" },
368 { "%+-10Zd", "-123", "-123 " },
369
370 { "%08Zd", "0", "00000000" },
371 { "%08Zd", "123", "00000123" },
372 { "%08Zd", "-123", "-0000123" },
373
374 { "%+08Zd", "0", "+0000000" },
375 { "%+08Zd", "123", "+0000123" },
376 { "%+08Zd", "-123", "-0000123" },
377
378 { "%#08Zx", "0", "00000000" },
379 { "%#08Zx", "123", "0x00007b" },
380 { "%#08Zx", "-123", "-0x0007b" },
381
382 { "%+#08Zx", "0", "+0000000" },
383 { "%+#08Zx", "123", "+0x0007b" },
384 { "%+#08Zx", "-123", "-0x0007b" },
385
386 { "%.0Zd", "0", "" },
387 { "%.1Zd", "0", "0" },
388 { "%.2Zd", "0", "00" },
389 { "%.3Zd", "0", "000" },
390 };
391
392 int i, j;
393 mpz_t z;
394 char *nfmt;
395 mp_size_t nsize, zeros;
396
397 mpz_init (z);
398
399 for (i = 0; i < numberof (data); i++)
400 {
401 mpz_set_str_or_abort (z, data[i].z, 0);
402
403 /* don't try negatives or forced sign in hex or octal */
404 if (mpz_fits_slong_p (z)
405 && ! (hex_or_octal_p (data[i].fmt)
406 && (strchr (data[i].fmt, '+') != NULL || mpz_sgn(z) < 0)))
407 {
408 check_plain (data[i].want, data[i].fmt, mpz_get_si (z));
409 }
410
411 check_one (data[i].want, data[i].fmt, z);
412
413 /* Same again, with %N and possibly some high zero limbs */
414 nfmt = __gmp_allocate_strdup (data[i].fmt);
415 for (j = 0; nfmt[j] != '\0'; j++)
416 if (nfmt[j] == 'Z')
417 nfmt[j] = 'N';
418 for (zeros = 0; zeros <= 3; zeros++)
419 {
420 nsize = ABSIZ(z)+zeros;
421 MPZ_REALLOC (z, nsize);
422 nsize = (SIZ(z) >= 0 ? nsize : -nsize);
423 refmpn_zero (PTR(z)+ABSIZ(z), zeros);
424 check_one (data[i].want, nfmt, PTR(z), nsize);
425 }
426 __gmp_free_func (nfmt, strlen(nfmt)+1);
427 }
428
429 mpz_clear (z);
430}
431
432void
433check_q (void)
434{
435 static const struct {
436 const char *fmt;
437 const char *q;
438 const char *want;
439 } data[] = {
440 { "%Qd", "0", "0" },
441 { "%Qd", "1", "1" },
442 { "%Qd", "123", "123" },
443 { "%Qd", "-1", "-1" },
444 { "%Qd", "-123", "-123" },
445 { "%Qd", "3/2", "3/2" },
446 { "%Qd", "-3/2", "-3/2" },
447
448 { "%+Qd", "0", "+0" },
449 { "%+Qd", "123", "+123" },
450 { "%+Qd", "-123", "-123" },
451 { "%+Qd", "5/8", "+5/8" },
452 { "%+Qd", "-5/8", "-5/8" },
453
454 { "%Qx", "123", "7b" },
455 { "%QX", "123", "7B" },
456 { "%Qx", "15/16", "f/10" },
457 { "%QX", "15/16", "F/10" },
458 { "%Qx", "-123", "-7b" },
459 { "%QX", "-123", "-7B" },
460 { "%Qx", "-15/16", "-f/10" },
461 { "%QX", "-15/16", "-F/10" },
462 { "%Qo", "123", "173" },
463 { "%Qo", "-123", "-173" },
464 { "%Qo", "16/17", "20/21" },
465 { "%Qo", "-16/17", "-20/21" },
466
467 { "%#Qx", "0", "0" },
468 { "%#QX", "0", "0" },
469 { "%#Qx", "123", "0x7b" },
470 { "%#QX", "123", "0X7B" },
471 { "%#Qx", "5/8", "0x5/0x8" },
472 { "%#QX", "5/8", "0X5/0X8" },
473 { "%#Qx", "-123", "-0x7b" },
474 { "%#QX", "-123", "-0X7B" },
475 { "%#Qx", "-5/8", "-0x5/0x8" },
476 { "%#QX", "-5/8", "-0X5/0X8" },
477 { "%#Qo", "0", "0" },
478 { "%#Qo", "123", "0173" },
479 { "%#Qo", "-123", "-0173" },
480 { "%#Qo", "5/7", "05/07" },
481 { "%#Qo", "-5/7", "-05/07" },
482
483 /* zero denominator and showbase */
484 { "%#10Qo", "0/0", " 0/0" },
485 { "%#10Qd", "0/0", " 0/0" },
486 { "%#10Qx", "0/0", " 0/0" },
487 { "%#10Qo", "123/0", " 0173/0" },
488 { "%#10Qd", "123/0", " 123/0" },
489 { "%#10Qx", "123/0", " 0x7b/0" },
490 { "%#10QX", "123/0", " 0X7B/0" },
491 { "%#10Qo", "-123/0", " -0173/0" },
492 { "%#10Qd", "-123/0", " -123/0" },
493 { "%#10Qx", "-123/0", " -0x7b/0" },
494 { "%#10QX", "-123/0", " -0X7B/0" },
495
496 { "%10Qd", "0", " 0" },
497 { "%-10Qd", "0", "0 " },
498 { "%10Qd", "123", " 123" },
499 { "%-10Qd", "123", "123 " },
500 { "%10Qd", "-123", " -123" },
501 { "%-10Qd", "-123", "-123 " },
502
503 { "%+10Qd", "123", " +123" },
504 { "%+-10Qd", "123", "+123 " },
505 { "%+10Qd", "-123", " -123" },
506 { "%+-10Qd", "-123", "-123 " },
507
508 { "%08Qd", "0", "00000000" },
509 { "%08Qd", "123", "00000123" },
510 { "%08Qd", "-123", "-0000123" },
511
512 { "%+08Qd", "0", "+0000000" },
513 { "%+08Qd", "123", "+0000123" },
514 { "%+08Qd", "-123", "-0000123" },
515
516 { "%#08Qx", "0", "00000000" },
517 { "%#08Qx", "123", "0x00007b" },
518 { "%#08Qx", "-123", "-0x0007b" },
519
520 { "%+#08Qx", "0", "+0000000" },
521 { "%+#08Qx", "123", "+0x0007b" },
522 { "%+#08Qx", "-123", "-0x0007b" },
523 };
524
525 int i;
526 mpq_t q;
527
528 mpq_init (q);
529
530 for (i = 0; i < numberof (data); i++)
531 {
532 mpq_set_str_or_abort (q, data[i].q, 0);
533 check_one (data[i].want, data[i].fmt, q);
534 }
535
536 mpq_clear (q);
537}
538
539void
540check_f (void)
541{
542 static const struct {
543 const char *fmt;
544 const char *f;
545 const char *want;
546
547 } data[] = {
548
549 { "%Ff", "0", "0.000000" },
550 { "%Ff", "123", "123.000000" },
551 { "%Ff", "-123", "-123.000000" },
552
553 { "%+Ff", "0", "+0.000000" },
554 { "%+Ff", "123", "+123.000000" },
555 { "%+Ff", "-123", "-123.000000" },
556
557 { "%.0Ff", "0", "0" },
558 { "%.0Ff", "123", "123" },
559 { "%.0Ff", "-123", "-123" },
560
561 { "%8.0Ff", "0", " 0" },
562 { "%8.0Ff", "123", " 123" },
563 { "%8.0Ff", "-123", " -123" },
564
565 { "%08.0Ff", "0", "00000000" },
566 { "%08.0Ff", "123", "00000123" },
567 { "%08.0Ff", "-123", "-0000123" },
568
569 { "%10.2Ff", "0", " 0.00" },
570 { "%10.2Ff", "0.25", " 0.25" },
571 { "%10.2Ff", "123.25", " 123.25" },
572 { "%10.2Ff", "-123.25", " -123.25" },
573
574 { "%-10.2Ff", "0", "0.00 " },
575 { "%-10.2Ff", "0.25", "0.25 " },
576 { "%-10.2Ff", "123.25", "123.25 " },
577 { "%-10.2Ff", "-123.25", "-123.25 " },
578
579 { "%.2Ff", "0.00000000000001", "0.00" },
580 { "%.2Ff", "0.002", "0.00" },
581 { "%.2Ff", "0.008", "0.01" },
582
583 { "%.0Ff", "123.00000000000001", "123" },
584 { "%.0Ff", "123.2", "123" },
585 { "%.0Ff", "123.8", "124" },
586
587 { "%.0Ff", "999999.9", "1000000" },
588 { "%.0Ff", "3999999.9", "4000000" },
589
590 { "%Fe", "0", "0.000000e+00" },
591 { "%Fe", "1", "1.000000e+00" },
592 { "%Fe", "123", "1.230000e+02" },
593
594 { "%FE", "0", "0.000000E+00" },
595 { "%FE", "1", "1.000000E+00" },
596 { "%FE", "123", "1.230000E+02" },
597
598 { "%Fe", "0", "0.000000e+00" },
599 { "%Fe", "1", "1.000000e+00" },
600
601 { "%.0Fe", "10000000000", "1e+10" },
602 { "%.0Fe", "-10000000000", "-1e+10" },
603
604 { "%.2Fe", "10000000000", "1.00e+10" },
605 { "%.2Fe", "-10000000000", "-1.00e+10" },
606
607 { "%8.0Fe", "10000000000", " 1e+10" },
608 { "%8.0Fe", "-10000000000", " -1e+10" },
609
610 { "%-8.0Fe", "10000000000", "1e+10 " },
611 { "%-8.0Fe", "-10000000000", "-1e+10 " },
612
613 { "%12.2Fe", "10000000000", " 1.00e+10" },
614 { "%12.2Fe", "-10000000000", " -1.00e+10" },
615
616 { "%012.2Fe", "10000000000", "00001.00e+10" },
617 { "%012.2Fe", "-10000000000", "-0001.00e+10" },
618
619 { "%Fg", "0", "0" },
620 { "%Fg", "1", "1" },
621 { "%Fg", "-1", "-1" },
622
623 { "%.0Fg", "0", "0" },
624 { "%.0Fg", "1", "1" },
625 { "%.0Fg", "-1", "-1" },
626
627 { "%.1Fg", "100", "1e+02" },
628 { "%.2Fg", "100", "1e+02" },
629 { "%.3Fg", "100", "100" },
630 { "%.4Fg", "100", "100" },
631
632 { "%Fg", "0.001", "0.001" },
633 { "%Fg", "0.0001", "0.0001" },
634 { "%Fg", "0.00001", "1e-05" },
635 { "%Fg", "0.000001", "1e-06" },
636
637 { "%.4Fg", "1.00000000000001", "1" },
638 { "%.4Fg", "100000000000001", "1e+14" },
639
640 { "%.4Fg", "12345678", "1.235e+07" },
641
642 { "%Fa", "0","0x0p+0" },
643 { "%FA", "0","0X0P+0" },
644
645 { "%Fa", "1","0x1p+0" },
646 { "%Fa", "65535","0xf.fffp+12" },
647 { "%Fa", "65536","0x1p+16" },
648 { "%F.10a", "65536","0x1.0000000000p+16" },
649 { "%F.1a", "65535","0x1.0p+16" },
650 { "%F.0a", "65535","0x1p+16" },
651
652 { "%.2Ff", "0.99609375", "1.00" },
653 { "%.Ff", "0.99609375", "0.99609375" },
654 { "%.Fe", "0.99609375", "9.9609375e-01" },
655 { "%.Fg", "0.99609375", "0.99609375" },
656 { "%.20Fg", "1000000", "1000000" },
657 { "%.Fg", "1000000", "1000000" },
658
659 { "%#.0Ff", "1", "1." },
660 { "%#.0Fe", "1", "1.e+00" },
661 { "%#.0Fg", "1", "1." },
662
663 { "%#.1Ff", "1", "1.0" },
664 { "%#.1Fe", "1", "1.0e+00" },
665 { "%#.1Fg", "1", "1." },
666
667 { "%#.4Ff", "1234", "1234.0000" },
668 { "%#.4Fe", "1234", "1.2340e+03" },
669 { "%#.4Fg", "1234", "1234." },
670
671 { "%#.8Ff", "1234", "1234.00000000" },
672 { "%#.8Fe", "1234", "1.23400000e+03" },
673 { "%#.8Fg", "1234", "1234.0000" },
674
675 };
676
677 int i;
678 mpf_t f;
679 double d;
680
681 mpf_init2 (f, 256L);
682
683 for (i = 0; i < numberof (data); i++)
684 {
685 if (data[i].f[0] == '0' && data[i].f[1] == 'x')
686 mpf_set_str_or_abort (f, data[i].f, 16);
687 else
688 mpf_set_str_or_abort (f, data[i].f, 10);
689
690 /* if mpf->double doesn't truncate, then expect same result */
691 d = mpf_get_d (f);
692 if (mpf_cmp_d (f, d) == 0)
693 check_plain (data[i].want, data[i].fmt, d);
694
695 check_one (data[i].want, data[i].fmt, f);
696 }
697
698 mpf_clear (f);
699}
700
701
702void
703check_limb (void)
704{
705 int i;
706 mp_limb_t limb;
707 mpz_t z;
708 char *s;
709
710 check_one ("0", "%Md", CNST_LIMB(0));
711 check_one ("1", "%Md", CNST_LIMB(1));
712
713 /* "i" many 1 bits, tested against mpz_get_str in decimal and hex */
714 limb = 1;
715 mpz_init_set_ui (z, 1L);
716 for (i = 1; i <= GMP_LIMB_BITS; i++)
717 {
718 s = mpz_get_str (NULL, 10, z);
719 check_one (s, "%Mu", limb);
720 (*__gmp_free_func) (s, strlen (s) + 1);
721
722 s = mpz_get_str (NULL, 16, z);
723 check_one (s, "%Mx", limb);
724 (*__gmp_free_func) (s, strlen (s) + 1);
725
726 s = mpz_get_str (NULL, -16, z);
727 check_one (s, "%MX", limb);
728 (*__gmp_free_func) (s, strlen (s) + 1);
729
730 limb = 2*limb + 1;
731 mpz_mul_2exp (z, z, 1L);
732 mpz_add_ui (z, z, 1L);
733 }
734
735 mpz_clear (z);
736}
737
738
739void
740check_n (void)
741{
742 {
743 int n = -1;
744 check_one ("blah", "%nblah", &n);
745 ASSERT_ALWAYS (n == 0);
746 }
747
748 {
749 int n = -1;
750 check_one ("hello ", "hello %n", &n);
751 ASSERT_ALWAYS (n == 6);
752 }
753
754 {
755 int n = -1;
756 check_one ("hello world", "hello %n world", &n);
757 ASSERT_ALWAYS (n == 6);
758 }
759
760#define CHECK_N(type, string) \
761 do { \
762 type x[2]; \
763 char fmt[128]; \
764 \
765 x[0] = ~ (type) 0; \
766 x[1] = ~ (type) 0; \
767 sprintf (fmt, "%%d%%%sn%%d", string); \
768 check_one ("123456", fmt, 123, &x[0], 456); \
769 \
770 /* should write whole of x[0] and none of x[1] */ \
771 ASSERT_ALWAYS (x[0] == 3); \
772 ASSERT_ALWAYS (x[1] == (type) ~ (type) 0); \
773 \
774 } while (0)
775
776 CHECK_N (mp_limb_t, "M");
777 CHECK_N (char, "hh");
778 CHECK_N (long, "l");
779#if HAVE_LONG_LONG
780 CHECK_N (long long, "L");
781#endif
782#if HAVE_INTMAX_T
783 CHECK_N (intmax_t, "j");
784#endif
785#if HAVE_PTRDIFF_T
786 CHECK_N (ptrdiff_t, "t");
787#endif
788 CHECK_N (short, "h");
789 CHECK_N (size_t, "z");
790
791 {
792 mpz_t x[2];
793 mpz_init_set_si (x[0], -987L);
794 mpz_init_set_si (x[1], 654L);
795 check_one ("123456", "%d%Zn%d", 123, x[0], 456);
796 MPZ_CHECK_FORMAT (x[0]);
797 MPZ_CHECK_FORMAT (x[1]);
798 ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0);
799 ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0);
800 mpz_clear (x[0]);
801 mpz_clear (x[1]);
802 }
803
804 {
805 mpq_t x[2];
806 mpq_init (x[0]);
807 mpq_init (x[1]);
808 mpq_set_ui (x[0], 987L, 654L);
809 mpq_set_ui (x[1], 4115L, 226L);
810 check_one ("123456", "%d%Qn%d", 123, x[0], 456);
811 MPQ_CHECK_FORMAT (x[0]);
812 MPQ_CHECK_FORMAT (x[1]);
813 ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0);
814 ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0);
815 mpq_clear (x[0]);
816 mpq_clear (x[1]);
817 }
818
819 {
820 mpf_t x[2];
821 mpf_init (x[0]);
822 mpf_init (x[1]);
823 mpf_set_ui (x[0], 987L);
824 mpf_set_ui (x[1], 654L);
825 check_one ("123456", "%d%Fn%d", 123, x[0], 456);
826 MPF_CHECK_FORMAT (x[0]);
827 MPF_CHECK_FORMAT (x[1]);
828 ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0);
829 ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0);
830 mpf_clear (x[0]);
831 mpf_clear (x[1]);
832 }
833
834 {
835 mp_limb_t a[5];
836 mp_limb_t a_want[numberof(a)];
837 mp_size_t i;
838
839 a[0] = 123;
840 check_one ("blah", "bl%Nnah", a, (mp_size_t) 0);
841 ASSERT_ALWAYS (a[0] == 123);
842
843 MPN_ZERO (a_want, numberof (a_want));
844 for (i = 1; i < numberof (a); i++)
845 {
846 check_one ("blah", "bl%Nnah", a, i);
847 a_want[0] = 2;
848 ASSERT_ALWAYS (mpn_cmp (a, a_want, i) == 0);
849 }
850 }
851}
852
853
854void
855check_misc (void)
856{
857 mpz_t z;
858 mpf_t f;
859
860 mpz_init (z);
861 mpf_init2 (f, 128L);
862
863 check_one ("!", "%c", '!');
864
865 check_one ("hello world", "hello %s", "world");
866 check_one ("hello:", "%s:", "hello");
867 mpz_set_ui (z, 0L);
868 check_one ("hello0", "%s%Zd", "hello", z, z);
869
870 {
871 static char xs[801];
872 memset (xs, 'x', sizeof(xs)-1);
873 check_one (xs, "%s", xs);
874 }
875 {
876 char *xs;
877 xs = (char *) (*__gmp_allocate_func) (MAX_OUTPUT * 2 - 12);
878 memset (xs, '%', MAX_OUTPUT * 2 - 14);
879 xs [MAX_OUTPUT * 2 - 13] = '\0';
880 xs [MAX_OUTPUT * 2 - 14] = 'x';
881 check_one (xs + MAX_OUTPUT - 7, xs, NULL);
882 (*__gmp_free_func) (xs, MAX_OUTPUT * 2 - 12);
883 }
884
885 mpz_set_ui (z, 12345L);
886 check_one (" 12345", "%*Zd", 10, z);
887 check_one ("0000012345", "%0*Zd", 10, z);
888 check_one ("12345 ", "%*Zd", -10, z);
889 check_one ("12345 and 678", "%Zd and %d", z, 678);
890 check_one ("12345,1,12345,2,12345", "%Zd,%d,%Zd,%d,%Zd", z, 1, z, 2, z);
891
892 /* from the glibc info docs */
893 mpz_set_si (z, 0L);
894 check_one ("| 0|0 | +0|+0 | 0|00000| | 00|0|",
895 "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
896 /**/ z, z, z, z, z, z, z, z, z);
897 mpz_set_si (z, 1L);
898 check_one ("| 1|1 | +1|+1 | 1|00001| 1| 01|1|",
899 "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
900 /**/ z, z, z, z, z, z, z, z, z);
901 mpz_set_si (z, -1L);
902 check_one ("| -1|-1 | -1|-1 | -1|-0001| -1| -01|-1|",
903 "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
904 /**/ z, z, z, z, z, z, z, z, z);
905 mpz_set_si (z, 100000L);
906 check_one ("|100000|100000|+100000|+100000| 100000|100000|100000|100000|100000|",
907 "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
908 /**/ z, z, z, z, z, z, z, z, z);
909 mpz_set_si (z, 0L);
910 check_one ("| 0| 0| 0| 0| 0| 0| 00000000|",
911 "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
912 /**/ z, z, z, z, z, z, z);
913 mpz_set_si (z, 1L);
914 check_one ("| 1| 1| 1| 01| 0x1| 0X1|0x00000001|",
915 "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
916 /**/ z, z, z, z, z, z, z);
917 mpz_set_si (z, 100000L);
918 check_one ("|303240|186a0|186A0|0303240|0x186a0|0X186A0|0x000186a0|",
919 "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
920 /**/ z, z, z, z, z, z, z);
921
922 /* %zd for size_t won't be available on old systems, and running something
923 to see if it works might be bad, so only try it on glibc, and only on a
924 new enough version (glibc 2.0 doesn't have %zd) */
925#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
926 mpz_set_ui (z, 789L);
927 check_one ("456 789 blah", "%zd %Zd blah", (size_t) 456, z);
928#endif
929
930 mpz_clear (z);
931 mpf_clear (f);
932}
933
934
935int
936main (int argc, char *argv[])
937{
938 if (argc > 1 && strcmp (argv[1], "-s") == 0)
939 option_check_printf = 1;
940
941 tests_start ();
942 check_vfprintf_fp = fopen (CHECK_VFPRINTF_FILENAME, "w+");
943 ASSERT_ALWAYS (check_vfprintf_fp != NULL);
944
945 check_z ();
946 check_q ();
947 check_f ();
948 check_limb ();
949 check_n ();
950 check_misc ();
951
952 ASSERT_ALWAYS (fclose (check_vfprintf_fp) == 0);
953 unlink (CHECK_VFPRINTF_FILENAME);
954 tests_end ();
955 exit (0);
956}