📄 vsprintf.c
字号:
/* $Id: vsprintf.c,v 1.2 2002/08/09 20:57:00 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 <stdio.h>#include <stdarg.h>#include <string.h>#include <ctype.h>#include <pmon.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 dst = d; for (; *s;) { if (*s == '%') { s++; fmt = FMT_RJUST; width = trunc = haddot = longlong = 0; for (; *s; s++) { if (strchr ("dobpxXulscefg%", *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 ("dobpxXu", *s)) { if (*s == 'd') base = -10; else if (*s == 'u') base = 10; else if (*s == 'x' || *s == 'X') base = 16; else if(*s == 'p') { base = 16; *d++ = '0'; *d++ = 'x'; fmt = FMT_RJUST0; width = 8; } else if (*s == 'o') base = 8; else if (*s == 'b') base = 2;#ifdef HAVE_QUAD if (longlong) llbtoa(d, va_arg (ap, quad_t), base); else#endif 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); 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) 0typedef 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 *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 struct IEEEdp { unsigned sign:1; unsigned exp:11; unsigned manh:20; unsigned manl:32; } *ip;#endif ip = (struct IEEEdp *)&d; return (ip->exp != 0x7ff);}static 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 intcvt(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 = 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 = 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 = 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 = 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 *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 *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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -