📄 snprintf.c
字号:
/* ====================================================================
* Copyright (c) 1995-1998 The Apache Group. All rights reserved.
*
* 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 acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 5. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED 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 APACHE GROUP OR
* ITS 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 software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
* This code is based on, and used with the permission of, the
* SIO stdio-replacement strx_* functions by Panos Tsirigotis
* <panos@alumni.cs.colorado.edu> for xinetd.
*/
#include "libxode.h"
#include "globaldata.h"
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#ifdef HAVE_GCVT
#define ap_ecvt ecvt
#define ap_fcvt fcvt
#define ap_gcvt gcvt
#else
/*
* cvt.c - IEEE floating point formatting routines for FreeBSD
* from GNU libc-4.6.27
*/
/*
* ap_ecvt converts to decimal
* the number of digits is specified by ndigit
* decpt is set to the position of the decimal point
* sign is set to 0 for positive, 1 for negative
*/
//#define NDIG 80
static char *
ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, Globaldata* g )
{
register int r2;
double fi, fj;
register char *p, *p1;
//static char buf[NDIG];
char* buf = g->_snprintf_ap_cvt_ndig_buf;
if (ndigits >= NDIG - 1)
ndigits = NDIG - 2;
r2 = 0;
*sign = 0;
p = &buf[0];
if (arg < 0) {
*sign = 1;
arg = -arg;
}
arg = modf(arg, &fi);
p1 = &buf[NDIG];
/*
* Do integer part
*/
if (fi != 0) {
p1 = &buf[NDIG];
while (fi != 0) {
fj = modf(fi / 10, &fi);
*--p1 = (int) ((fj + .03) * 10) + '0';
r2++;
}
while (p1 < &buf[NDIG])
*p++ = *p1++;
} else if (arg > 0) {
while ((fj = arg * 10) < 1) {
arg = fj;
r2--;
}
}
p1 = &buf[ndigits];
if (eflag == 0)
p1 += r2;
*decpt = r2;
if (p1 < &buf[0]) {
buf[0] = '\0';
return (buf);
}
while (p <= p1 && p < &buf[NDIG]) {
arg *= 10;
arg = modf(arg, &fj);
*p++ = (int) fj + '0';
}
if (p1 >= &buf[NDIG]) {
buf[NDIG - 1] = '\0';
return (buf);
}
p = p1;
*p1 += 5;
while (*p1 > '9') {
*p1 = '0';
if (p1 > buf)
++ * --p1;
else {
*p1 = '1';
(*decpt)++;
if (eflag == 0) {
if (p > buf)
*p = '0';
p++;
}
}
}
*p = '\0';
return (buf);
}
static char *
ap_ecvt(double arg, int ndigits, int *decpt, int *sign, Globaldata* g )
{
return (ap_cvt(arg, ndigits, decpt, sign, 1, g));
}
static char *
ap_fcvt(double arg, int ndigits, int *decpt, int *sign, Globaldata* g )
{
return (ap_cvt(arg, ndigits, decpt, sign, 0, g));
}
/*
* ap_gcvt - Floating output conversion to
* minimal length string
*/
static char *
ap_gcvt(double number, int ndigit, char *buf, Globaldata* g)
{
int sign, decpt;
register char *p1, *p2;
int i;
p1 = ap_ecvt(number, ndigit, &decpt, &sign, g);
p2 = buf;
if (sign)
*p2++ = '-';
for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
ndigit--;
if ((decpt >= 0 && decpt - ndigit > 4)
|| (decpt < 0 && decpt < -3)) { /* use E-style */
decpt--;
*p2++ = *p1++;
*p2++ = '.';
for (i = 1; i < ndigit; i++)
*p2++ = *p1++;
*p2++ = 'e';
if (decpt < 0) {
decpt = -decpt;
*p2++ = '-';
} else
*p2++ = '+';
if (decpt / 100 > 0)
*p2++ = decpt / 100 + '0';
if (decpt / 10 > 0)
*p2++ = (decpt % 100) / 10 + '0';
*p2++ = decpt % 10 + '0';
} else {
if (decpt <= 0) {
if (*p1 != '0')
*p2++ = '.';
while (decpt < 0) {
decpt++;
*p2++ = '0';
}
}
for (i = 1; i <= ndigit; i++) {
*p2++ = *p1++;
if (i == decpt)
*p2++ = '.';
}
if (ndigit < decpt) {
while (ndigit++ < decpt)
*p2++ = '0';
*p2++ = '.';
}
}
if (p2[-1] == '.')
p2--;
*p2 = '\0';
return (buf);
}
#endif /* HAVE_CVT */
typedef enum {
NO = 0, YES = 1
} boolean_e;
#define FALSE 0
#define TRUE 1
#define NUL '\0'
#define INT_NULL ((int *)0)
#define WIDE_INT long
typedef WIDE_INT wide_int;
typedef unsigned WIDE_INT u_wide_int;
typedef int bool_int;
#define S_NULL "(null)"
#define S_NULL_LEN 6
#define FLOAT_DIGITS 6
#define EXPONENT_LENGTH 10
/*
* NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
*
* XXX: this is a magic number; do not decrease it
*/
#define NUM_BUF_SIZE 512
/*
* Descriptor for buffer area
*/
struct buf_area {
char *buf_end;
char *nextb; /* pointer to next byte to read/write */
};
typedef struct buf_area buffy;
/*
* The INS_CHAR macro inserts a character in the buffer and writes
* the buffer back to disk if necessary
* It uses the char pointers sp and bep:
* sp points to the next available character in the buffer
* bep points to the end-of-buffer+1
* While using this macro, note that the nextb pointer is NOT updated.
*
* NOTE: Evaluation of the c argument should not have any side-effects
*/
#define INS_CHAR( c, sp, bep, cc ) \
{ \
if ( sp < bep ) \
{ \
*sp++ = c ; \
cc++ ; \
} \
}
#define NUM( c ) ( c - '0' )
#define STR_TO_DEC( str, num ) \
num = NUM( *str++ ) ; \
while ( isdigit((int)*str ) ) \
{ \
num *= 10 ; \
num += NUM( *str++ ) ; \
}
/*
* This macro does zero padding so that the precision
* requirement is satisfied. The padding is done by
* adding '0's to the left of the string that is going
* to be printed.
*/
#define FIX_PRECISION( adjust, precision, s, s_len ) \
if ( adjust ) \
while ( s_len < precision ) \
{ \
*--s = '0' ; \
s_len++ ; \
}
/*
* Macro that does padding. The padding is done by printing
* the character ch.
*/
#define PAD( width, len, ch ) do \
{ \
INS_CHAR( ch, sp, bep, cc ) ; \
width-- ; \
} \
while ( width > len )
/*
* Prefix the character ch to the string str
* Increase length
* Set the has_prefix flag
*/
#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES
/*
* Convert num to its decimal format.
* Return value:
* - a pointer to a string containing the number (no sign)
* - len contains the length of the string
* - is_negative is set to TRUE or FALSE depending on the sign
* of the number (always set to FALSE if is_unsigned is TRUE)
*
* The caller provides a buffer for the string: that is the buf_end argument
* which is a pointer to the END of the buffer + 1 (i.e. if the buffer
* is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
*/
static char *
conv_10(register wide_int num, register bool_int is_unsigned,
register bool_int * is_negative, char *buf_end, register int *len)
{
register char *p = buf_end;
register u_wide_int magnitude;
if (is_unsigned) {
magnitude = (u_wide_int) num;
*is_negative = FALSE;
} else {
*is_negative = (num < 0);
/*
* On a 2's complement machine, negating the most negative integer
* results in a number that cannot be represented as a signed integer.
* Here is what we do to obtain the number's magnitude:
* a. add 1 to the number
* b. negate it (becomes positive)
* c. convert it to unsigned
* d. add 1
*/
if (*is_negative) {
wide_int t = num + 1;
magnitude = ((u_wide_int) - t) + 1;
} else
magnitude = (u_wide_int) num;
}
/*
* We use a do-while loop so that we write at least 1 digit
*/
do {
register u_wide_int new_magnitude = magnitude / 10;
*--p = magnitude - new_magnitude * 10 + '0';
magnitude = new_magnitude;
}
while (magnitude);
*len = buf_end - p;
return (p);
}
/*
* Convert a floating point number to a string formats 'f', 'e' or 'E'.
* The result is placed in buf, and len denotes the length of the string
* The sign is returned in the is_negative argument (and is not placed
* in buf).
*/
static char *
conv_fp(register char format, register double num,
boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len, Globaldata* g)
{
register char *s = buf;
register char *p;
int decimal_point;
if (format == 'f')
p = ap_fcvt(num, precision, &decimal_point, is_negative, g);
else /* either e or E format */
p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, g);
/*
* Check for Infinity and NaN
*/
if (isalpha((int)*p)) {
*len = strlen(strcpy(buf, p));
*is_negative = FALSE;
return (buf);
}
if (format == 'f') {
if (decimal_point <= 0) {
*s++ = '0';
if (precision > 0) {
*s++ = '.';
while (decimal_point++ < 0)
*s++ = '0';
} else if (add_dp) {
*s++ = '.';
}
} else {
while (decimal_point-- > 0) {
*s++ = *p++;
}
if (precision > 0 || add_dp) {
*s++ = '.';
}
}
} else {
*s++ = *p++;
if (precision > 0 || add_dp)
*s++ = '.';
}
/*
* copy the rest of p, the NUL is NOT copied
*/
while (*p)
*s++ = *p++;
if (format != 'f') {
char temp[EXPONENT_LENGTH]; /* for exponent conversion */
int t_len;
bool_int exponent_is_negative;
*s++ = format; /* either e or E */
decimal_point--;
if (decimal_point != 0) {
p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
&temp[EXPONENT_LENGTH], &t_len);
*s++ = exponent_is_negative ? '-' : '+';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -