📄 apr_snprintf.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "apr.h"
#include "apr_private.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "apr_network_io.h"
#include "apr_portable.h"
#include <math.h>
#if APR_HAVE_CTYPE_H
#include <ctype.h>
#endif
#if APR_HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if APR_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if APR_HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#if APR_HAVE_LIMITS_H
#include <limits.h>
#endif
#if APR_HAVE_STRING_H
#include <string.h>
#endif
typedef enum {
NO = 0, YES = 1
} boolean_e;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#define NUL '\0'
#define WIDE_INT long
typedef WIDE_INT wide_int;
typedef unsigned WIDE_INT u_wide_int;
typedef apr_int64_t widest_int;
#ifdef __TANDEM
/* Although Tandem supports "long long" there is no unsigned variant. */
typedef unsigned long u_widest_int;
#else
typedef apr_uint64_t u_widest_int;
#endif
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
*
* NOTICE: this is a magic number; do not decrease it
*/
#define NUM_BUF_SIZE 512
/*
* cvt.c - IEEE floating point formatting routines for FreeBSD
* from GNU libc-4.6.27. Modified to be thread safe.
*/
/*
* apr_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
/* buf must have at least NDIG bytes */
static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign,
int eflag, char *buf)
{
register int r2;
double fi, fj;
register char *p, *p1;
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 (p1 > &buf[0] && 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;
if (p1 < &buf[0]) {
*decpt = -ndigits;
buf[0] = '\0';
return (buf);
}
*decpt = r2;
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 *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
{
return (apr_cvt(arg, ndigits, decpt, sign, 1, buf));
}
static char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
{
return (apr_cvt(arg, ndigits, decpt, sign, 0, buf));
}
/*
* apr_gcvt - Floating output conversion to
* minimal length string
*/
static char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform)
{
int sign, decpt;
register char *p1, *p2;
register int i;
char buf1[NDIG];
p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1);
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] == '.' && !altform)
p2--;
*p2 = '\0';
return (buf);
}
/*
* 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) { \
if (sp >= bep) { \
vbuff->curpos = sp; \
if (flush_func(vbuff)) \
return -1; \
sp = vbuff->curpos; \
bep = vbuff->endpos; \
} \
*sp++ = (c); \
} \
cc++; \
}
#define NUM(c) (c - '0')
#define STR_TO_DEC(str, num) \
num = NUM(*str++); \
while (apr_isdigit(*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. We don't allow precision to be large
* enough that we continue past the start of s.
*
* NOTE: this makes use of the magic info that s is
* always based on num_buf with a size of NUM_BUF_SIZE.
*/
#define FIX_PRECISION(adjust, precision, s, s_len) \
if (adjust) { \
int p = precision < NUM_BUF_SIZE - 1 ? precision : NUM_BUF_SIZE - 1; \
while (s_len < p) \
{ \
*--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 ])
*
* Note: we have 2 versions. One is used when we need to use quads
* (conv_10_quad), the other when we don't (conv_10). We're assuming the
* latter is faster.
*/
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 = (char) (magnitude - new_magnitude * 10 + '0');
magnitude = new_magnitude;
}
while (magnitude);
*len = buf_end - p;
return (p);
}
static char *conv_10_quad(widest_int num, register bool_int is_unsigned,
register bool_int *is_negative, char *buf_end,
register int *len)
{
register char *p = buf_end;
u_widest_int magnitude;
/*
* We see if we can use the faster non-quad version by checking the
* number against the largest long value it can be. If <=, we
* punt to the quicker version.
*/
if ((num <= ULONG_MAX && is_unsigned)
|| (num <= LONG_MAX && num >= LONG_MIN && !is_unsigned))
return(conv_10( (wide_int)num, is_unsigned, is_negative,
buf_end, len));
if (is_unsigned) {
magnitude = (u_widest_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) {
widest_int t = num + 1;
magnitude = ((u_widest_int) -t) + 1;
}
else
magnitude = (u_widest_int) num;
}
/*
* We use a do-while loop so that we write at least 1 digit
*/
do {
u_widest_int new_magnitude = magnitude / 10;
*--p = (char) (magnitude - new_magnitude * 10 + '0');
magnitude = new_magnitude;
}
while (magnitude);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -