dietlibc/dietlibc-0.31-printFG.patch
2009-07-25 14:52:48 +00:00

275 lines
7.9 KiB
Diff

From d10d2f6fca4e391fa863d771dd8c5f7c01d7dfa4 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 12/18] 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.6.2.5