?? snprintf.c
字號:
/* snprintf - formatted output to strings, with bounds checking and allocation *//* build a test version with gcc -g -DDRIVER -I../.. -I../../include -o test-snprintf snprintf.c fmtu*long.o*/ /* Unix snprintf implementation. derived from inetutils/libinetutils/snprintf.c Version 1.1 Copyright (C) 2001,2006,2010 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash 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 3 of the License, or (at your option) any later version. Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>. Revision History: 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: * support %s %c %d THANKS(for the patches and ideas): Miles Bader Cyrille Rustom Jacek Slabocewiz Mike Parker(mouse)*//* * Currently doesn't handle (and bash/readline doesn't use): * * *M$ width, precision specifications * * %N$ numbered argument conversions * * inf, nan floating values imperfect (if isinf(), isnan() not in libc) * * support for `F' is imperfect with ldfallback(), since underlying * printf may not handle it -- should ideally have another autoconf test */#define FLOATING_POINT#ifdef HAVE_CONFIG_H# include <config.h>#endif/* GCC 4.2 on Snow Leopard doesn't like the snprintf prototype */#if defined(DEBUG) && !defined (MACOSX)# undef HAVE_SNPRINTF# undef HAVE_ASPRINTF# define HAVE_SNPRINTF 0# define HAVE_ASPRINTF 0#endif#if defined(DRIVER) && !defined(HAVE_CONFIG_H)#define HAVE_LONG_LONG#define HAVE_LONG_DOUBLE#ifdef __linux__#define HAVE_PRINTF_A_FORMAT#endif#define HAVE_ISINF_IN_LIBC#define HAVE_ISNAN_IN_LIBC#define PREFER_STDARG#define HAVE_STRINGIZE#define HAVE_LIMITS_H#define HAVE_STDDEF_H#define HAVE_LOCALE_H#define intmax_t long#endif#if !HAVE_SNPRINTF || !HAVE_ASPRINTF#include <bashtypes.h>#if defined(PREFER_STDARG)# include <stdarg.h>#else# include <varargs.h>#endif#ifdef HAVE_LIMITS_H# include <limits.h>#endif#include <bashansi.h>#ifdef HAVE_STDDEF_H# include <stddef.h>#endif#include <chartypes.h>#ifdef HAVE_STDINT_H# include <stdint.h>#endif#ifdef FLOATING_POINT# include <float.h> /* for manifest constants */# include <stdio.h> /* for sprintf */#endif#include <typemax.h>#ifdef HAVE_LOCALE_H# include <locale.h>#endif#include "stdc.h"#include <shmbutil.h>#ifndef DRIVER# include "shell.h"#else# define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */# define FL_ADDBASE 0x02 /* add base# prefix to converted value */# define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */# define FL_UNSIGNED 0x08 /* don't add any sign */extern char *fmtulong __P((unsigned long int, int, char *, size_t, int));extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));#endif#ifndef FREE# define FREE(x) if (x) free (x)#endif/* Bound on length of the string representing an integer value of type T. Subtract one for the sign bit if T is signed; 302 / 1000 is log10 (2) rounded up; add one for integer division truncation; add one more for a minus sign if t is signed. */#define INT_STRLEN_BOUND(t) \ ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \ + 1 + TYPE_SIGNED (t))/* conversion flags */#define PF_ALTFORM 0x00001 /* # */#define PF_HEXPREFIX 0x00002 /* 0[Xx] */#define PF_LADJUST 0x00004 /* - */#define PF_ZEROPAD 0x00008 /* 0 */#define PF_PLUS 0x00010 /* + */#define PF_SPACE 0x00020 /* ' ' */#define PF_THOUSANDS 0x00040 /* ' */#define PF_DOT 0x00080 /* `.precision' */#define PF_STAR_P 0x00100 /* `*' after precision */#define PF_STAR_W 0x00200 /* `*' before or without precision *//* length modifiers */#define PF_SIGNEDCHAR 0x00400 /* hh */#define PF_SHORTINT 0x00800 /* h */#define PF_LONGINT 0x01000 /* l */#define PF_LONGLONG 0x02000 /* ll */#define PF_LONGDBL 0x04000 /* L */#define PF_INTMAX_T 0x08000 /* j */#define PF_SIZE_T 0x10000 /* z */#define PF_PTRDIFF_T 0x20000 /* t */#define PF_ALLOCBUF 0x40000 /* for asprintf, vasprintf */#define PFM_SN 0x01 /* snprintf, vsnprintf */#define PFM_AS 0x02 /* asprintf, vasprintf */#define ASBUFSIZE 128#define x_digs "0123456789abcdef"#define X_digs "0123456789ABCDEF"static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1];static int decpoint;static int thoussep;static char *grouping;/* * For the FLOATING POINT FORMAT : * the challenge was finding a way to * manipulate the Real numbers without having * to resort to mathematical function(it * would require to link with -lm) and not * going down to the bit pattern(not portable) * * so a number, a real is: real = integral + fraction integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0 fraction = b(1)*10^-1 + b(2)*10^-2 + ... where: 0 <= a(i) => 9 0 <= b(i) => 9 from then it was simple math *//* * size of the buffer for the integral part * and the fraction part */#define MAX_INT 99 + 1 /* 1 for the null */#define MAX_FRACT 307 + 1/* * These functions use static buffers to store the results, * and so are not reentrant */#define itoa(n) fmtulong(n, 10, intbuf, sizeof(intbuf), 0);#define dtoa(n, p, f) numtoa(n, 10, p, f)#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}#define GETARG(type) (va_arg(args, type))/* Macros that do proper sign extension and handle length modifiers. Used for the integer conversion specifiers. */#define GETSIGNED(p) \ (((p)->flags & PF_LONGINT) \ ? GETARG (long) \ : (((p)->flags & PF_SHORTINT) ? (long)(short)GETARG (int) \ : (long)GETARG (int)))#define GETUNSIGNED(p) \ (((p)->flags & PF_LONGINT) \ ? GETARG (unsigned long) \ : (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)GETARG (int) \ : (unsigned long)GETARG (unsigned int)))#ifdef HAVE_LONG_DOUBLE#define GETLDOUBLE(p) GETARG (long double)#endif#define GETDOUBLE(p) GETARG (double)#define SET_SIZE_FLAGS(p, type) \ if (sizeof (type) > sizeof (int)) \ (p)->flags |= PF_LONGINT; \ if (sizeof (type) > sizeof (long)) \ (p)->flags |= PF_LONGLONG;/* this struct holds everything we need */struct DATA{ int length; char *base; /* needed for [v]asprintf */ char *holder; int counter; const char *pf;/* FLAGS */ int flags; int justify; int width, precision; char pad;};/* the floating point stuff */#ifdef FLOATING_POINTstatic double pow_10 __P((int));static int log_10 __P((double));static double integral __P((double, double *));static char *numtoa __P((double, int, int, char **));#endifstatic void init_data __P((struct DATA *, char *, size_t, const char *, int));static void init_conv_flag __P((struct DATA *));/* for the format */#ifdef FLOATING_POINTstatic void floating __P((struct DATA *, double));static void exponent __P((struct DATA *, double));#endifstatic void number __P((struct DATA *, unsigned long, int));#ifdef HAVE_LONG_LONGstatic void lnumber __P((struct DATA *, unsigned long long, int));#endifstatic void pointer __P((struct DATA *, unsigned long));static void strings __P((struct DATA *, char *));#ifdef FLOATING_POINT# define FALLBACK_FMTSIZE 32# define FALLBACK_BASE 4096# define LFALLBACK_BASE 5120# ifdef HAVE_LONG_DOUBLEstatic void ldfallback __P((struct DATA *, const char *, const char *, long double));# endifstatic void dfallback __P((struct DATA *, const char *, const char *, double));#endifstatic char *groupnum __P((char *));#ifndef HAVE_ISINF_IN_LIBCstatic int isinf __P((double));#endif#ifndef HAVE_ISNAN_IN_LIBCstatic int isnan __P((double));#endif#ifdef DRIVERstatic void memory_error_and_abort ();static void *xmalloc __P((size_t));static void *xrealloc __P((void *, size_t));static void xfree __P((void *));#else# include <xmalloc.h>#endif/* those are defines specific to snprintf to hopefully * make the code clearer :-) */#define RIGHT 1#define LEFT 0#define NOT_FOUND -1#define FOUND 1#define MAX_FIELD 15/* round off to the precision */#define ROUND(d, p) \ (d < 0.) ? \ d - pow_10(-(p)->precision) * 0.5 : \ d + pow_10(-(p)->precision) * 0.5/* set default precision */#define DEF_PREC(p) \ if ((p)->precision == NOT_FOUND) \ (p)->precision = 6/* put a char. increment the number of chars written even if we've exceeded the vsnprintf/snprintf buffer size (for the return value) */#define PUT_CHAR(c, p) \ do \ { \ if (((p)->flags & PF_ALLOCBUF) && ((p)->counter >= (p)->length - 1)) \ { \ (p)->length += ASBUFSIZE; \ (p)->base = (char *)xrealloc((p)->base, (p)->length); \ (p)->holder = (p)->base + (p)->counter; /* in case reallocated */ \ } \ if ((p)->counter < (p)->length) \ *(p)->holder++ = (c); \ (p)->counter++; \ } \ while (0)/* Output a string. P->WIDTH has already been adjusted for padding. */#define PUT_STRING(string, len, p) \ do \ { \ PAD_RIGHT (p); \ while ((len)-- > 0) \ { \ PUT_CHAR (*(string), (p)); \ (string)++; \ } \ PAD_LEFT (p); \ } \ while (0)#define PUT_PLUS(d, p, zero) \ if ((d) > zero && (p)->justify == RIGHT) \ PUT_CHAR('+', p)#define PUT_SPACE(d, p, zero) \ if (((p)->flags & PF_SPACE) && (d) > zero) \ PUT_CHAR(' ', p)/* pad right */ #define PAD_RIGHT(p) \ if ((p)->width > 0 && (p)->justify != LEFT) \ for (; (p)->width > 0; (p)->width--) \ PUT_CHAR((p)->pad, p)/* pad left */#define PAD_LEFT(p) \ if ((p)->width > 0 && (p)->justify == LEFT) \ for (; (p)->width > 0; (p)->width--) \ PUT_CHAR((p)->pad, p)/* pad with zeros from decimal precision */#define PAD_ZERO(p) \ if ((p)->precision > 0) \ for (; (p)->precision > 0; (p)->precision--) \ PUT_CHAR('0', p)/* if width and prec. in the args */#define STAR_ARGS(p) \ do { \ if ((p)->flags & PF_STAR_W) \ { \ (p)->width = GETARG (int); \ if ((p)->width < 0) \ { \ (p)->flags |= PF_LADJUST; \ (p)->justify = LEFT; \ (p)->width = -(p)->width; \ } \ } \ if ((p)->flags & PF_STAR_P) \ { \ (p)->precision = GETARG (int); \ if ((p)->precision < 0) \ { \ (p)->flags &= ~PF_STAR_P; \ (p)->precision = NOT_FOUND; \ } \ } \ } while (0)#if defined (HAVE_LOCALE_H) && defined (HAVE_LOCALECONV)# define GETLOCALEDATA(d, t, g) \ do \ { \ struct lconv *lv; \ if ((d) == 0) { \ (d) = '.'; (t) = -1; (g) = 0; /* defaults */ \ lv = localeconv(); \ if (lv) \ { \ if (lv->decimal_point && lv->decimal_point[0]) \ (d) = lv->decimal_point[0]; \ if (lv->thousands_sep && lv->thousands_sep[0]) \ (t) = lv->thousands_sep[0]; \ (g) = lv->grouping ? lv->grouping : ""; \ if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \ } \ } \ } \ while (0);#else# define GETLOCALEDATA(d, t, g) \ ( (d) = '.', (t) = ',', g = "\003" )#endif#ifdef FLOATING_POINT/* * Find the nth power of 10 */static doublepow_10(n) int n;{ double P; /* handle common cases with fast switch statement. */ switch (n) { case -3: return .001; case -2: return .01; case -1: return .1; case 0: return 1.; case 1: return 10.; case 2: return 100.; case 3: return 1000.; } if (n < 0) { P = .0001; for (n += 4; n < 0; n++) P /= 10.; } else { P = 10000.; for (n -= 4; n > 0; n--) P *= 10.; } 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; * * NOTE: do not call this with r == 0 -- an infinite loop results. */static intlog_10(r) double r;{ int i = 0; double result = 1.; if (r < 0.) r = -r; if (r < 1.) { while (result >= r) { result /= 10.; 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 */static doubleintegral(real, ip) double real; double *ip;{ int j; double i, s, p; double real_integral = 0.; /* take care of the obvious */ /* equal to zero ? */ if (real == 0.) { *ip = 0.;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -