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 + -
显示快捷键?