Sophie

Sophie

distrib > Mageia > 1 > i586 > by-pkgid > 03bdd856d84db3146de6a56ce373d107 > files > 32

dietlibc-0.32-4.20090113.6.mga1.src.rpm

From 313a9b41133ca631890de99f979ee01074d0c0be Mon Sep 17 00:00:00 2001
From: Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Date: Sat, 19 Apr 2008 17:39:23 +0200
Subject: [PATCH] Fixes/enhancements for INF/NAN handling in printf()

This patch adds support for uppercase 'F' and 'G' printf format
specifiers.  It fixes handling of -INF values in __dtostr() too;
previously, there was

| unsigned int i;
| if ((i=isinf(d))) return copystring(buf,maxlen,i>0?"inf":"-inf");
                                                 ~~~
which evaluated to true everytime. The copystring() function
worked for 3-letter words only but not for '-inf'.

The last argument of __dtostr() was changed from a boolean flag to
a bitmask. Bit 0 encodes 'g' or 'f', and bit 1 lower-/uppercase.
There should be probably added some macros for them; for now,
these values are used directly.

Please note that this might affect other applications (liblowfat?)
too which are using __dtostr().

'isinf(3)' is a builtin with gcc 4.3 and does not give a hint
about the signess of the infinity anymore. Hence, this patch uses
a more portable way where needed.
---
 include/stdlib.h |    6 ++++-
 lib/__dtostr.c   |   18 +++++++++++-----
 lib/__v_printf.c |   59 +++++++++++++++++++++++++++++------------------------
 test/printf.c    |   44 +++++++++++++++++++++++++++++++++++----
 4 files changed, 88 insertions(+), 39 deletions(-)

diff --git a/include/stdlib.h b/include/stdlib.h
index d1e1569..34f3a7f 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -28,8 +28,12 @@ long double strtold(const char *nptr, char **endptr) __THROW;
 long int strtol(const char *nptr, char **endptr, int base) __THROW;
 unsigned long int strtoul(const char *nptr, char **endptr, int base) __THROW;
 
+/* HACK: used flags in __dtostr
+     0x01 ... 'g'
+     0x02 ... uppercase
+   Define some constants somewhere... */
 extern int __ltostr(char *s, unsigned int size, unsigned long i, unsigned int base, int UpCase) __THROW;
-extern int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned int prec2,int g) __THROW;
+extern int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned int prec2,int flags) __THROW;
 
 #if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L
 __extension__ long long int strtoll(const char *nptr, char **endptr, int base) __THROW;
diff --git a/lib/__dtostr.c b/lib/__dtostr.c
index 1d082e3..bc61200 100644
--- a/lib/__dtostr.c
+++ b/lib/__dtostr.c
@@ -5,13 +5,15 @@
 
 static int copystring(char* buf,int maxlen, const char* s) {
   int i;
-  for (i=0; i<3&&i<maxlen; ++i)
+  for (i=0; i<maxlen; ++i) {
     buf[i]=s[i];
-  if (i<maxlen) { buf[i]=0; ++i; }
+    if (!s[i])
+      break;
+  }
   return i;
 }
 
