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