1 /*
2 * Copyright (c) 1994 Cygnus Support.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * and/or other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * at Cygnus Support, Inc. Cygnus Support, Inc. may not be used to
11 * endorse or promote products derived from this software without
12 * specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17 /* Test conversions */
18
19 #define _GNU_SOURCE
20 #include "test.h"
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <string.h>
24
25 static char buffer[500];
26
27 extern double_type doubles[];
28
29 //#define GENERATE_VECTORS
30
31 /* TEST ATOF ATOFF */
32
33 double_type *pd = doubles;
34
35 #ifdef _IO_FLOAT_EXACT
36 #if !defined(TINYSTDIO) && defined(__m68k__) && !defined(__mcf_fpu__) && !defined(__HAVE_M68881__)
37 /* soft floats on m68k have rounding bugs for 64-bit values */
38 #define CONVERT_BITS_DOUBLE 63
39 #else
40 #define CONVERT_BITS_DOUBLE 64
41 #endif
42 #define CONVERT_BITS_FLOAT 32
43 #else
44 #define CONVERT_BITS_DOUBLE 58
45 #define CONVERT_BITS_FLOAT 28
46 #endif
47
48 static void
test_strtod(void)49 test_strtod (void)
50 {
51 char *tail;
52 double v;
53 /* On average we'll loose 1/2 a bit, so the test is for within 1 bit */
54 errno = 0;
55 v = strtod(pd->string, &tail);
56 if (tail - pd->string) {
57 if (fabs(v) < DBL_MIN && !(pd->endscan & ENDSCAN_IS_ZERO)) {
58 #ifdef NO_NEWLIB
59 /* Glibc has bugs in strtod with hex format float */
60 if (strncasecmp(pd->string, "0x", 2) == 0)
61 ;
62 else
63 #endif
64 test_eok(errno, ERANGE);
65 } else if (isinf(v) && !(pd->endscan & ENDSCAN_IS_INF))
66 test_eok(errno, ERANGE);
67 else
68 test_eok(errno, 0);
69 }
70 test_mok(v, pd->value, CONVERT_BITS_DOUBLE);
71 test_iok(tail - pd->string, pd->endscan & ENDSCAN_MASK);
72 }
73
74 static void
test_strtof(void)75 test_strtof (void)
76 {
77 char *tail;
78 float v;
79 /* On average we'll loose 1/2 a bit, so the test is for within 1 bit */
80 errno = 0;
81 v = strtof(pd->string, &tail);
82 if (tail - pd->string) {
83 int e = errno;
84 if (fabsf(v) < FLT_MIN && !(pd->endscan & ENDSCAN_IS_ZERO))
85 test_eok(e, ERANGE);
86 else if (isinf(v) && !(pd->endscan & ENDSCAN_IS_INF))
87 test_eok(errno, ERANGE);
88 else
89 test_eok(errno, 0);
90 }
91 test_mfok((double) v, pd->value, CONVERT_BITS_FLOAT);
92 test_iok(tail - pd->string, pd->endscan & ENDSCAN_MASK);
93 }
94
95 #if defined(_TEST_LONG_DOUBLE) && (__LDBL_MANT_DIG__ == 64 || defined(TINY_STDIO))
96 #define HAVE_STRTOLD
97 #endif
98
99 #ifdef __m68k__
100 #define STRTOLD_TEST_BITS (CONVERT_BITS_DOUBLE > 63 ? 63 : CONVERT_BITS_DOUBLE)
101 #else
102 #define STRTOLD_TEST_BITS CONVERT_BITS_DOUBLE
103 #endif
104
105 #ifdef HAVE_STRTOLD
106 static void
test_strtold(void)107 test_strtold (void)
108 {
109 char *tail;
110 long double v, av;
111 /* On average we'll loose 1/2 a bit, so the test is for within 1 bit */
112 errno = 0;
113 v = strtold(pd->string, &tail);
114 if (tail - pd->string) {
115 int e = errno;
116 av = v;
117 if (av < 0)
118 av = -av;
119 if (av < LDBL_MIN && !(pd->endscan & ENDSCAN_IS_ZERO))
120 test_eok(e, ERANGE);
121 else if (isinf(av) && !(pd->endscan & ENDSCAN_IS_INF))
122 test_eok(e, ERANGE);
123 else
124 test_eok(e, 0);
125 }
126 test_mok(v, pd->value, STRTOLD_TEST_BITS);
127 test_iok(tail - pd->string, pd->endscan & ENDSCAN_MASK);
128 }
129 #endif
130
131 static void
test_atof(void)132 test_atof (void)
133 {
134 test_mok(atof(pd->string), pd->value, CONVERT_BITS_DOUBLE);
135 }
136
137 #ifndef NO_NEWLIB
138 static void
test_atoff(void)139 test_atoff (void)
140 {
141 float v = atoff(pd->string);
142 test_mfok(v, (float) pd->value, CONVERT_BITS_FLOAT);
143 }
144 #endif
145
146
147 static
148 void
iterate(void (* func)(void),char * name)149 iterate (void (*func) (void),
150 char *name)
151 {
152 pd = doubles;
153 if (!pd->string)
154 return;
155
156 newfunc(name);
157 while (pd->string) {
158 line(pd->line);
159 func();
160 pd++;
161 }
162 }
163
164
165 extern int_type ints[];
166
167 int_type *p = ints;
168
169
170 static void
int_iterate(void (* func)(),char * name)171 int_iterate (void (*func)(),
172 char *name)
173 {
174 p = ints;
175 if (!p->string)
176 return;
177
178 newfunc(name);
179
180 while (p->string) {
181 line(p->line);
182 errno = 0;
183 func();
184 p++;
185 }
186 }
187
188 static void
test_strtol_base(int base,int_scan_type * pi,char * string)189 test_strtol_base (int base,
190 int_scan_type *pi,
191 char *string)
192 {
193 long r;
194 char *ptr;
195 errno = 0;
196 r = strtol(string, &ptr, base);
197 test_iok(r, pi->value);
198 test_eok(errno, pi->errno_val);
199 test_iok(ptr - string, pi->end);
200 }
201
202 static void
test_strtol(void)203 test_strtol (void)
204 {
205 test_strtol_base(8,&(p->octal), p->string);
206 test_strtol_base(10,&(p->decimal), p->string);
207 test_strtol_base(16, &(p->hex), p->string);
208 test_strtol_base(0, &(p->normal), p->string);
209 test_strtol_base(26, &(p->alphabetical), p->string);
210 }
211
212 static void
test_atoi(void)213 test_atoi (void)
214 {
215 if (p->decimal.errno_val == 0)
216 test_iok(atoi(p->string), p->decimal.value);
217 }
218
219 static void
test_atol(void)220 test_atol (void)
221 {
222 test_iok(atol(p->string), p->decimal.value);
223 test_eok(errno, p->decimal.errno_val);
224 }
225
226 extern ddouble_type ddoubles[];
227 ddouble_type *pdd;
228
229 static inline char *
check_null(char * s)230 check_null(char *s) {
231 if (s == NULL)
232 return "(out of memory)";
233 return s;
234 }
235
236 #if !defined(TINY_STDIO) && !defined(NO_NEWLIB)
237 #define ecvt_r(n, dig, dec, sign, buf, len) (ecvtbuf(n, dig, dec, sign, buf) ? 0 : -1)
238 #define fcvt_r(n, dig, dec, sign, buf, len) (fcvtbuf(n, dig, dec, sign, buf) ? 0 : -1)
239 #define ecvtf_r(n, dig, dec, sign, buf, len) (ecvtbuf(n, dig, dec, sign, buf) ? 0 : -1)
240 #define fcvtf_r(n, dig, dec, sign, buf, len) (fcvtbuf(n, dig, dec, sign, buf) ? 0 : -1)
241 #endif
242
243 /* test ECVT and friends */
244 static void
test_ecvt_r(void)245 test_ecvt_r (void)
246 {
247 int a2,a3;
248 int r;
249
250 r = ecvt_r(pdd->value, pdd->e1, &a2, &a3, buffer, sizeof(buffer));
251 test_iok(0, r);
252
253 test_sok(buffer,pdd->estring);
254 test_iok(pdd->e2,a2);
255 test_iok(pdd->e3,a3);
256
257 #ifndef NO_NEWLIB
258 r = ecvtf_r(pdd->value, pdd->e1, &a2, &a3, buffer, sizeof(buffer));
259 test_iok(0, r);
260
261 test_scok(buffer,pdd->estring, 6);
262 test_iok(pdd->e2,a2);
263 test_iok(pdd->e3,a3);
264 #endif
265 }
266
267 static void
test_ecvt(void)268 test_ecvt (void)
269 {
270 int a2,a3;
271 char *s;
272 s = check_null(ecvt(pdd->value, pdd->e1, &a2, &a3));
273
274 test_sok(s,pdd->estring);
275 test_iok(pdd->e2,a2);
276 test_iok(pdd->e3,a3);
277
278 #ifndef NO_NEWLIB
279 s = check_null(ecvtf(pdd->value, pdd->e1, &a2, &a3));
280
281 test_scok(s,pdd->estring, 6);
282 test_iok(pdd->e2,a2);
283 test_iok(pdd->e3,a3);
284 #endif
285 }
286
287 static void
test_fcvt_r(void)288 test_fcvt_r (void)
289 {
290 int a2,a3;
291 int r;
292 r = fcvt_r(pdd->value, pdd->f1, &a2, &a3, buffer, sizeof(buffer));
293
294 test_iok(r, 0);
295 test_scok(buffer,pdd->fstring,10);
296 test_iok(pdd->f2,a2);
297 test_iok(pdd->f3,a3);
298
299 #ifndef NO_NEWLIB
300 double v1;
301 double v2;
302 static char fbuffer[sizeof(buffer)];
303 char *sde, *sfe;
304 /* Test the float version by converting and inspecting the numbers 3
305 after reconverting */
306 r = fcvtf_r(pdd->value, pdd->f1, &a2, &a3, fbuffer, sizeof(fbuffer));
307 test_iok(0, r);
308 errno = 0;
309 v1 = strtod(buffer, &sde);
310 v2 = strtod(fbuffer, &sfe);
311 /* float version may return fewer digits; expand to match */
312 int x = strlen(buffer) - strlen(fbuffer);
313 while (x-- > 0)
314 v2 *= 10;
315 if (strlen(buffer) == 0) {
316 test_iok(0, sde - buffer);
317 v1 = 0.0;
318 }
319 if (strlen(fbuffer) == 0) {
320 test_iok(0, sfe - fbuffer);
321 v2 = 0.0;
322 }
323 test_mok(v1, v2,30);
324 test_iok(pdd->f2,a2);
325 test_iok(pdd->f3,a3);
326 #endif
327 }
328
329 static void
test_gcvt(void)330 test_gcvt (void)
331 {
332 char *s = check_null(gcvt(pdd->value, pdd->g1, buffer));
333 test_scok(s, pdd->gstring, 9);
334
335 #ifndef NO_NEWLIB
336 s = check_null(gcvtf(pdd->value, pdd->g1, buffer));
337 test_scok2(s, pdd->gstring, pdd->gfstring, 6);
338 #endif
339 }
340
341 static void
test_fcvt(void)342 test_fcvt (void)
343 {
344 int a2,a3;
345 char *sd;
346 sd = check_null(fcvt(pdd->value, pdd->f1, &a2, &a3));
347
348 test_scok(sd,pdd->fstring,10);
349 test_iok(pdd->f2,a2);
350 test_iok(pdd->f3,a3);
351
352 #ifndef NO_NEWLIB
353 char *sf;
354 double v1;
355 double v2;
356 char *sde, *sfe;
357 /* Test the float version by converting and inspecting the numbers 3
358 after reconverting */
359 sf = check_null(fcvtf(pdd->value, pdd->f1, &a2, &a3));
360 errno = 0;
361 v1 = strtod(sd, &sde);
362 v2 = strtod(sf, &sfe);
363 /* float version may return fewer digits; expand to match */
364 int x = strlen(sd) - strlen(sf);
365 while (x-- > 0)
366 v2 *= 10;
367 if (strlen(sd) == 0) {
368 test_iok(0, sde - sd);
369 v1 = 0.0;
370 }
371 if (strlen(sf) == 0) {
372 test_iok(0, sfe - sf);
373 v2 = 0.0;
374 }
375 test_mok(v1, v2,30);
376 test_iok(pdd->f2,a2);
377 test_iok(pdd->f3,a3);
378 #endif
379 }
380
381 static void
diterate(void (* func)(),char * name)382 diterate (void (*func)(),
383 char *name)
384 {
385 pdd = ddoubles;
386 if (!pdd->estring)
387 return;
388
389 newfunc(name);
390
391 while (pdd->estring) {
392 line(pdd->line);
393 errno = 0;
394 func();
395 pdd++;
396 }
397 }
398
399 #if TEST_PART ==1 || TEST_PART == -1
400 static void
deltest(void)401 deltest (void)
402 {
403 #if defined(TINY_STDIO) || !defined(NO_FLOATING_POINT)
404 newfunc("rounding");
405 line(1);
406 sprintf(buffer,"%.2f", 9.999);
407 test_sok(buffer,"10.00");
408 line(2);
409 sprintf(buffer,"%.2g", 1.0);
410 test_sok(buffer,"1");
411 line(3);
412 sprintf(buffer,"%.2g", 1.2e-6);
413 test_sok(buffer,"1.2e-06");
414 line(4);
415 sprintf(buffer,"%.0g", 1.0);
416 test_sok(buffer,"1");
417 line(5);
418 sprintf(buffer,"%.0e",1e1);
419 test_sok(buffer,"1e+01");
420 line(6);
421 sprintf(buffer, "%f", 12.3456789);
422 test_sok(buffer, "12.345679");
423 line(7);
424 sprintf(buffer, "%6.3f", 12.3456789);
425 test_sok(buffer, "12.346");
426 line(8);
427 sprintf(buffer,"%.0f", 12.3456789);
428 test_sok(buffer,"12");
429 #endif
430 }
431
432 /* Most of what sprint does is tested with the tests of
433 fcvt/ecvt/gcvt, but here are some more */
434 static void
test_sprint(void)435 test_sprint (void)
436 {
437 #if defined(TINY_STDIO) || !defined(NO_FLOATING_POINT)
438 extern sprint_double_type sprint_doubles[];
439 sprint_double_type *s = sprint_doubles;
440 #endif
441 extern sprint_int_type sprint_ints[];
442 sprint_int_type *si = sprint_ints;
443
444
445 newfunc( "sprintf");
446
447
448 #if defined(TINY_STDIO) || !defined(NO_FLOATING_POINT)
449 while (s->line)
450 {
451 line( s->line);
452 sprintf(buffer, s->format_string, s->value);
453 #ifdef GENERATE_VECTORS
454 if (s->mag)
455 printf("{__LINE__, %.15e,\t\"%s\", \"%s\", %d },\n",
456 s->value, buffer, s->format_string, s->mag);
457 else
458 printf("{__LINE__, %.15e,\t\"%s\", \"%s\" },\n",
459 s->value, buffer, s->format_string);
460 #else
461 test_scok(buffer, s->result, 12); /* Only check the first 12 digs,
462 other stuff is random */
463 #endif
464 s++;
465 }
466 #endif
467
468 #ifdef GENERATE_VECTORS
469 int c = 0;
470 int q = 1;
471 #endif
472 while (si->line)
473 {
474 line( si->line);
475 if (strchr(si->format_string, 'l'))
476 sprintf(buffer, si->format_string, (long) si->value);
477 else
478 sprintf(buffer, si->format_string, si->value);
479 #ifdef GENERATE_VECTORS
480 static char sbuffer[500];
481 static char sformat[1024];
482 char *df = si->format_string;
483 char *sf = sformat;
484 int size = 0;
485 while (*df) {
486 switch (*df) {
487 case 'd':
488 case 'x':
489 case 'X':
490 case 'o':
491 if (!size) {
492 *sf++ = 'h';
493 size = 2;
494 }
495 break;
496 case 'l':
497 size = 1;
498 break;
499 }
500 *sf++ = *df++;
501 }
502 *sf = '\0';
503 sprintf(sbuffer, sformat, (short) si->value);
504 if (strcmp(sbuffer, buffer) && size != 1) {
505 snprintf(sformat, sizeof(sformat), "I(\"%s\", \"%s\")", buffer, sbuffer);
506 } else {
507 snprintf(sformat, sizeof(sformat), "\"%s\"", buffer);
508 }
509 if (c == 0) {
510 printf("#if TEST_PART == %d || TEST_PART == -1\n", q);
511 q++;
512 }
513 if (si->value < 0)
514 printf("{__LINE__, -%#09xl, %s, \"%s\", },\n",
515 -si->value, sformat, si->format_string);
516 else
517 printf("{__LINE__, %#010xl, %s, \"%s\", },\n",
518 si->value, sformat, si->format_string);
519 c++;
520 if (c == 511 || !si[1].line) {
521 printf("#endif\n");
522 c = 0;
523 }
524 #else
525 test_sok(buffer, si->result);
526 #endif
527 si++;
528 }
529 }
530
531 /* Scanf calls strtod etc tested elsewhere, but also has some pattern matching skills */
532 static void
test_scan(void)533 test_scan (void)
534 {
535 int i,j;
536 #if defined(TINY_STDIO) || !defined(NO_FLOATING_POINT)
537 extern sprint_double_type sprint_doubles[];
538 sprint_double_type *s = sprint_doubles;
539 #endif
540 extern sprint_int_type sprint_ints[];
541 sprint_int_type *si = sprint_ints;
542
543 newfunc( "scanf");
544
545 #if defined(TINY_STDIO) || !defined(NO_FLOATING_POINT)
546 /* Test scanf by converting all the numbers in the sprint vectors
547 to and from their source and making sure nothing breaks */
548
549 while (s->line)
550 {
551
552 double d0,d1;
553 line( s->line);
554 sscanf(s->result, "%lg", &d0);
555 sprintf(buffer, "%.16e", d0);
556 sscanf(buffer, "%lg", &d1);
557 if (s->mag && s->mag < CONVERT_BITS_DOUBLE)
558 test_mok(d0, d1, s->mag);
559 else
560 test_mok(d0,d1, CONVERT_BITS_DOUBLE);
561 s++;
562 }
563 #endif
564
565 /* And integers too */
566 while (si->line)
567 {
568
569 long d0,d1;
570
571 line(si->line);
572 sscanf(si->result, "%ld", &d0);
573 sprintf(buffer, "%ld", d0);
574 sscanf(buffer, "%ld", &d1);
575 test_iok(d0,d1);
576 si++;
577 }
578
579 /* And the string matching */
580
581 sscanf(" 9","%d", &i);
582 test_iok(i, 9);
583 sscanf("foo bar 123 zap 456","foo bar %d zap %d", &i, &j);
584 test_iok(i, 123);
585 test_iok(j, 456);
586
587 sscanf("magicXYZZYfoobar","magic%[XYZ]", buffer);
588 test_sok("XYZZY", buffer);
589 sscanf("magicXYZZYfoobar","%[^XYZ]", buffer);
590 test_sok("magic", buffer);
591 }
592 #endif
593
594 #ifdef GENERATE_VECTORS
595 static void
gen_dvec(void)596 gen_dvec(void)
597 {
598 char ebuf[128];
599 char fbuf[128];
600 char gbuf[128];
601 int e_decpt, e_sign;
602 int f_decpt, f_sign;
603
604 strcpy(ebuf, check_null(ecvt(pdd->value, pdd->e1, &e_decpt, &e_sign)));
605 strcpy(fbuf, check_null(fcvt(pdd->value, pdd->f1, &f_decpt, &f_sign)));
606 check_null(gcvt(pdd->value, pdd->g1, gbuf));
607 printf("__LINE__, %.15e,\"%s\",%d,%d,%d,\"%s\",%d,%d,%d,\"%s\",%d,\n\n",
608 pdd->value,
609 ebuf, pdd->e1, e_decpt, e_sign,
610 fbuf, pdd->f1, f_decpt, f_sign,
611 gbuf, pdd->g1);
612 }
613 #endif
614
615 extern int _malloc_test_fail;
616
617 void
test_cvt(void)618 test_cvt (void)
619 {
620 #ifdef GENERATE_VECTORS
621 diterate(gen_dvec, "gen");
622 #else
623 diterate(test_fcvt_r,"fcvt_r");
624 diterate(test_fcvt,"fcvt/fcvtf");
625
626 diterate(test_gcvt,"gcvt/gcvtf");
627 diterate(test_ecvt_r,"ecvt_r");
628 diterate(test_ecvt,"ecvt/ecvtf");
629 #endif
630
631 iterate(test_strtod, "strtod");
632 #ifdef HAVE_STRTOLD
633 #ifdef __m68k__
634 volatile long double zero = 0.0L;
635 volatile long double one = 1.0L;
636 volatile long double check = nextafterl(zero, one);
637 if (check + check == zero) {
638 printf("m68k emulating long double with double, skipping\n");
639 } else
640 #endif
641 iterate(test_strtold, "strtold");
642 #endif
643
644 #if TEST_PART ==1 || TEST_PART == -1
645 deltest();
646 test_scan();
647 test_sprint();
648 #endif
649 iterate(test_atof, "atof");
650 #ifndef NO_NEWLIB
651 iterate(test_atoff, "atoff");
652 #endif
653
654 iterate(test_strtof, "strtof");
655
656 int_iterate(test_atoi,"atoi");
657 if (sizeof(int) == sizeof(long)) {
658 int_iterate(test_atol,"atol");
659 int_iterate(test_strtol, "strtol");
660 }
661 }
662