-int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned int prec2,int g) {
+int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned int prec2,int flags) {
 #if 1
   union {
     unsigned long long l;
@@ -35,8 +37,12 @@ int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned i
   double tmp;
   char *oldbuf=buf;
 
-  if ((i=isinf(d))) return copystring(buf,maxlen,i>0?"inf":"-inf");
-  if (isnan(d)) return copystring(buf,maxlen,"nan");
+  if (isinf(d))
+    return copystring(buf,maxlen,
+		      (d<0)?
+		      (flags&0x02?"-INF":"-inf"):
+		      (flags&0x02?"INF":"inf"));
+  if (isnan(d)) return copystring(buf,maxlen,flags&0x02?"NAN":"nan");
   e10=1+(long)(e*0.30102999566398119802); /* log10(2) */
   /* Wir iterieren von Links bis wir bei 0 sind oder maxlen erreicht
    * ist.  Wenn maxlen erreicht ist, machen wir das nochmal in
@@ -126,7 +132,7 @@ int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned i
   if (prec2 || prec>(unsigned int)(buf-oldbuf)+1) {	/* more digits wanted */
     if (!maxlen) return 0; --maxlen;
     *buf='.'; ++buf;
-    if (g) {
+    if ((flags & 0x01)) {
       if (prec2) prec=prec2;
       prec-=buf-oldbuf-1;
     } else {
diff --git a/lib/__v_printf.c b/lib/__v_printf.c
index 36202f5..964c005 100644
--- a/lib/__v_printf.c
+++ b/lib/__v_printf.c
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <math.h>
 #include "dietstdio.h"
 #include "dietwarning.h"
 
@@ -346,45 +347,49 @@ num_printf:
 #ifdef WANT_FLOATING_POINT_IN_PRINTF
       /* print a floating point value */
       case 'f':
+      case 'F':
       case 'g':
+      case 'G':
 	{
-	  int g=(ch=='g');
+	  int flags=(((ch&0x5f)=='G') ? 0x01 : 0x00) | ((ch&0x20) ? 0x00 : 0x02);
 	  double d=va_arg(arg_ptr,double);
 	  s=buf+1;
 	  if (width==0) width=1;
 	  if (!flag_dot) preci=6;
 	  if (flag_sign || d < +0.0) flag_in_sign=1;
 
-	  sz=__dtostr(d,s,sizeof(buf)-1,width,preci,g);
-
-	  if (flag_dot) {
-	    char *tmp;
-	    if ((tmp=strchr(s,'.'))) {
-	      if (preci || flag_hash) ++tmp;
-	      while (preci>0 && *++tmp) --preci;
-	      *tmp=0;
-	    } else if (flag_hash) {
-	      s[sz]='.';
-	      s[++sz]='\0';
+	  sz=__dtostr(d,s,sizeof(buf)-1,width,preci,flags);
+
+	  if (!isnan(d) && !isinf(d)) {		/* skip NaN + INF values */
+	    if (flag_dot) {
+	      char *tmp;
+	      if ((tmp=strchr(s,'.'))) {
+		if (preci || flag_hash) ++tmp;
+		while (preci>0 && *++tmp) --preci;
+		*tmp=0;
+	      } else if (flag_hash) {
+		s[sz]='.';
+		s[++sz]='\0';
+	      }
 	    }
-	  }
 
-	  if (g) {
-	    char *tmp,*tmp1;	/* boy, is _this_ ugly! */
-	    if ((tmp=strchr(s,'.'))) {
-	      tmp1=strchr(tmp,'e');
-	      while (*tmp) ++tmp;
-	      if (tmp1) tmp=tmp1;
-	      while (*--tmp=='0') ;
-	      if (*tmp!='.') ++tmp;
-	      *tmp=0;
-	      if (tmp1) strcpy(tmp,tmp1);
+	    if ((flags&0x01)) {
+	      char *tmp,*tmp1;	/* boy, is _this_ ugly! */
+	      if ((tmp=strchr(s,'.'))) {
+		tmp1=strchr(tmp,'e');
+		while (*tmp) ++tmp;
+		if (tmp1) tmp=tmp1;
+		while (*--tmp=='0') ;
+		if (*tmp!='.') ++tmp;
+		*tmp=0;
+		if (tmp1) strcpy(tmp,tmp1);
+	      }
 	    }
-	  }
 	  
-	  if ((flag_sign || flag_space) && d>=0) {
-	    *(--s)=(flag_sign)?'+':' ';
-	    ++sz;
+	    if ((flag_sign || flag_space) && d>=0) {
+	      *(--s)=(flag_sign)?'+':' ';
+	      ++sz;
+	    }
 	  }
 	  
 	  sz=strlen(s);
diff --git a/test/printf.c b/test/printf.c
index 719461a..ef6050d 100644
--- a/test/printf.c
+++ b/test/printf.c
@@ -2,11 +2,26 @@
 #include <string.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <math.h>
+#include <float.h>
 #include <sys/param.h>
 #include <locale.h>
 
 #define ALGN		5
 
+#ifndef INFINITY
+#  if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3))
+#    define INFINITY	(__builtin_inf())
+#  endif
+#endif
+
+#ifndef NAN
+#  if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3))
+#    define NAN		(__builtin_nan(""))
+#  endif
+#endif
+
+
 // https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=112986
 #if 0
 #undef  assert
@@ -60,7 +75,7 @@
   TEST_SNPRINTF(EXP,  0,                __VA_ARGS__);		\
   TEST_SNPRINTF(EXP,  sizeof(EXP)+ALGN, __VA_ARGS__);		\
   TEST_SNPRINTF_NULL(EXP, __VA_ARGS__)
-  
+
 
 int main()
 {
@@ -101,7 +116,7 @@ int main()
   TEST("42.23",   "%5.2f",  42.23);
   TEST("42.23",   "%5.4g",  42.23);
   TEST(" 42.2",   "%5.3g",  42.23);
-  
+
   TEST("   1",     "%*i",   4, 1);
   TEST("   1",     "%4i",   1);
   TEST("1   ",     "%-4i",  1);
@@ -131,13 +146,32 @@ int main()
   TEST("-01234",   "%6.5i", -1234);
   TEST("  1234",   "%6.5s", "1234");
 
+#ifdef INFINITY
+  TEST("inf",	"%f", INFINITY);
+  TEST("-inf",	"%f", -INFINITY);
+  TEST("INF",	"%F", INFINITY);
+  TEST("-INF",	"%F", -INFINITY);
+
+  TEST("inf",	"%g", INFINITY);
+  TEST("-inf",	"%g", -INFINITY);
+  TEST("INF",	"%G", INFINITY);
+  TEST("-INF",	"%G", -INFINITY);
+#endif
+
+#ifdef NAN
+  TEST("nan",	"%f", NAN);
+  TEST("NAN",	"%F", NAN);
+  TEST("nan",	"%g", NAN);
+  TEST("NAN",	"%G", NAN);
+#endif
+
 #ifdef XSI_TESTS
   setlocale(LC_ALL, "de_DE");
-  
+
   TEST("1.234",    "%'u", 1234);
   TEST("2 1",      "%2$u %1$u",  1, 2);
 #endif
-  
-  
+
+
   return EXIT_SUCCESS;
 }
-- 
1.5.4.5