ap_snprintf.c
来自「以便Apache与其他服务进行整合 Mod_JK安装」· C语言 代码 · 共 1,179 行 · 第 1/3 页
C
1,179 行
/* 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. *//* * 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. */#define BUILD_STANDALONE#ifndef BUILD_STANDALONE#include "httpd.h"#else#include "ap_snprintf.h"#endif#include <stdio.h>#include <ctype.h>#ifndef NETWARE#include <sys/types.h>#endif#include <stdarg.h>#include <string.h>#include <stdlib.h>#include <math.h>#ifdef WIN32#include <float.h>#endiftypedef enum { NO = 0, YES = 1} boolean_e;#ifndef FALSE#define FALSE 0#endif#ifndef TRUE#define TRUE 1#endif#ifndef AP_LONGEST_LONG#define AP_LONGEST_LONG long#endif#define NUL '\0'#define WIDE_INT long#define WIDEST_INT AP_LONGEST_LONGtypedef WIDE_INT wide_int;typedef unsigned WIDE_INT u_wide_int;typedef WIDEST_INT widest_int;#ifdef __TANDEM/* Although Tandem supports "long long" there is no unsigned variant. */typedef unsigned long u_widest_int;#elsetypedef unsigned WIDEST_INT 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 * * XXX: 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. *//* * 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/* buf must have at least NDIG bytes */static char *ap_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; *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, char *buf){ return (ap_cvt(arg, ndigits, decpt, sign, 1, buf));}static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf){ return (ap_cvt(arg, ndigits, decpt, sign, 0, buf));}/* * ap_gcvt - Floating output conversion to * minimal length string */static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform){ int sign, decpt; register char *p1, *p2; register int i; char buf1[NDIG]; p1 = ap_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 >= 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 ( ap_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 && !is_unsigned))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?