From f3540ffe29877ecfb37733a56625671bcd916122 Mon Sep 17 00:00:00 2001 From: HuangRui Date: Thu, 12 Feb 2015 01:15:30 +0800 Subject: [PATCH] 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. --- app/libc/c_stdio.c | 1404 ++++++++++++++++++++++++++++++++------------ 1 file changed, 1014 insertions(+), 390 deletions(-) diff --git a/app/libc/c_stdio.c b/app/libc/c_stdio.c index 43d7bd24..6ef1dd30 100644 --- a/app/libc/c_stdio.c +++ b/app/libc/c_stdio.c @@ -58,423 +58,1047 @@ int c_stderr = 1001; #else -/* -File: printf.c +#define FLOATINGPT 1 +#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 - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -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. - -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 -without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. - ----------------------------------------------------------------------- - -This library is realy just two files: 'printf.h' and 'printf.c'. - -They provide a simple and small (+200 loc) printf functionality to -be used in embedded systems. - -I've found them so usefull in debugging that I do not bother with a -debugger at all. - -They are distributed in source form, so to use them, just compile them -into your project. - -Two printf variants are provided: printf and sprintf. - -The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. - -Zero padding and field width are also supported. - -If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the -long specifier is also -supported. Note that this will pull in some long math routines (pun intended!) -and thus make your executable noticably longer. - -The memory foot print of course depends on the target cpu, compiler and -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, -something like : - -void putc ( void* p, char c) - { - while (!SERIAL_PORT_EMPTY) ; - SERIAL_PORT_TX_REGISTER = c; - } - -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 -passed to your 'putc' routine. This allows you to pass some storage space (or -anything realy) to the character output function, if necessary. -This is not often needed but it was implemented like that because it made -implementing the sprintf function so neat (look at the source code). - -The code is re-entrant, except for the 'init_printf' function, so it -is safe to call it from interupts too, although this may result in mixed output. -If you rely on re-entrancy, take care that your 'putc' function is re-entrant! - -The printf and sprintf functions are actually macros that translate to -'tfp_printf' and 'tfp_sprintf'. This makes it possible -to use them along with 'stdio.h' printf's in a single source file. -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. - -regs Kusti, 23.10.2004 -*/ +/* $Id: strichr.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */ /* -Add lightweight %g support by vowstar, -NodeMCU Team, 26.1.2015 -*/ + * 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 +#include "c_string.h" -typedef void (*putcf) (void *, char); - -#ifdef PRINTF_LONG_SUPPORT - -static int uli2a(unsigned long int num, unsigned int base, int uc, char *bf) +char * +strichr(char *p, int c) { - int n = 0; - unsigned long int d = 1; - int len = 1; - while (num / d >= base) - { - d *= base; - len ++; + char *t; + + if (p != NULL) { + for(t = p; *t; t++); + for (; t >= p; t--) { + *(t + 1) = *t; + } + *p = c; } - 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; + return (p); +} + +/* $Id: str_fmt.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */ + +/* + * 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 +#include "c_string.h" + +#define FMT_RJUST 0 +#define FMT_LJUST 1 +#define FMT_RJUST0 2 +#define FMT_CENTER 3 + +/* + * Format string by inserting blanks. + */ + +void +str_fmt(char *p, int size, int fmt) +{ + int n, m, len; + + len = strlen (p); + 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; + } +} + +/* $Id: strtoupp.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */ + +/* + * 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 +//#include +#include "c_string.h" +#include "c_ctype.h" + +void +strtoupper(char *p) +{ + if(!p) + return; + for (; *p; p++) + *p = toupper (*p); +} + +/* $Id: atob.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */ + +/* + * 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 +//#include +//#include +#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; + +#define __P(x) x + +static char * _getbase __P((char *, int *)); +static int _atob __P((unsigned long long *, char *p, int)); + +static char * +_getbase(char *p, int *basep) +{ + 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); +} + + +/* + * _atob(vp,p,base) + */ +static int +_atob (u_quad_t *vp, char *p, int base) +{ + u_quad_t value, v1, v2; + char *q, tmp[20]; + int digit; + + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + base = 16; + p += 2; + } + + if (base == 16 && (q = strchr (p, '.')) != 0) { + if (q - p > sizeof(tmp) - 1) + return (0); + + strncpy (tmp, p, q - p); + tmp[q - p] = '\0'; + if (!_atob (&v1, tmp, 16)) + return (0); + + q++; + if (strchr (q, '.')) + return (0); + + if (!_atob (&v2, q, 16)) + return (0); + *vp = (v1 << 16) + v2; + return (1); + } + + 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); + + if (digit >= base) + return (0); + value *= base; + value += digit; + } + *vp = value; + return (1); +} + +/* + * 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) +{ + u_quad_t v; + + if (base == 0) + p = _getbase (p, &base); + if (_atob (&v, p, base)) { + *vp = v; + return (1); + } + return (0); +} + + +/* + * 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) +{ + if (base == 0) + p = _getbase (p, &base); + return _atob(vp, p, base); +} + + +/* + * char *btoa(dst,value,base) + * converts value to ascii, result in dst + */ +char * +btoa(char *dst, u_int value, int base) +{ + char buf[34], digit; + int i, j, rem, neg; + + if (value == 0) { + dst[0] = '0'; + dst[1] = 0; + return (dst); + } + + neg = 0; + if (base == -10) { + base = 10; + if (value & (1L << 31)) { + value = (~value) + 1; + neg = 1; } } - *bf = 0; - return len; -} -static int li2a (long num, char *bf) -{ - int len = 0; - if (num < 0) - { - num = -num; - *bf++ = '-'; - 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; } - len += uli2a(num, 10, 0, bf); - return len; + + 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); } +/* + * char *btoa(dst,value,base) + * converts value to ascii, result in dst + */ +char * +llbtoa(char *dst, u_quad_t value, int base) +{ + char buf[66], digit; + int i, j, rem, neg; + + if (value == 0) { + dst[0] = '0'; + dst[1] = 0; + return (dst); + } + + neg = 0; + if (base == -10) { + base = 10; + if (value & (1LL << 63)) { + value = (~value) + 1; + neg = 1; + } + } + + 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); +} + +/* + * 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) +{ + u_long v; + int digit; + + for (v = 0; n > 0; n--) { + if (*p == 0) + return (0); + 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); + + v <<= 4; + v |= digit; + p++; + } + *vp = v; + return (1); +} + +/* $Id: vsprintf.c,v 1.1.1.1 2006/08/23 17:03:06 pefo Exp $ */ + +/* + * 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 +//#include +//#include +//#include +//#include +#include "c_stdarg.h" +#include "c_string.h" +#include "c_ctype.h" + +/* + * int vsprintf(d,s,ap) + */ +int +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 -static int ui2a(unsigned int num, unsigned int base, int uc, char *bf) + dst = d; + 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 + } + if (trunc) + d[trunc] = 0; + if (width) + str_fmt (d, width, fmt); + for (; *d; d++); + s++; + } else + *d++ = *s++; + } + *d = 0; + return (d - dst); +} + +#ifdef FLOATINGPT +/* + * Floating point output, cvt() onward lifted from BSD sources: + * + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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 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) { - int n = 0; - unsigned int d = 1; - int len = 1; - while (num / d >= base) - { - d *= base; - len ++; - } - 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 len; -} - -static int i2a (int num, char *bf) -{ - int len = 0; - if (num < 0) - { - num = -num; - *bf++ = '-'; - len ++; - } - len += ui2a(num, 10, 0, bf); - return len; -} - -// Converts a floating point number to string. -static int d2a(double num, char *bf) -{ - int len = 0; - double ipart = 0; - double fpart = 0; - double absnum = num; - - // Add sign - if (absnum < 0) - { - absnum = -absnum; - *bf++ = '-'; - // len must add 1 when return - // but can't add at here - } - - // Extract integer part - ipart = (int)absnum; - - // Extract floating part - fpart = absnum - (double)ipart; - - // convert integer part to string -#ifdef PRINTF_LONG_SUPPORT - len += li2a(ipart, bf); +#if ENDIAN == ENDIAN_LITTLE + struct IEEEdp { + unsigned manl:32; + unsigned manh:20; + unsigned exp:11; + unsigned sign:1; + } *ip; #else - len += i2a(ipart, bf); + struct IEEEdp { + unsigned sign:1; + unsigned exp:11; + unsigned manh:20; + unsigned manl:32; + } *ip; #endif -#ifndef EPSILON -#define EPSILON ((double)(0.00000001)) -#endif - if (fpart < EPSILON) - { - // fpart is zero + ip = (struct IEEEdp *)&d; + return (ip->exp != 0x7ff); +} + + +void dtoa (char *dbuf, rtype arg, int fmtch, int width, int prec) +{ + char buf[MAX_FCONVERSION+1], *cp; + char sign; + int size; + + if( !_finite(arg) ) { + if( _isNan(arg) ) + strcpy (dbuf, "NaN"); + else if( arg < 0) + strcpy (dbuf, "-Infinity"); + else + strcpy (dbuf, "Infinity"); + return; + } + + if (prec == 0) + prec = 6; + else if (prec > MAX_FRACT) + prec = MAX_FRACT; + + /* leave room for sign at start of buffer */ + cp = buf + 1; + + /* + * cvt may have to round up before the "start" of + * 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); +} + + +static int +cvt(rtype number, int prec, char *signp, int fmtch, char *startp, char *endp) +{ + 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; + + fract = modf(number, &integer); + + /* get an extra slot for rounding. */ + t = ++startp; + + /* + * get integer portion of number; put into the end of the buffer; the + * .01 is added for modf(356.0 / 10, &integer) returning .59999999... + */ + 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 + *t++ = '0'; + /* + * if precision required or alternate flag set, add in a + * decimal point. + */ + if (prec || TESTFLAG(ALTERNATE_FORM)) + *t++ = '.'; + /* 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, (int *)NULL, startp, + t - 1, (char)0, signp); + } + for (; prec--; *t++ = '0'); + break; + case 'e': + case 'E': +eformat: if (expcnt) { + *t++ = *++p; + if (prec || TESTFLAG(ALTERNATE_FORM)) + *t++ = '.'; + /* if requires more precision and some integer left */ + for (; prec && ++p < endp; --prec) + *t++ = *p; + /* + * if done precision and more of the integer component, + * round using it; adjust fract so we don't re-round + * later. + */ + if (!prec && ++p < endp) { + fract = 0; + startp = c_round((double)0, &expcnt, startp, + t - 1, *p, signp); + } + /* adjust expcnt for digit in front of decimal */ + --expcnt; + } + /* until first fractional digit, decrement exponent */ + else if (fract) { + /* adjust expcnt for digit in front of decimal */ + for (expcnt = -1;; --expcnt) { + fract = modf(fract * 10, &tmp); + if (tmp) + break; + } + *t++ = to_char((int)tmp); + if (prec || TESTFLAG(ALTERNATE_FORM)) + *t++ = '.'; + } + else { + *t++ = '0'; + if (prec || TESTFLAG(ALTERNATE_FORM)) + *t++ = '.'; + } + /* 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); + } + } + if (fract) + startp = c_round(fract, (int *)NULL, startp, + t - 1, (char)0, signp); + } + /* alternate format, adds 0's for precision, else trim 0's */ + if (TESTFLAG(ALTERNATE_FORM)) + for (; prec--; *t++ = '0'); + 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; + *end = '0'; + if (end == start) { + if (exp) { /* e/E; increment exponent */ + *end = '1'; + ++*exp; + } + else { /* f; add extra digit */ + *--end = '1'; + --start; + } + break; + } + } + /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ + else if (*signp == '-') + for (;; --end) { + if (*end == '.') + --end; + if (*end != '0') + break; + if (end == start) + *signp = 0; + } + return (start); +} + +static char * +exponent(char *p, int exp, int fmtch) +{ + char *t; + char expbuf[MAX_FCONVERSION]; + + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; } else - { - bf += len; - // add dot - *bf ++ = '.'; - len += 1; - // add zero after dot - while (fpart < 0.1) - { - fpart *= 10; - *bf ++ = '0'; - len += 1; - } - while ((fpart < (double)1.0 / EPSILON) && ((fpart - (int)fpart) > EPSILON)) - { - fpart = fpart * 10; - } -#ifdef PRINTF_LONG_SUPPORT - len += li2a((int)fpart, bf); -#else - len += i2a((int)fpart, bf); -#endif + *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++); } -#undef EPSILON - if (num < 0) - { - len ++; + else { + *p++ = '0'; + *p++ = to_char(exp); } - return len; -} - -static int a2d(char ch) -{ - 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) -{ - char *p = *src; - int num = 0; - int digit; - while ((digit = a2d(ch)) >= 0) - { - if (digit > base) break; - num = num * base + digit; - ch = *p++; - } - *src = p; - *nump = num; - return ch; -} - -static void putchw(void *putp, putcf putf, int n, char z, char *bf) -{ - char fc = z ? '0' : ' '; - char ch; - char *p = bf; - while (*p++ && n > 0) - n--; - while (n-- > 0) - putf(putp, fc); - while ((ch = *bf++)) - putf(putp, ch); -} - -void c_format(void *putp, putcf putf, char *fmt, va_list va) -{ - char bf[12]; - - char ch; - - - while ((ch = *(fmt++))) - { - if (ch != '%') - putf(putp, ch); - else - { - char lz = 0; -#ifdef PRINTF_LONG_SUPPORT - char lng = 0; -#endif - int w = 0; - ch = *(fmt++); - if (ch == '0') - { - ch = *(fmt++); - lz = 1; - } - if (ch >= '0' && ch <= '9') - { - ch = a2i(ch, &fmt, 10, &w); - } -#ifdef PRINTF_LONG_SUPPORT - if (ch == 'l') - { - ch = *(fmt++); - lng = 1; - } -#endif - switch (ch) - { - case 0: - goto abort; - case 'u' : - { -#ifdef PRINTF_LONG_SUPPORT - if (lng) - uli2a(va_arg(va, unsigned long int), 10, 0, bf); - else -#endif - ui2a(va_arg(va, unsigned int), 10, 0, bf); - putchw(putp, putf, w, lz, bf); - break; - } - case 'o' : - { -#ifdef PRINTF_LONG_SUPPORT - if (lng) - uli2a(va_arg(va, unsigned long int), 8, 0, bf); - else -#endif - ui2a(va_arg(va, unsigned int), 8, 0, bf); - putchw(putp, putf, w, lz, bf); - break; - } - case 'd' : case 'i': - { -#ifdef PRINTF_LONG_SUPPORT - if (lng) - li2a(va_arg(va, unsigned long int), bf); - else -#endif - i2a(va_arg(va, int), bf); - putchw(putp, putf, w, lz, bf); - break; - } - case 'x': case 'X' : -#ifdef PRINTF_LONG_SUPPORT - if (lng) - uli2a(va_arg(va, unsigned long int), 16, (ch == 'X'), bf); - else -#endif - ui2a(va_arg(va, unsigned int), 16, (ch == 'X'), bf); - putchw(putp, putf, w, lz, bf); - break; - case 'e': case 'E': case 'f': - case 'g': case 'G': - { - d2a(va_arg(va, double), bf); - putchw(putp, putf, w, lz, bf); - break; - } - case 'c' : - putf(putp, (char)(va_arg(va, int))); - break; - case 's' : - putchw(putp, putf, w, 0, va_arg(va, char *)); - break; - case '%' : - putf(putp, ch); - default: - break; - } - } - } -abort:; -} - - -static void putcp(void *p, char c) -{ - *(*((char **)p))++ = c; + return (p); } +#endif /* FLOATINGPT */ void c_sprintf(char *s, char *fmt, ...) { - va_list va; - va_start(va, fmt); - c_format(&s, putcp, fmt, va); - putcp(&s, 0); - va_end(va); + va_list arg; + va_start(arg, fmt); + vsprintf(s, fmt, arg); + va_end(arg); } #endif