Commit f3540ffe authored by HuangRui's avatar HuangRui
Browse files

Fixed many floating point bug.

Fixed #148 String:format Floating point, width.precision not working.
Fixed #140 string.format not working since 0127(float version) #140.
parent b86bb495
...@@ -58,423 +58,1047 @@ int c_stderr = 1001; ...@@ -58,423 +58,1047 @@ int c_stderr = 1001;
#else #else
/* #define FLOATINGPT 1
File: printf.c #define NEWFP 1
#define ENDIAN_LITTLE 1234
#define ENDIAN_BIG 4321
#define ENDIAN_PDP 3412
#define ENDIAN ENDIAN_BIG
Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs /* $Id: strichr.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
All rights reserved. /*
* Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//#include <string.h>
#include "c_string.h"
Redistribution and use in source and binary forms, with or without modification, char *
are permitted provided that the following conditions are met: strichr(char *p, int c)
{
char *t;
Redistributions of source code must retain the above copyright notice, this list if (p != NULL) {
of conditions and the following disclaimer. for(t = p; *t; t++);
for (; t >= p; t--) {
*(t + 1) = *t;
}
*p = c;
}
return (p);
}
Redistributions in binary form must reproduce the above copyright notice, this /* $Id: str_fmt.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its /*
contributors may be used to endorse or promote products derived from this software * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
without specific prior written permission. *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//#include <string.h>
#include "c_string.h"
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" #define FMT_RJUST 0
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #define FMT_LJUST 1
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. #define FMT_RJUST0 2
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, #define FMT_CENTER 3
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
---------------------------------------------------------------------- /*
* Format string by inserting blanks.
*/
This library is realy just two files: 'printf.h' and 'printf.c'. void
str_fmt(char *p, int size, int fmt)
{
int n, m, len;
They provide a simple and small (+200 loc) printf functionality to len = strlen (p);
be used in embedded systems. switch (fmt) {
case FMT_RJUST:
for (n = size - len; n > 0; n--)
strichr (p, ' ');
break;
case FMT_LJUST:
for (m = size - len; m > 0; m--)
strcat (p, " ");
break;
case FMT_RJUST0:
for (n = size - len; n > 0; n--)
strichr (p, '0');
break;
case FMT_CENTER:
m = (size - len) / 2;
n = size - (len + m);
for (; m > 0; m--)
strcat (p, " ");
for (; n > 0; n--)
strichr (p, ' ');
break;
}
}
I've found them so usefull in debugging that I do not bother with a /* $Id: strtoupp.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
debugger at all.
They are distributed in source form, so to use them, just compile them /*
into your project. * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//#include <string.h>
//#include <ctype.h>
#include "c_string.h"
#include "c_ctype.h"
Two printf variants are provided: printf and sprintf. void
strtoupper(char *p)
{
if(!p)
return;
for (; *p; p++)
*p = toupper (*p);
}
The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. /* $Id: atob.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
Zero padding and field width are also supported. /*
* Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the //#include <sys/types.h>
long specifier is also //#include <string.h>
supported. Note that this will pull in some long math routines (pun intended!) //#include <pmon.h>
and thus make your executable noticably longer. #include "c_string.h"
typedef int int32_t;
typedef unsigned int u_int32_t;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef int32_t register_t;
typedef long long quad_t;
typedef unsigned long long u_quad_t;
typedef double rtype;
The memory foot print of course depends on the target cpu, compiler and #define __P(x) x
compiler options, but a rough guestimate (based on a H8S target) is about
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
Not too bad. Your milage may vary. By hacking the source code you can
get rid of some hunred bytes, I'm sure, but personally I feel the balance of
functionality and flexibility versus code size is close to optimal for
many embedded systems.
To use the printf you need to supply your own character output function, static char * _getbase __P((char *, int *));
something like : static int _atob __P((unsigned long long *, char *p, int));
void putc ( void* p, char c) static char *
{ _getbase(char *p, int *basep)
while (!SERIAL_PORT_EMPTY) ; {
SERIAL_PORT_TX_REGISTER = c; if (p[0] == '0') {
switch (p[1]) {
case 'x':
*basep = 16;
break;
case 't': case 'n':
*basep = 10;
break;
case 'o':
*basep = 8;
break;
default:
*basep = 10;
return (p);
}
return (p + 2);
} }
*basep = 10;
return (p);
}
Before you can call printf you need to initialize it to use your
character output function with something like:
init_printf(NULL,putc);
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', /*
the NULL (or any pointer) you pass into the 'init_printf' will eventually be * _atob(vp,p,base)
passed to your 'putc' routine. This allows you to pass some storage space (or */
anything realy) to the character output function, if necessary. static int
This is not often needed but it was implemented like that because it made _atob (u_quad_t *vp, char *p, int base)
implementing the sprintf function so neat (look at the source code). {
u_quad_t value, v1, v2;
char *q, tmp[20];
int digit;
The code is re-entrant, except for the 'init_printf' function, so it if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
is safe to call it from interupts too, although this may result in mixed output. base = 16;
If you rely on re-entrancy, take care that your 'putc' function is re-entrant! p += 2;
}
The printf and sprintf functions are actually macros that translate to if (base == 16 && (q = strchr (p, '.')) != 0) {
'tfp_printf' and 'tfp_sprintf'. This makes it possible if (q - p > sizeof(tmp) - 1)
to use them along with 'stdio.h' printf's in a single source file. return (0);
You just need to undef the names before you include the 'stdio.h'.
Note that these are not function like macros, so if you have variables
or struct members with these names, things will explode in your face.
Without variadic macros this is the best we can do to wrap these
fucnction. If it is a problem just give up the macros and use the
functions directly or rename them.
For further details see source code. strncpy (tmp, p, q - p);
tmp[q - p] = '\0';
if (!_atob (&v1, tmp, 16))
return (0);
regs Kusti, 23.10.2004 q++;
*/ if (strchr (q, '.'))
return (0);
/* if (!_atob (&v2, q, 16))
Add lightweight %g support by vowstar, <vowstar@gmail.com> return (0);
NodeMCU Team, 26.1.2015 *vp = (v1 << 16) + v2;
*/ return (1);
}
typedef void (*putcf) (void *, char); value = *vp = 0;
for (; *p; p++) {
if (*p >= '0' && *p <= '9')
digit = *p - '0';
else if (*p >= 'a' && *p <= 'f')
digit = *p - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
digit = *p - 'A' + 10;
else
return (0);
#ifdef PRINTF_LONG_SUPPORT if (digit >= base)
return (0);
value *= base;
value += digit;
}
*vp = value;
return (1);
}
static int uli2a(unsigned long int num, unsigned int base, int uc, char *bf) /*
* atob(vp,p,base)
* converts p to binary result in vp, rtn 1 on success
*/
int
atob(u_int32_t *vp, char *p, int base)
{ {
int n = 0; u_quad_t v;
unsigned long int d = 1;
int len = 1; if (base == 0)
while (num / d >= base) p = _getbase (p, &base);
{ if (_atob (&v, p, base)) {
d *= base; *vp = v;
len ++; return (1);
}
while (d != 0)
{
int dgt = num / d;
num %= d;
d /= base;
if (n || dgt > 0 || d == 0)
{
*bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
++n;
}
} }
*bf = 0; return (0);
return len;
} }
static int li2a (long num, char *bf)
/*
* llatob(vp,p,base)
* converts p to binary result in vp, rtn 1 on success
*/
int
llatob(u_quad_t *vp, char *p, int base)
{ {
int len = 0; if (base == 0)
if (num < 0) p = _getbase (p, &base);
{ return _atob(vp, p, base);
num = -num;
*bf++ = '-';
len ++;
}
len += uli2a(num, 10, 0, bf);
return len;
} }
#endif
static int ui2a(unsigned int num, unsigned int base, int uc, char *bf) /*
* char *btoa(dst,value,base)
* converts value to ascii, result in dst
*/
char *
btoa(char *dst, u_int value, int base)
{ {
int n = 0; char buf[34], digit;
unsigned int d = 1; int i, j, rem, neg;
int len = 1;
while (num / d >= base) if (value == 0) {
{ dst[0] = '0';
d *= base; dst[1] = 0;
len ++; return (dst);
} }
while (d != 0)
{ neg = 0;
int dgt = num / d; if (base == -10) {
num %= d; base = 10;
d /= base; if (value & (1L << 31)) {
if (n || dgt > 0 || d == 0) value = (~value) + 1;
{ neg = 1;
*bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
++n;
} }
} }
*bf = 0;
return len; for (i = 0; value != 0; i++) {
rem = value % base;
value /= base;
if (rem >= 0 && rem <= 9)
digit = rem + '0';
else if (rem >= 10 && rem <= 36)
digit = (rem - 10) + 'a';
buf[i] = digit;
}
buf[i] = 0;
if (neg)
strcat (buf, "-");
/* reverse the string */
for (i = 0, j = strlen (buf) - 1; j >= 0; i++, j--)
dst[i] = buf[j];
dst[i] = 0;
return (dst);
} }
static int i2a (int num, char *bf) /*
* char *btoa(dst,value,base)
* converts value to ascii, result in dst
*/
char *
llbtoa(char *dst, u_quad_t value, int base)
{ {
int len = 0; char buf[66], digit;
if (num < 0) int i, j, rem, neg;
{
num = -num; if (value == 0) {
*bf++ = '-'; dst[0] = '0';
len ++; dst[1] = 0;
return (dst);
}
neg = 0;
if (base == -10) {
base = 10;
if (value & (1LL << 63)) {
value = (~value) + 1;
neg = 1;
}
} }
len += ui2a(num, 10, 0, bf);
return len; for (i = 0; value != 0; i++) {
rem = value % base;
value /= base;
if (rem >= 0 && rem <= 9)
digit = rem + '0';
else if (rem >= 10 && rem <= 36)
digit = (rem - 10) + 'a';
buf[i] = digit;
}
buf[i] = 0;
if (neg)
strcat (buf, "-");
/* reverse the string */
for (i = 0, j = strlen (buf) - 1; j >= 0; i++, j--)
dst[i] = buf[j];
dst[i] = 0;
return (dst);
} }
// Converts a floating point number to string. /*
static int d2a(double num, char *bf) * gethex(vp,p,n)
* convert n hex digits from p to binary, result in vp,
* rtn 1 on success
*/
int
gethex(int32_t *vp, char *p, int n)
{ {
int len = 0; u_long v;
double ipart = 0; int digit;
double fpart = 0;
double absnum = num; for (v = 0; n > 0; n--) {
if (*p == 0)
// Add sign return (0);
if (absnum < 0) if (*p >= '0' && *p <= '9')
{ digit = *p - '0';
absnum = -absnum; else if (*p >= 'a' && *p <= 'f')
*bf++ = '-'; digit = *p - 'a' + 10;
// len must add 1 when return else if (*p >= 'A' && *p <= 'F')
// but can't add at here digit = *p - 'A' + 10;
else
return (0);
v <<= 4;
v |= digit;
p++;
} }
*vp = v;
return (1);
}
// Extract integer part /* $Id: vsprintf.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */
ipart = (int)absnum;
// Extract floating part /*
fpart = absnum - (double)ipart; * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//#include <stdio.h>
//#include <stdarg.h>
//#include <string.h>
//#include <ctype.h>
//#include <pmon.h>
#include "c_stdarg.h"
#include "c_string.h"
#include "c_ctype.h"
// convert integer part to string /*
#ifdef PRINTF_LONG_SUPPORT * int vsprintf(d,s,ap)
len += li2a(ipart, bf); */
#else int
len += i2a(ipart, bf); vsprintf (char *d, const char *s, va_list ap)
{
const char *t;
char *p, *dst, tmp[40];
unsigned int n;
int fmt, trunc, haddot, width, base, longlong;
#ifdef FLOATINGPT
double dbl;
#ifndef NEWFP
EP ex;
#endif
#endif #endif
#ifndef EPSILON dst = d;
#define EPSILON ((double)(0.00000001)) for (; *s;) {
if (*s == '%') {
s++;
fmt = FMT_RJUST;
width = trunc = haddot = longlong = 0;
for (; *s; s++) {
if (strchr("bcdefgilopPrRsuxX%", *s))
break;
else if (*s == '-')
fmt = FMT_LJUST;
else if (*s == '0')
fmt = FMT_RJUST0;
else if (*s == '~')
fmt = FMT_CENTER;
else if (*s == '*') {
if (haddot)
trunc = va_arg(ap, int);
else
width = va_arg(ap, int);
} else if (*s >= '1' && *s <= '9') {
for (t = s; isdigit(*s); s++);
strncpy(tmp, t, s - t);
tmp[s - t] = '\0';
atob(&n, tmp, 10);
if (haddot)
trunc = n;
else
width = n;
s--;
} else if (*s == '.')
haddot = 1;
}
if (*s == '%') {
*d++ = '%';
*d = 0;
} else if (*s == 's') {
p = va_arg(ap, char *);
if (p)
strcpy(d, p);
else
strcpy(d, "(null)");
} else if (*s == 'c') {
n = va_arg (ap, int);
*d = n;
d[1] = 0;
} else {
if (*s == 'l') {
if (*++s == 'l') {
longlong = 1;
++s;
}
}
if (strchr("bdiopPrRxXu", *s)) {
if (*s == 'd' || *s == 'i')
base = -10;
else if (*s == 'u')
base = 10;
else if (*s == 'x' || *s == 'X')
base = 16;
else if(*s == 'p' || *s == 'P') {
base = 16;
if (*s == 'p') {
*d++ = '0';
*d++ = 'x';
}
fmt = FMT_RJUST0;
if (sizeof(long) > 4) {
width = 16;
longlong = 1;
} else {
width = 8;
}
}
else if(*s == 'r' || *s == 'R') {
base = 16;
if (*s == 'r') {
*d++ = '0';
*d++ = 'x';
}
fmt = FMT_RJUST0;
if (sizeof(register_t) > 4) {
width = 16;
longlong = 1;
} else {
width = 8;
}
}
else if (*s == 'o')
base = 8;
else if (*s == 'b')
base = 2;
if (longlong)
llbtoa(d, va_arg (ap, quad_t),
base);
else
btoa(d, va_arg (ap, int), base);
if (*s == 'X')
strtoupper(d);
}
#ifdef FLOATINGPT
else if (strchr ("eEfgG", *s)) {
//static void dtoa (char *, double, int, int, int);
void dtoa (char *dbuf, rtype arg, int fmtch, int width, int prec);
dbl = va_arg(ap, double);
dtoa(d, dbl, *s, width, trunc);
trunc = 0;
}
#endif #endif
if (fpart < EPSILON) }
{ if (trunc)
// fpart is zero d[trunc] = 0;
if (width)
str_fmt (d, width, fmt);
for (; *d; d++);
s++;
} else
*d++ = *s++;
} }
else *d = 0;
{ return (d - dst);
bf += len; }
// add dot
*bf ++ = '.'; #ifdef FLOATINGPT
len += 1; /*
// add zero after dot * Floating point output, cvt() onward lifted from BSD sources:
while (fpart < 0.1) *
{ * Copyright (c) 1990 The Regents of the University of California.
fpart *= 10; * All rights reserved.
*bf ++ = '0'; *
len += 1; * This code is derived from software contributed to Berkeley by
} * Chris Torek.
while ((fpart < (double)1.0 / EPSILON) && ((fpart - (int)fpart) > EPSILON)) *
{ * Redistribution and use in source and binary forms, with or without
fpart = fpart * 10; * modification, are permitted provided that the following conditions
} * are met:
#ifdef PRINTF_LONG_SUPPORT * 1. Redistributions of source code must retain the above copyright
len += li2a((int)fpart, bf); * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define MAX_FCONVERSION 512 /* largest possible real conversion */
#define MAX_EXPT 5 /* largest possible exponent field */
#define MAX_FRACT 39 /* largest possible fraction field */
#define TESTFLAG(x) 0
typedef double rtype;
extern double modf(double, double *);
#define to_char(n) ((n) + '0')
#define to_digit(c) ((c) - '0')
#define _isNan(arg) ((arg) != (arg))
static int cvt (rtype arg, int prec, char *signp, int fmtch,
char *startp, char *endp);
static char *c_round (double fract, int *exp, char *start, char *end,
char ch, char *signp);
static char *exponent(char *p, int exp, int fmtch);
/*
* _finite arg not Infinity or Nan
*/
static int _finite(rtype d)
{
#if ENDIAN == ENDIAN_LITTLE
struct IEEEdp {
unsigned manl:32;
unsigned manh:20;
unsigned exp:11;
unsigned sign:1;
} *ip;
#else #else
len += i2a((int)fpart, bf); struct IEEEdp {
unsigned sign:1;
unsigned exp:11;
unsigned manh:20;
unsigned manl:32;
} *ip;
#endif #endif
}
#undef EPSILON
if (num < 0)
{
len ++;
}
return len;
}
static int a2d(char ch) ip = (struct IEEEdp *)&d;
{ return (ip->exp != 0x7ff);
if (ch >= '0' && ch <= '9')
return ch - '0';
else if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
else if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
else return -1;
} }
static char a2i(char ch, char **src, int base, int *nump)
void dtoa (char *dbuf, rtype arg, int fmtch, int width, int prec)
{ {
char *p = *src; char buf[MAX_FCONVERSION+1], *cp;
int num = 0; char sign;
int digit; int size;
while ((digit = a2d(ch)) >= 0)
{ if( !_finite(arg) ) {
if (digit > base) break; if( _isNan(arg) )
num = num * base + digit; strcpy (dbuf, "NaN");
ch = *p++; else if( arg < 0)
strcpy (dbuf, "-Infinity");
else
strcpy (dbuf, "Infinity");
return;
} }
*src = p;
*nump = num;
return ch;
}
static void putchw(void *putp, putcf putf, int n, char z, char *bf) if (prec == 0)
{ prec = 6;
char fc = z ? '0' : ' '; else if (prec > MAX_FRACT)
char ch; prec = MAX_FRACT;
char *p = bf;
while (*p++ && n > 0) /* leave room for sign at start of buffer */
n--; cp = buf + 1;
while (n-- > 0)
putf(putp, fc); /*
while ((ch = *bf++)) * cvt may have to round up before the "start" of
putf(putp, ch); * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
* if the first character is still NUL, it did.
* softsign avoids negative 0 if _double < 0 but
* no significant digits will be shown.
*/
*cp = '\0';
size = cvt (arg, prec, &sign, fmtch, cp, buf + sizeof(buf));
if (*cp == '\0')
cp++;
if (sign)
*--cp = sign, size++;
cp[size] = 0;
memcpy (dbuf, cp, size + 1);
} }
void c_format(void *putp, putcf putf, char *fmt, va_list va)
static int
cvt(rtype number, int prec, char *signp, int fmtch, char *startp, char *endp)
{ {
char bf[12]; register char *p, *t;
register double fract;
double integer, tmp;
int dotrim, expcnt, gformat;
dotrim = expcnt = gformat = 0;
if (number < 0) {
number = -number;
*signp = '-';
} else
*signp = 0;
char ch; fract = modf(number, &integer);
/* get an extra slot for rounding. */
t = ++startp;
while ((ch = *(fmt++))) /*
{ * get integer portion of number; put into the end of the buffer; the
if (ch != '%') * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
putf(putp, ch); */
for (p = endp - 1; integer; ++expcnt) {
tmp = modf(integer / 10, &integer);
*p-- = to_char((int)((tmp + .01) * 10));
}
switch (fmtch) {
case 'f':
/* reverse integer into beginning of buffer */
if (expcnt)
for (; ++p < endp; *t++ = *p);
else else
{ *t++ = '0';
char lz = 0; /*
#ifdef PRINTF_LONG_SUPPORT * if precision required or alternate flag set, add in a
char lng = 0; * decimal point.
#endif */
int w = 0; if (prec || TESTFLAG(ALTERNATE_FORM))
ch = *(fmt++); *t++ = '.';
if (ch == '0') /* if requires more precision and some fraction left */
{ if (fract) {
ch = *(fmt++); if (prec)
lz = 1; do {
} fract = modf(fract * 10, &tmp);
if (ch >= '0' && ch <= '9') *t++ = to_char((int)tmp);
{ } while (--prec && fract);
ch = a2i(ch, &fmt, 10, &w); if (fract)
} startp = c_round(fract, (int *)NULL, startp,
#ifdef PRINTF_LONG_SUPPORT t - 1, (char)0, signp);
if (ch == 'l') }
{ for (; prec--; *t++ = '0');
ch = *(fmt++); break;
lng = 1; case 'e':
} case 'E':
#endif eformat: if (expcnt) {
switch (ch) *t++ = *++p;
{ if (prec || TESTFLAG(ALTERNATE_FORM))
case 0: *t++ = '.';
goto abort; /* if requires more precision and some integer left */
case 'u' : for (; prec && ++p < endp; --prec)
{ *t++ = *p;
#ifdef PRINTF_LONG_SUPPORT /*
if (lng) * if done precision and more of the integer component,
uli2a(va_arg(va, unsigned long int), 10, 0, bf); * round using it; adjust fract so we don't re-round
else * later.
#endif */
ui2a(va_arg(va, unsigned int), 10, 0, bf); if (!prec && ++p < endp) {
putchw(putp, putf, w, lz, bf); fract = 0;
break; startp = c_round((double)0, &expcnt, startp,
t - 1, *p, signp);
} }
case 'o' : /* adjust expcnt for digit in front of decimal */
{ --expcnt;
#ifdef PRINTF_LONG_SUPPORT }
if (lng) /* until first fractional digit, decrement exponent */
uli2a(va_arg(va, unsigned long int), 8, 0, bf); else if (fract) {
else /* adjust expcnt for digit in front of decimal */
#endif for (expcnt = -1;; --expcnt) {
ui2a(va_arg(va, unsigned int), 8, 0, bf); fract = modf(fract * 10, &tmp);
putchw(putp, putf, w, lz, bf); if (tmp)
break; break;
} }
case 'd' : case 'i': *t++ = to_char((int)tmp);
{ if (prec || TESTFLAG(ALTERNATE_FORM))
#ifdef PRINTF_LONG_SUPPORT *t++ = '.';
if (lng) }
li2a(va_arg(va, unsigned long int), bf); else {
else *t++ = '0';
#endif if (prec || TESTFLAG(ALTERNATE_FORM))
i2a(va_arg(va, int), bf); *t++ = '.';
putchw(putp, putf, w, lz, bf); }
break; /* if requires more precision and some fraction left */
if (fract) {
if (prec)
do {
fract = modf(fract * 10, &tmp);
*t++ = to_char((int)tmp);
} while (--prec && fract);
if (fract)
startp = c_round(fract, &expcnt, startp,
t - 1, (char)0, signp);
}
/* if requires more precision */
for (; prec--; *t++ = '0');
/* unless alternate flag, trim any g/G format trailing 0's */
if (gformat && !TESTFLAG(ALTERNATE_FORM)) {
while (t > startp && *--t == '0');
if (*t == '.')
--t;
++t;
}
t = exponent(t, expcnt, fmtch);
break;
case 'g':
case 'G':
/* a precision of 0 is treated as a precision of 1. */
if (!prec)
++prec;
/*
* ``The style used depends on the value converted; style e
* will be used only if the exponent resulting from the
* conversion is less than -4 or greater than the precision.''
* -- ANSI X3J11
*/
if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
/*
* g/G format counts "significant digits, not digits of
* precision; for the e/E format, this just causes an
* off-by-one problem, i.e. g/G considers the digit
* before the decimal point significant and e/E doesn't
* count it as precision.
*/
--prec;
fmtch -= 2; /* G->E, g->e */
gformat = 1;
goto eformat;
}
/*
* reverse integer into beginning of buffer,
* note, decrement precision
*/
if (expcnt)
for (; ++p < endp; *t++ = *p, --prec);
else
*t++ = '0';
/*
* if precision required or alternate flag set, add in a
* decimal point. If no digits yet, add in leading 0.
*/
if (prec || TESTFLAG(ALTERNATE_FORM)) {
dotrim = 1;
*t++ = '.';
}
else
dotrim = 0;
/* if requires more precision and some fraction left */
if (fract) {
if (prec) {
do {
fract = modf(fract * 10, &tmp);
*t++ = to_char((int)tmp);
} while(!tmp && !expcnt);
while (--prec && fract) {
fract = modf(fract * 10, &tmp);
*t++ = to_char((int)tmp);
}
} }
case 'x': case 'X' : if (fract)
#ifdef PRINTF_LONG_SUPPORT startp = c_round(fract, (int *)NULL, startp,
if (lng) t - 1, (char)0, signp);
uli2a(va_arg(va, unsigned long int), 16, (ch == 'X'), bf); }
else /* alternate format, adds 0's for precision, else trim 0's */
#endif if (TESTFLAG(ALTERNATE_FORM))
ui2a(va_arg(va, unsigned int), 16, (ch == 'X'), bf); for (; prec--; *t++ = '0');
putchw(putp, putf, w, lz, bf); else if (dotrim) {
while (t > startp && *--t == '0');
if (*t != '.')
++t;
}
}
return (t - startp);
}
static char *
c_round(double fract, int *exp, char *start, char *end, char ch, char *signp)
{
double tmp;
if (fract)
(void)modf(fract * 10, &tmp);
else
tmp = to_digit(ch);
if (tmp > 4)
for (;; --end) {
if (*end == '.')
--end;
if (++*end <= '9')
break; break;
case 'e': case 'E': case 'f': *end = '0';
case 'g': case 'G': if (end == start) {
{ if (exp) { /* e/E; increment exponent */
d2a(va_arg(va, double), bf); *end = '1';
putchw(putp, putf, w, lz, bf); ++*exp;
}
else { /* f; add extra digit */
*--end = '1';
--start;
}
break; break;
} }
case 'c' : }
putf(putp, (char)(va_arg(va, int))); /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
break; else if (*signp == '-')
case 's' : for (;; --end) {
putchw(putp, putf, w, 0, va_arg(va, char *)); if (*end == '.')
break; --end;
case '%' : if (*end != '0')
putf(putp, ch);
default:
break; break;
} if (end == start)
*signp = 0;
} }
} return (start);
abort:;
} }
static char *
static void putcp(void *p, char c) exponent(char *p, int exp, int fmtch)
{ {
*(*((char **)p))++ = c; char *t;
char expbuf[MAX_FCONVERSION];
*p++ = fmtch;
if (exp < 0) {
exp = -exp;
*p++ = '-';
}
else
*p++ = '+';
t = expbuf + MAX_FCONVERSION;
if (exp > 9) {
do {
*--t = to_char(exp % 10);
} while ((exp /= 10) > 9);
*--t = to_char(exp);
for (; t < expbuf + MAX_FCONVERSION; *p++ = *t++);
}
else {
*p++ = '0';
*p++ = to_char(exp);
}
return (p);
} }
#endif /* FLOATINGPT */
void c_sprintf(char *s, char *fmt, ...) void c_sprintf(char *s, char *fmt, ...)
{ {
va_list va; va_list arg;
va_start(va, fmt); va_start(arg, fmt);
c_format(&s, putcp, fmt, va); vsprintf(s, fmt, arg);
putcp(&s, 0); va_end(arg);
va_end(va);
} }
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment