📄 snprintf.c
字号:
/* Unix snprintf implementation. Version 1.1 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Revision History: sitecopy changes: renamed dtoa -> doubletoa to avoid dtoa conflict with cygwin. 1.1: * added changes from Miles Bader * corrected a bug with %f * added support for %#g * added more comments :-) 1.0: * supporting must ANSI syntaxic_sugars 0.0: * suppot %s %c %d THANKS(for the patches and ideas): Miles Bader Cyrille Rustom Jacek Slabocewiz Mike Parker(mouse)*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "snprintf.h"#ifdef HAVE_STRING_H#include <string.h> /* for strlen() */#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h> /* for atoi() */#endif#include <ctype.h>/* * Find the nth power of 10 */PRIVATE double#ifdef __STDC__pow_10(int n)#elsepow_10(n)int n;#endif{ int i; double P; if (n < 0) for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;} else for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;} return P;}/* * Find the integral part of the log in base 10 * Note: this not a real log10() I just need and approximation(integerpart) of x in: 10^x ~= r * log_10(200) = 2; * log_10(250) = 2; */PRIVATE int#ifdef __STDC__log_10(double r)#elselog_10(r)double r;#endif{ int i = 0; double result = 1.; if (r < 0.) r = -r; if (r < 1.) { while (result >= r) {result *= .1; i++;} return (-i); } else { while (result <= r) {result *= 10.; i++;} return (i - 1); }}/* * This function return the fraction part of a double * and set in ip the integral part. * In many ways it resemble the modf() found on most Un*x */PRIVATE double#ifdef __STDC__integral(double real, double * ip)#elseintegral(real, ip)double real;double * ip;#endif{ int j; double i, s, p; double real_integral = 0.;/* take care of the obvious *//* equal to zero ? */ if (real == 0.) { *ip = 0.; return (0.); }/* negative number ? */ if (real < 0.) real = -real;/* a fraction ? */ if ( real < 1.) { *ip = 0.; return real; }/* the real work :-) */ for (j = log_10(real); j >= 0; j--) { p = pow_10(j); s = (real - real_integral)/p; i = 0.; while (i + 1. <= s) {i++;} real_integral += i*p; } *ip = real_integral; return (real - real_integral);}#define PRECISION 1.e-6/* * return an ascii representation of the integral part of the number * and set fract to be an ascii representation of the fraction part * the container for the fraction and the integral part or staticly * declare with fix size */PRIVATE char *#ifdef __STDC__numtoa(double number, int base, int precision, char ** fract)#elsenumtoa(number, base, precision, fract)double number;int base;int precision;char ** fract;#endif{ register int i, j; double ip, fp; /* integer and fraction part */ double fraction; int digits = MAX_INT - 1; static char integral_part[MAX_INT]; static char fraction_part[MAX_FRACT]; double sign; int ch;/* taking care of the obvious case: 0.0 */ if (number == 0.) { integral_part[0] = '0'; integral_part[1] = '\0'; fraction_part[0] = '0'; fraction_part[1] = '\0'; return integral_part; }/* for negative numbers */ if ((sign = number) < 0.) { number = -number; digits--; /* sign consume one digit */ } fraction = integral(number, &ip); number = ip;/* do the integral part */ if ( ip == 0.) { integral_part[0] = '0'; i = 1; } else { for ( i = 0; i < digits && number != 0.; ++i) { number /= base; fp = integral(number, &ip); ch = (int)((fp + PRECISION)*base); /* force to round */ integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10; if (! isxdigit(integral_part[i])) /* bail out overflow !! */ break; number = ip; } } /* Oh No !! out of bound, ho well fill it up ! */ if (number != 0.) for (i = 0; i < digits; ++i) integral_part[i] = '9';/* put the sign ? */ if (sign < 0.) integral_part[i++] = '-'; integral_part[i] = '\0';/* reverse every thing */ for ( i--, j = 0; j < i; j++, i--) SWAP_INT(integral_part[i], integral_part[j]); /* the fractionnal part */ for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision-- ) { fraction_part[i] = (int)((fp + PRECISION)*10. + '0'); if (! isdigit(fraction_part[i])) /* underflow ? */ break; fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.); } fraction_part[i] = '\0'; if (fract != (char **)0) *fract = fraction_part; return integral_part;}/* for %d and friends, it puts in holder * the representation with the right padding */PRIVATE void#ifdef __STDC__decimal(struct DATA *p, double d)#elsedecimal(p, d)struct DATA *p;double d;#endif{ char *tmp; tmp = itoa(d); p->width -= strlen(tmp); PAD_RIGHT(p); PUT_PLUS(d, p); PUT_SPACE(d, p); while (*tmp) { /* the integral */ PUT_CHAR(*tmp, p); tmp++; } PAD_LEFT(p);}/* for %o octal representation */PRIVATE void#ifdef __STDC__octal(struct DATA *p, double d)#elseoctal(p, d)struct DATA *p;double d;#endif{ char *tmp; tmp = otoa(d); p->width -= strlen(tmp); PAD_RIGHT(p); if (p->square == FOUND) /* had prefix '0' for octal */ PUT_CHAR('0', p); while (*tmp) { /* octal */ PUT_CHAR(*tmp, p); tmp++; } PAD_LEFT(p);}/* for %x %X hexadecimal representation */PRIVATE void#ifdef __STDC__hexa(struct DATA *p, double d)#elsehexa(p, d)struct DATA *p;double d;#endif{ char *tmp; tmp = htoa(d); p->width -= strlen(tmp); PAD_RIGHT(p); if (p->square == FOUND) { /* prefix '0x' for hexa */ PUT_CHAR('0', p); PUT_CHAR(*p->pf, p); } while (*tmp) { /* hexa */ PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p); tmp++; } PAD_LEFT(p);}/* %s strings */PRIVATE void#ifdef __STDC__strings(struct DATA *p, char *tmp)#elsestrings(p, tmp)struct DATA *p;char *tmp;#endif{ int i; i = strlen(tmp); if (p->precision != NOT_FOUND) /* the smallest number */ i = (i < p->precision ? i : p->precision); p->width -= i; PAD_RIGHT(p); while (i-- > 0) { /* put the sting */ PUT_CHAR(*tmp, p); tmp++; } PAD_LEFT(p);}/* %f or %g floating point representation */PRIVATE void#ifdef __STDC__floating(struct DATA *p, double d)#elsefloating(p, d)struct DATA *p;double d;#endif{ char *tmp, *tmp2; int i; DEF_PREC(p); d = ROUND(d, p); tmp = doubletoa(d, p->precision, &tmp2); /* calculate the padding. 1 for the dot */ p->width = p->width - ((d > 0. && p->justify == RIGHT) ? 1:0) - ((p->space == FOUND) ? 1:0) - strlen(tmp) - p->precision - 1; PAD_RIGHT(p); PUT_PLUS(d, p); PUT_SPACE(d, p); while (*tmp) { /* the integral */ PUT_CHAR(*tmp, p); tmp++; } if (p->precision != 0 || p->square == FOUND) PUT_CHAR('.', p); /* put the '.' */ if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */ for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) tmp2[i] = '\0'; for (; *tmp2; tmp2++) PUT_CHAR(*tmp2, p); /* the fraction */ PAD_LEFT(p);} /* %e %E %g exponent representation */PRIVATE void#ifdef __STDC__exponent(struct DATA *p, double d)#elseexponent(p, d)struct DATA *p;double d;#endif{ char *tmp, *tmp2; int j, i; DEF_PREC(p); j = log_10(d); d = d / pow_10(j); /* get the Mantissa */ d = ROUND(d, p); tmp = doubletoa(d, p->precision, &tmp2); /* 1 for unit, 1 for the '.', 1 for 'e|E', * 1 for '+|-', 3 for 'exp' */ /* calculate how much padding need */ p->width = p->width - ((d > 0. && p->justify == RIGHT) ? 1:0) - ((p->space == FOUND) ? 1:0) - p->precision - 7; PAD_RIGHT(p); PUT_PLUS(d, p); PUT_SPACE(d, p); while (*tmp) {/* the integral */ PUT_CHAR(*tmp, p); tmp++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -