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