1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2019 Keith Packard
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #define _DEFAULT_SOURCE
37 #include <stdio.h>
38 #include <math.h>
39 #include <unistd.h>
40 #include <stdint.h>
41 #include <errno.h>
42 #include <sys/stat.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <stddef.h>
47 #include <wchar.h>
48 #include <locale.h>
49 #include <limits.h>
50 
51 #ifndef __PICOLIBC__
52 # define printf_float(x) ((double) (x))
53 #elif defined(TINY_STDIO)
54 # if defined(PICOLIBC_MINIMAL_PRINTF_SCANF)
55 #  define NO_FLOATING_POINT
56 #  define NO_POS_ARGS
57 #  define NO_MULTI_BYTE
58 #  if !defined(_WANT_MINIMAL_IO_LONG_LONG) && __SIZEOF_LONG_LONG__ > __SIZEOF_LONG__
59 #   define NO_LONG_LONG
60 #  endif
61 #  ifndef _WANT_IO_C99_FORMATS
62 #   define NO_C99_FORMATS
63 #  endif
64 # elif defined(PICOLIBC_INTEGER_PRINTF_SCANF)
65 #  define NO_FLOATING_POINT
66 #  define NO_MULTI_BYTE
67 #  ifndef _WANT_IO_POS_ARGS
68 #   define NO_POS_ARGS
69 #  endif
70 #  if !defined(_WANT_IO_LONG_LONG) && __SIZEOF_LONG_LONG__ > __SIZEOF_LONG__
71 #   define NO_LONG_LONG
72 #  endif
73 #  ifndef _WANT_IO_C99_FORMATS
74 #   define NO_C99_FORMATS
75 #  endif
76 #  ifdef _WANT_IO_PERCENT_B
77 #   define BINARY_FORMAT
78 #  endif
79 # elif defined(PICOLIBC_LONG_LONG_PRINTF_SCANF)
80 #  define NO_FLOATING_POINT
81 #  define NO_MULTI_BYTE
82 #  ifndef _WANT_IO_POS_ARGS
83 #   define NO_POS_ARGS
84 #  endif
85 #  ifndef _WANT_IO_C99_FORMATS
86 #   define NO_C99_FORMATS
87 #  endif
88 #  ifdef _WANT_IO_PERCENT_B
89 #   define BINARY_FORMAT
90 #  endif
91 # elif defined(PICOLIBC_FLOAT_PRINTF_SCANF)
92 #  define NO_MULTI_BYTE
93 #  ifndef _IO_FLOAT_EXACT
94 #   define NO_FLOAT_EXACT
95 #  endif
96 #  ifdef _WANT_IO_PERCENT_B
97 #   define BINARY_FORMAT
98 #  endif
99 # elif defined(PICOLIBC_DOUBLE_PRINTF_SCANF)
100 #  ifndef _HAS_IO_MBCHAR
101 #   define NO_MULTI_BYTE
102 #  endif
103 #  ifndef _IO_FLOAT_EXACT
104 #   define NO_FLOAT_EXACT
105 #  endif
106 #  ifdef _WANT_IO_PERCENT_B
107 #   define BINARY_FORMAT
108 #  endif
109 # endif
110 #else
111 #define printf_float(x) ((double) (x))
112 
113 #ifndef _WIDE_ORIENT
114 #define NO_WIDE_IO
115 #endif
116 
117 #ifndef _WANT_IO_POS_ARGS
118 #define NO_POS_ARGS
119 #endif
120 #if !defined(_WANT_IO_C99_FORMATS) || defined(_NANO_FORMATTED_IO)
121 # define NO_C99_FORMATS
122 #endif
123 
124 #if __SIZEOF_DOUBLE__ != 8
125 #define NO_FLOATING_POINT
126 #endif
127 
128 #ifndef _WANT_IO_LONG_LONG
129 #define NO_LONG_LONG
130 #endif
131 
132 #ifdef _NANO_FORMATTED_IO
133 
134 #ifndef NO_FLOATING_POINT
135 extern int _printf_float();
136 extern int _scanf_float();
137 
138 int (*_reference_printf_float)() = _printf_float;
139 int (*_reference_scanf_float)() = _scanf_float;
140 #endif
141 #endif
142 #endif
143 
144 #if !defined(NO_FLOATING_POINT)
145 static const double test_vals[] = { 1.234567, 1.1, M_PI };
146 #endif
147 
148 static int
check_vsnprintf(char * str,size_t size,const char * format,...)149 check_vsnprintf(char *str, size_t size, const char *format, ...)
150 {
151 	int i;
152 	va_list ap;
153 
154 	va_start(ap, format);
155 	i = vsnprintf(str, size, format, ap);
156 	va_end(ap);
157 	return i;
158 }
159 
160 #if !defined(NO_FLOATING_POINT)
161 #ifdef PICOLIBC_FLOAT_PRINTF_SCANF
162 #define float_type float
163 #define pow(a,b) powf((float) (a), (float) (b))
164 #define nextafter(a,b) nextafterf((float)(a), (float)(b))
165 #define fabs(a) fabsf(a)
166 #define scanf_format "%f"
167 #if (defined(TINY_STDIO) && !defined(_IO_FLOAT_EXACT))
168 #define ERROR_MAX 1e-6
169 #else
170 #define ERROR_MAX 0
171 #endif
172 #else
173 #define float_type double
174 #define scanf_format "%lf"
175 #if defined(TINY_STDIO) && !defined(_IO_FLOAT_EXACT)
176 # if __SIZEOF_DOUBLE__ == 4
177 #  define ERROR_MAX 1e-6
178 # else
179 #  define ERROR_MAX 1e-14
180 # endif
181 #else
182 #if (!defined(TINY_STDIO) && defined(_WANT_IO_LONG_DOUBLE))
183 /* __ldtoa is really broken */
184 #define ERROR_MAX 1e-5
185 #else
186 #define ERROR_MAX 0
187 #endif
188 #endif
189 #endif
190 #endif
191 
192 #if defined(__PICOLIBC__) && !defined(TINYSTDIO)
193 #define LEGACY_NEWLIB
194 #endif
195 
196 #ifndef NO_WIDE_IO
197 static struct {
198     const wchar_t *str;
199     const wchar_t *fmt;
200     int expect;
201 } wtest[] = {
202     { .str = L"foo\n", .fmt = L"foo\nbar", .expect = -1 },
203     { .str = L"foo\n", .fmt = L"foo bar", .expect = -1 },
204     { .str = L"foo\n", .fmt = L"foo %d", .expect = -1 },
205     { .str = L"foo\n", .fmt = L"foo\n%d", .expect = -1 },
206     { .str = L"foon", .fmt = L"foonbar", .expect = -1 },
207     { .str = L"foon", .fmt = L"foon%d", .expect = -1 },
208     { .str = L"foo ", .fmt = L"foo bar", .expect = -1 },
209     { .str = L"foo ", .fmt = L"foo %d", .expect = -1 },
210     { .str = L"foo\t", .fmt = L"foo\tbar", .expect = -1 },
211     { .str = L"foo\t", .fmt = L"foo bar", .expect = -1 },
212     { .str = L"foo\t", .fmt = L"foo %d", .expect = -1 },
213     { .str = L"foo\t", .fmt = L"foo\t%d", .expect = -1 },
214     { .str = L"foo", .fmt = L"foo", .expect = 0 },
215 #ifndef LEGACY_NEWLIB
216     { .str = L"foon", .fmt = L"foo bar", .expect = 0 },
217     { .str = L"foon", .fmt = L"foo %d", .expect = 0 },
218     { .str = L"foo ", .fmt = L"fooxbar", .expect = 0 },
219     { .str = L"foo ", .fmt = L"foox%d", .expect = 0 },
220     { .str = L"foo bar", .fmt = L"foon", .expect = 0 },
221 #endif
222     { .str = L"foo bar", .fmt = L"foo bar", .expect = 0 },
223     { .str = L"foo bar", .fmt = L"foo %d", .expect = 0 },
224 #ifndef LEGACY_NEWLIB
225     { .str = L"foo bar", .fmt = L"foon%d", .expect = 0 },
226 #endif
227     { .str = L"foo (nil)", .fmt = L"foo %4p", .expect = 0},
228     { .str = L"foo ", .fmt = L"foo %n", .expect = 0 },
229     { .str = L"foo%bar1", .fmt = L"foo%%bar%d", 1 },
230     { }
231 };
232 #endif
233 
234 #ifndef NO_FLOATING_POINT
235 
236 static float_type
int_exp10(int n)237 int_exp10(int n)
238 {
239         float_type      a = 1.0;
240         int             sign = n < 0;
241 
242         if (sign)
243                 n = -n;
244         while (n--)
245                 a *= (float_type) 10.0;
246         if (sign)
247                 a = 1/a;
248         return a;
249 }
250 
251 #ifndef NO_FLOAT_EXACT
252 
253 static int
check_float(const char * test_name,float_type a,const char * buf,const char * head,int zeros,const char * tail)254 check_float(const char *test_name, float_type a, const char *buf, const char *head, int zeros, const char *tail)
255 {
256         int z;
257         int o;
258 
259         if (strncmp(buf, head, strlen(head)) != 0)
260                 goto fail;
261 
262         o = strlen(head);
263         for (z = 0; z < zeros; z++) {
264                 if (buf[o] != '0')
265                         goto fail;
266                 o++;
267         }
268 
269         if (strcmp(buf + o, tail) != 0)
270                 goto fail;
271         return 0;
272 
273 fail:
274         printf("float mismatch test %s: %a %.17e \"%s\" isn't in the form \"%s\", %d zeros, \"%s\"\n",
275                test_name, printf_float(a), printf_float(a), buf, head, zeros, tail);
276         return 1;
277 }
278 
279 #endif
280 #endif
281 
282 int
main(void)283 main(void)
284 {
285 	int x = -35;
286 	int y;
287 	char	buf[256];
288 	int	errors = 0;
289 
290 #if !defined(__PICOLIBC__) || defined(_MB_CAPABLE)
291         if (!setlocale(LC_CTYPE, "C.UTF-8")) {
292             printf("setlocale(LC_CTYPE, \"C.UTF-8\") failed\n");
293             return 1;
294         }
295 #endif
296 #if 0
297 	double	a;
298 
299 	printf ("hello world\n");
300 	for (x = 1; x < 20; x++) {
301 		printf("%.*f\n", x, 9.99999999999);
302 	}
303 
304 	for (a = 1e-10; a < 1e10; a *= 10.0) {
305 		printf("g format: %10.3g %10.3g\n", 1.2345678 * a, 1.1 * a);
306 		fflush(stdout);
307 	}
308 	for (a = 1e-10; a < 1e10; a *= 10.0) {
309 		printf("f format: %10.3f %10.3f\n", 1.2345678 * a, 1.1 * a);
310 		fflush(stdout);
311 	}
312 	for (a = 1e-10; a < 1e10; a *= 10.0) {
313 		printf("e format: %10.3e %10.3e\n", 1.2345678 * a, 1.1 * a);
314 		fflush(stdout);
315 	}
316 	printf ("%g\n", exp(11));
317 #endif
318 
319 #ifndef NO_WIDE_IO
320         unsigned wt;
321         for (wt = 0; wtest[wt].str; wt++) {
322             void *extra;
323             int wtr = swscanf(wtest[wt].str, wtest[wt].fmt, &extra);
324             if (wtr != wtest[wt].expect) {
325                 printf("%d str %ls fmt %ls expected %d got %d\n", wt,
326                        wtest[wt].str, wtest[wt].fmt, wtest[wt].expect, wtr);
327                 ++errors;
328             }
329         }
330 #ifndef NO_MULTI_BYTE
331         {
332             wchar_t c;
333             char test_val[] = "㌰";
334             int i = sscanf(test_val, "%lc", &c);
335             if (i != 1 || c != L'㌰') {
336                 printf("%d: %lc != %s or %d != 1\n", __LINE__, (wint_t) c, test_val, i);
337                 ++errors;
338             }
339             wchar_t wtest_val[] = L"㌰";
340             char c_mb[MB_LEN_MAX+1] = {0};
341             i = swscanf(wtest_val, L"%c", c_mb);
342             if (i != 1 || strcmp(c_mb, test_val) != 0) {
343                 printf("%d: %s != %s or %d != 1\n", __LINE__, c_mb, test_val, i);
344                 ++errors;
345             }
346         }
347 #endif
348 #endif
349 
350 #if !defined(NO_FLOATING_POINT)
351         printf("checking floating point\n");
352 	sprintf(buf, "%g", printf_float(0.0f));
353 	if (strcmp(buf, "0") != 0) {
354 		printf("0: wanted \"0\" got \"%s\"\n", buf);
355 		errors++;
356 		fflush(stdout);
357 	}
358 #endif
359 
360 #ifndef NO_POS_ARGS
361         printf("checking pos args\n");
362         x = y = 0;
363         int r = sscanf("3 4", "%2$d %1$d", &x, &y);
364         if (x != 4 || y != 3 || r != 2) {
365             printf("pos: wanted %d %d (ret %d) got %d %d (ret %d)\n", 4, 3, 2, x, y, r);
366             errors++;
367             fflush(stdout);
368         }
369 #endif
370 
371 	/*
372 	 * test snprintf and vsnprintf to make sure they don't
373 	 * overwrite the specified buffer length (even if that is
374 	 * zero)
375 	 */
376 	for (x = 0; x <= 6; x++) {
377 		for (y = 0; y < 2; y++) {
378 			char tbuf[10] = "xxxxxxxxx";
379 			const char ref[10] = "xxxxxxxxx";
380 			const char *name = (y == 0 ? "snprintf" : "vsnprintf");
381 			int i = (y == 0 ? snprintf : check_vsnprintf) (tbuf, x, "%s", "123");
382 			int y = x <= 4 ? x : 4;
383 			if (i != 3) {
384 				printf("%s(tbuf, %d, \"%%s\", \"123\") return %d instead of %d\n", name,
385 				       x, i, 3);
386 				errors++;
387 			}
388 			int l = strlen(tbuf);
389 			if (y > 0 && l != y - 1) {
390 				printf("%s: returned buffer len want %d got %d\n", name, y - 1, l);
391 				errors++;
392 			}
393 			if (y > 0 && strncmp(tbuf, "123", y - 1) != 0) {
394 #pragma GCC diagnostic ignored "-Wpragmas"
395 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
396 #pragma GCC diagnostic ignored "-Wstringop-truncation"
397 				strncpy(buf, "123", y - 1);
398 				buf[y-1] = '\0';
399 				printf("%s: returned buffer want %s got %s\n", name, buf, tbuf);
400 				errors++;
401 			}
402 			if (memcmp(tbuf + y, ref + y, sizeof(tbuf) - y) != 0) {
403 				printf("%s: tail of buf mangled %s\n", name, tbuf + y);
404 				errors++;
405 			}
406 		}
407 	}
408 
409 #define FMT(prefix,conv) "%" prefix conv
410 
411 #define VERIFY_BOTH(prefix, oconv, iconv) do {                          \
412             int __n;                                                    \
413             sprintf(buf, FMT(prefix, oconv), v);                        \
414             __n = sscanf(buf, FMT(prefix, iconv), &r);                  \
415             if (v != r || __n != 1) {                                   \
416                 printf("\t%3d: " prefix " " oconv " wanted " FMT(prefix, oconv) " got " FMT(prefix, oconv) "\n", x, v, r); \
417                 errors++;                                               \
418                 fflush(stdout);                                         \
419             }                                                           \
420         } while(0)
421 
422 #define VERIFY(prefix, conv) VERIFY_BOTH(prefix, conv, conv)
423 
424 #ifdef BINARY_FORMAT
425         printf("checking binary format\n");
426 #define VERIFY_BINARY(prefix) VERIFY(prefix, "b")
427 #pragma GCC diagnostic ignored "-Wformat"
428 #pragma GCC diagnostic ignored "-Wformat-extra-args"
429 #else
430 #define VERIFY_BINARY(prefix)
431 #endif
432 
433 #define CHECK_RT(type, prefix) do {                                     \
434         for (x = 0; x < (int) (sizeof(type) * 8); x++) {                \
435                 type v = (type) (0x123456789abcdef0LL >> (64 - sizeof(type) * 8)) >> x; \
436                 type r = ~v;                                            \
437                 VERIFY(prefix, "d");                                    \
438                 r = ~v;                                                 \
439                 VERIFY(prefix, "u");                                    \
440                 r = ~v;                                                 \
441                 VERIFY(prefix, "x");                                    \
442                 r = ~v;                                                 \
443                 VERIFY(prefix, "o");                                    \
444                 r = ~v;                                                 \
445                 VERIFY_BINARY(prefix);                                  \
446         }                                                               \
447         } while(0)
448 
449 #ifndef _NANO_FORMATTED_IO
450 	CHECK_RT(unsigned char, "hh");
451 #endif
452 	CHECK_RT(unsigned short, "h");
453         CHECK_RT(unsigned int, "");
454         CHECK_RT(unsigned long, "l");
455 #ifndef NO_LONG_LONG
456         printf("checking long long\n");
457         CHECK_RT(unsigned long long, "ll");
458 #endif
459 #ifndef NO_C99_FORMATS
460         printf("checking c99 formats\n");
461 #ifdef NO_LONG_LONG
462 	if (sizeof(intmax_t) <= sizeof(long))
463 #endif
464 	{
465 	        CHECK_RT(intmax_t, "j");
466 	}
467         CHECK_RT(size_t, "z");
468         CHECK_RT(ptrdiff_t, "t");
469 #endif
470 
471         {
472             static int i_addr = 12;
473             void *v = &i_addr;
474             void *r = (void *) -1;
475             VERIFY("", "p");
476         }
477 #if !defined(NO_FLOATING_POINT)
478 
479 #ifndef NO_FLOAT_EXACT
480         for (x = 0; x < 37; x++) {
481                 float_type m, n, a, b, c;
482                 float_type pow_val = int_exp10(x);
483 
484                 m = 1 / pow_val;
485                 n = m / (float_type) 2.0;
486 
487                 a = n;
488                 b = n;
489                 c = m;
490 
491                 /* Make sure the values are on the right side of the rounding value */
492                 for (y = 0; y < 5; y++) {
493                         a = nextafter(a, 2.0);
494                         b = nextafter(b, 0.0);
495                         c = nextafter(c, 0.0);
496                 }
497 
498                 /*
499                  * A value greater than 5 just past the last digit
500                  * rounds up to 0.0...1
501                  */
502                 sprintf(buf, "%.*f", x, printf_float(a));
503                 if (x == 0)
504                         errors += check_float(">= 0.5", a, buf, "1", x, "");
505                 else
506                         errors += check_float(">= 0.5", a, buf, "0.", x-1, "1");
507 
508                 /*
509                  * A value greater than 5 in the last digit
510                  * rounds to 0.0...5
511                  */
512                 sprintf(buf, "%.*f", x+1, printf_float(a));
513                 errors += check_float(">= 0.5", a, buf, "0.", x, "5");
514 
515                 /*
516                  * A value less than 5 just past the last digit
517                  * rounds down to 0.0...0
518                  */
519                 sprintf(buf, "%.*f", x, printf_float(b));
520                 if (x == 0)
521                         errors += check_float("< 0.5", b, buf, "0", x, "");
522                 else
523                         errors += check_float("< 0.5", b, buf, "0.", x, "");
524 
525                 /*
526                  * A value less than 5 in the last digit
527                  * rounds to 0.0...5
528                  */
529                 sprintf(buf, "%.*f", x+1, printf_float(b));
530                 errors += check_float("< 0.5", b, buf, "0.", x, "5");
531 
532                 /*
533                  * A value less than 1 in the last digit
534                  * rounds to 0.0...1
535                  */
536                 sprintf(buf, "%.*f", x, printf_float(c));
537                 if (x == 0)
538                         errors += check_float("< 1", c, buf, "1", x, "");
539                 else
540                         errors += check_float("< 1", c, buf, "0.", x-1, "1");
541         }
542 #endif
543 
544 	for (x = -37; x <= 37; x++)
545 	{
546                 float_type r;
547 		unsigned t;
548 		for (t = 0; t < sizeof(test_vals)/sizeof(test_vals[0]); t++) {
549 
550 			float_type v = (float_type) test_vals[t] * int_exp10(x);
551 			float_type e;
552 
553 			sprintf(buf, "%.55f", printf_float(v));
554 			sscanf(buf, scanf_format, &r);
555 			e = fabs(v-r) / v;
556 			if (e > (float_type) ERROR_MAX) {
557 				printf("\tf %3d: wanted %.7e %a got %.7e %a (error %.7e %a, buf %s)\n", x,
558 				       printf_float(v), printf_float(v),
559                                        printf_float(r), printf_float(r),
560                                        printf_float(e), printf_float(e),
561                                        buf);
562 				errors++;
563 				fflush(stdout);
564 			}
565 
566 
567 			sprintf(buf, "%.20e", printf_float(v));
568 			sscanf(buf, scanf_format, &r);
569 			e = fabs(v-r) / v;
570 			if (e > (float_type) ERROR_MAX)
571 			{
572 				printf("\te %3d: wanted %.7e got %.7e (error %.7e, buf %s)\n", x,
573 				       printf_float(v), printf_float(r), printf_float(e), buf);
574 				errors++;
575 				fflush(stdout);
576 			}
577 
578 
579 			sprintf(buf, "%.20g", printf_float(v));
580 			sscanf(buf, scanf_format, &r);
581 			e = fabs(v-r) / v;
582 			if (e > (float_type) ERROR_MAX)
583 			{
584 				printf("\tg %3d: wanted %.7e got %.7e (error %.7e, buf %s)\n", x,
585 				       printf_float(v), printf_float(r), printf_float(e), buf);
586 				errors++;
587 				fflush(stdout);
588 			}
589 
590 #ifndef NO_C99_FORMATS
591 			sprintf(buf, "%.20a", printf_float(v));
592 			sscanf(buf, scanf_format, &r);
593 			e = fabs(v-r) / v;
594 			if (e > (float_type) ERROR_MAX)
595 			{
596 				printf("\ta %3d: wanted %.7e got %.7e (error %.7e, buf %s)\n", x,
597 				       printf_float(v), printf_float(r), printf_float(e), buf);
598 				errors++;
599 				fflush(stdout);
600 			}
601 #endif
602 
603 		}
604 #ifndef NO_C99_FORMATS
605                 sprintf(buf, "0x0.0p%+d", x);
606                 sscanf(buf, scanf_format, &r);
607                 if (r != (float_type) 0.0)
608                 {
609                     printf("\tg %3d: wanted 0.0 got %.7e (buf %s)\n", x,
610                            printf_float(r), buf);
611                     errors++;
612                     fflush(stdout);
613                 }
614 
615                 sprintf(buf, "0x1p%+d", x);
616                 sscanf(buf, scanf_format, &r);
617                 if (r != (float_type) ldexp(1.0, x))
618                 {
619                     printf("\tg %3d: wanted 1 got %.7e (buf %s)\n", x,
620                            printf_float(r), buf);
621                     errors++;
622                     fflush(stdout);
623                 }
624 #endif
625 	}
626 #endif
627 	fflush(stdout);
628 	return errors;
629 }
630