1 /* Test gmp_printf and related functions.
2
3 Copyright 2001-2003, 2015 Free Software Foundation, Inc.
4
5 This file is part of the GNU MP Library test suite.
6
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 Public License for more details.
16
17 You should have received a copy of the GNU General Public License along with
18 the 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
58 int option_check_printf = 0;
59
60
61 #define CHECK_VFPRINTF_FILENAME "t-printf.tmp"
62 FILE *check_vfprintf_fp;
63
64
65 /* From any of the tests run here. */
66 #define MAX_OUTPUT 1024
67
68
69 void
check_plain(const char * want,const char * fmt_orig,...)70 check_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
131 void
check_vsprintf(const char * want,const char * fmt,va_list ap)132 check_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
152 void
check_vfprintf(const char * want,const char * fmt,va_list ap)153 check_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
190 void
check_vsnprintf(const char * want,const char * fmt,va_list ap)191 check_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
246 void
check_vasprintf(const char * want,const char * fmt,va_list ap)247 check_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
268 void
check_obstack_vprintf(const char * want,const char * fmt,va_list ap)269 check_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
301 void
check_one(const char * want,const char * fmt,...)302 check_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
321 void
check_z(void)322 check_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
432 void
check_q(void)433 check_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
539 void
check_f(void)540 check_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
702 void
check_limb(void)703 check_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
739 void
check_n(void)740 check_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
854 void
check_misc(void)855 check_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
935 int
main(int argc,char * argv[])936 main (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 }
957