📄 apr_snprintf.c
字号:
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed 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>#endiftypedef 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 longtypedef 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;#elsetypedef apr_uint64_t u_widest_int;#endiftypedef 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 + -