OSSP CVS Repository

ossp - Check-in [5008]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 5008
Date: 2005-Feb-03 10:45:37 (local)
2005-Feb-03 09:45:37 (UTC)
User:thl
Branch:
Comment: resolve trunc symbol conflict; make sure configure checks for isnan and isinf and l2_ut_format picks up the results
Tickets:
Inspections:
Files:
ossp-pkg/l2/configure.ac      1.29 -> 1.30     1 inserted, 1 deleted
ossp-pkg/l2/l2_ut_format.c      added-> 1.11

ossp-pkg/l2/configure.ac 1.29 -> 1.30

--- configure.ac 2005/02/03 09:40:34     1.29
+++ configure.ac 2005/02/03 09:45:37     1.30
@@ -57,7 +57,7 @@
 
 AC_CHECK_HEADERS(sys/time.h)
 
-AC_CHECK_FUNCS(inet_aton inet_pton inet_ntoa inet_ntop snprintf vsnprintf setitimer)
+AC_CHECK_FUNCS(inet_aton inet_pton inet_ntoa inet_ntop snprintf vsnprintf setitimer isnan isinf)
 
 CHECK_VA_COPY
 


ossp-pkg/l2/l2_ut_format.c -> 1.11

*** /dev/null    Fri Apr 26 15:01:11 2024
--- -    Fri Apr 26 15:01:52 2024
***************
*** 0 ****
--- 1,1190 ----
+ /*
+ **  OSSP l2 - Flexible Logging
+ **  Copyright (c) 2001-2004 Cable & Wireless <http://www.cw.com/>
+ **  Copyright (c) 2001-2004 The OSSP Project <http://www.ossp.org/>
+ **  Copyright (c) 2001-2004 Ralf S. Engelschall <rse@engelschall.com>
+ **
+ **  This file is part of OSSP l2, a flexible logging library which
+ **  can be found at http://www.ossp.org/pkg/lib/l2/.
+ **
+ **  Permission to use, copy, modify, and distribute this software for
+ **  any purpose with or without fee is hereby granted, provided that
+ **  the above copyright notice and this permission notice appear in all
+ **  copies.
+ **
+ **  THIS SOFTWARE IS PROVIDED ``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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+ **  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.
+ **
+ **  l2_ut_format.c: printf(3)-style formatting
+ */
+ 
+ /*
+  * This is a generic printf-style formatting code which is based on
+  * Apache's ap_snprintf which it turn 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. The IEEE
+  * floating point formatting routines are derived from an anchient
+  * FreeBSD version which took it from GNU libc-4.6.27 and modified it
+  * to be thread safe. The whole code was finally cleaned up, stripped
+  * and extended by Ralf S. Engelschall for use inside the Str library.
+  * Especially any Apache and network specific kludges were removed again
+  * and instead the formatting engine now can be extended by the caller
+  * on-the-fly. It was then finally adjusted to be stand-alone for use
+  * inside OSSP l2.
+  */
+ 
+ /*
+  * The Apache Software License, Version 1.1
+  *
+  * Copyright (c) 2000-2002 The Apache Software Foundation.  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. The end-user documentation included with the redistribution,
+  *    if any, must include the following acknowledgment:
+  *       "This product includes software developed by the
+  *        Apache Software Foundation (http://www.apache.org/)."
+  *    Alternately, this acknowledgment may appear in the software itself,
+  *    if and wherever such third-party acknowledgments normally appear.
+  *
+  * 4. The names "Apache" and "Apache Software Foundation" must
+  *    not be used to endorse or promote products derived from this
+  *    software without prior written permission. For written
+  *    permission, please contact apache@apache.org.
+  *
+  * 5. Products derived from this software may not be called "Apache",
+  *    nor may "Apache" appear in their name, without prior written
+  *    permission of the Apache Software Foundation.
+  *
+  * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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.
+  */
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <stdarg.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <math.h>
+ 
+ #include "l2_config.h"
+ #include "l2_ut_format.h"
+ 
+ /* types which are locally use */
+ typedef long                 long_int;
+ typedef unsigned long      u_long_int;
+ #if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG > 0)
+ typedef long long            quad_int;
+ typedef unsigned long long u_quad_int;
+ #else
+ typedef long                 quad_int;
+ typedef unsigned long      u_quad_int;
+ #endif
+ 
+ /* a few handy defines */
+ #ifndef NUL
+ #define NUL '\0'
+ #endif
+ #ifndef NULL
+ #define NULL ((void *)0)
+ #endif
+ #ifndef FALSE
+ #define FALSE (0)
+ #endif
+ #ifndef TRUE
+ #define TRUE (!FALSE)
+ #endif
+ #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. This is a magic number; do NOT decrease it! */
+ #define NUM_BUF_SIZE    512
+ #define NDIG            80
+ 
+ /* compatibility */
+ #if !defined(HAVE_ISNAN)
+ #define isnan(d) (0)
+ #endif
+ #if !defined(HAVE_ISINF)
+ #define isinf(d) (0)
+ #endif
+ 
+ /* explicit support for unsigned char based ctype stuff */
+ #define l2_util_isalpha(c)  (isalpha(((unsigned char)(c))))
+ #define l2_util_isdigit(c)  (isdigit(((unsigned char)(c))))
+ #define l2_util_isxdigit(c) (isxdigit(((unsigned char)(c))))
+ #define l2_util_islower(c)  (islower(((unsigned char)(c))))
+ #define l2_util_tolower(c)  (tolower((unsigned char)(c)))
+ 
+ /*
+  * Convert decimal number to its string representation. 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. buf must
+  * have at least NDIG bytes.
+  */
+ 
+ #define l2_util_ecvt(arg,ndigits,decpt,sign,buf) \
+         l2_util_cvt((arg), (ndigits), (decpt), (sign), 1, (buf))
+ 
+ #define l2_util_fcvt(arg,ndigits,decpt,sign,buf) \
+         l2_util_cvt((arg), (ndigits), (decpt), (sign), 0, (buf))
+ 
+ /* inlined modf(3) to avoid dependency to external libm on systems
+    (like Tru64, QNX, etc) where modf(3) is not part of libc.
+    We use trnc to avoid conflicts with global definitions of trunc and truncate */
+ static double
+ l2_util_modf(
+     double arg,
+     double *iptr)
+ {
+     double fraction;
+     double integral;
+     long trnc;
+ 
+     trnc = (long)arg;
+     integral = (double)trnc;
+     fraction = arg - integral;
+     if (iptr != NULL)
+         *iptr = integral;
+     return fraction;
+ }
+ 
+ static char *
+ l2_util_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 = FALSE;
+     p = &buf[0];
+     if (arg < 0) {
+         *sign = TRUE;
+         arg = -arg;
+     }
+     arg = l2_util_modf(arg, &fi);
+     p1 = &buf[NDIG];
+ 
+     /* Do integer part */
+     if (fi != 0) {
+         p1 = &buf[NDIG];
+         while (fi != 0 && p1 > &buf[0]) {
+             fj = l2_util_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] = NUL;
+         return (buf);
+     }
+     while (p <= p1 && p < &buf[NDIG]) {
+         arg *= 10;
+         arg = l2_util_modf(arg, &fj);
+         *p++ = (int) fj + '0';
+     }
+     if (p1 >= &buf[NDIG]) {
+         buf[NDIG - 1] = NUL;
+         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 = NUL;
+     return buf;
+ }
+ 
+ static char *
+ l2_util_gcvt(
+     double number,
+     int ndigit,
+     char *buf,
+     int altform)
+ {
+     int sign;
+     int decpt;
+     register char *p1, *p2;
+     register int i;
+     char buf1[NDIG];
+ 
+     p1 = l2_util_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 = NUL;
+     return buf;
+ }
+ 
+ /*
+  * The INS_CHAR macro inserts a character in the buffer and flushes the
+  * buffer 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 (vbuff->flush(vbuff))    \
+             return -1;              \
+         sp = vbuff->curpos;         \
+         bep = vbuff->endpos;        \
+     }                               \
+     *sp++ = (c);                    \
+     cc++;                           \
+ }
+ 
+ /*
+  * Convert a string to decimal value
+  */
+ #define NUM(c) ((c) - '0')
+ #define STR_TO_DEC(str, num) {    \
+     num = NUM(*str++);            \
+     while (l2_util_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.
+  */
+ #define FIX_PRECISION(adjust, precision, s, s_len)  \
+     if (adjust) {                                   \
+         while (s_len < precision) {                 \
+             *--s = '0';                             \
+             s_len++;                                \
+         }                                           \
+     }
+ 
+ /*
+  * This macro 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 = TRUE
+ 
+ /*
+  * 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 long_int num,
+     register int is_unsigned,
+     register int *is_negative,
+     char *buf_end,
+     register size_t *len)
+ {
+     register char *p = buf_end;
+     register u_long_int magnitude;
+ 
+     if (is_unsigned) {
+         magnitude = (u_long_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) {
+             long_int t = num + 1;
+ 
+             magnitude = ((u_long_int) - t) + 1;
+         }
+         else
+             magnitude = (u_long_int)num;
+     }
+     /* We use a do-while loop so that we write at least 1 digit */
+     do {
+         register u_long_int new_magnitude = magnitude / 10;
+         *--p = (char) (magnitude - new_magnitude * 10 + '0');
+         magnitude = new_magnitude;
+     } while (magnitude);
+     *len = (int)(buf_end - p);
+     return p;
+ }
+ 
+ static char *
+ conv_10_quad(
+     quad_int num,
+     register int is_unsigned,
+     register int *is_negative,
+     char *buf_end,
+     register size_t *len)
+ {
+     register char *p = buf_end;
+     u_quad_int magnitude;
+ 
+     if (is_unsigned) {
+         magnitude = (u_quad_int)num;
+         *is_negative = FALSE;
+     }
+     else {
+         *is_negative = (num < 0);
+         /* On a 2's complement machine, negating the most negative integer
+            result 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) {
+             quad_int t = num + 1;
+             magnitude = ((u_quad_int) - t) + 1;
+         }
+         else
+             magnitude = (u_quad_int)num;
+     }
+     /* We use a do-while loop so that we write at least 1 digit */
+     do {
+         u_quad_int new_magnitude = magnitude / 10;
+         *--p = (char)(magnitude - new_magnitude * 10 + '0');
+         magnitude = new_magnitude;
+     } while (magnitude);
+     *len = (int)(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,
+     int add_dp,
+     int precision,
+     int *is_negative,
+     char *buf,
+     size_t *len)
+ {
+     register char *s = buf;
+     register char *p;
+     int decimal_point;
+     char buf1[NDIG];
+ 
+     if (format == 'f')
+         p = l2_util_fcvt(num, precision, &decimal_point, is_negative, buf1);
+     else  /* either e or E format */
+         p = l2_util_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
+ 
+     /* Check for Infinity and NaN */
+     if (l2_util_isalpha(*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 */
+         size_t t_len;
+         int exponent_is_negative;
+ 
+         *s++ = format;          /* either e or E */
+         decimal_point--;
+         if (decimal_point != 0) {
+             p = conv_10((long_int) decimal_point, FALSE, &exponent_is_negative,
+                         &temp[EXPONENT_LENGTH], &t_len);
+             *s++ = exponent_is_negative ? '-' : '+';
+             /* Make sure the exponent has at least 2 digits */
+             if (t_len == 1)
+                 *s++ = '0';
+             while (t_len--)
+                 *s++ = *p++;
+         }
+         else {
+             *s++ = '+';
+             *s++ = '0';
+             *s++ = '0';
+         }
+     }
+ 
+     *len = (int)(s - buf);
+     return buf;
+ }
+ 
+ /*
+  * Convert num to a base X number where X is a power of 2. nbits determines X.
+  * For example, if nbits is 3, we do base 8 conversion
+  * Return value:
+  *      a pointer to a string containing the number
+  * 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]) As with
+  * conv_10, we have a faster version which is used when the number isn't
+  * quad size.
+  */
+ 
+ static const char low_digits[]   = "0123456789abcdef";
+ static const char upper_digits[] = "0123456789ABCDEF";
+ 
+ static char *
+ conv_p2(
+     register u_long_int num,
+     register int nbits,
+     char format,
+     char *buf_end,
+     register size_t *len)
+ {
+     register int mask = (1 << nbits) - 1;
+     register char *p = buf_end;
+     register const char *digits = (format == 'X') ? upper_digits : low_digits;
+ 
+     do {
+         *--p = digits[num & mask];
+         num >>= nbits;
+     } while (num);
+     *len = (int)(buf_end - p);
+     return p;
+ }
+ 
+ static char *
+ conv_p2_quad(
+     u_quad_int num,
+     register int nbits,
+     char format,
+     char *buf_end,
+     register size_t *len)
+ {
+     register int mask = (1 << nbits) - 1;
+     register char *p = buf_end;
+     register const char *digits = (format == 'X') ? upper_digits : low_digits;
+ 
+     do {
+         *--p = digits[num & mask];
+         num >>= nbits;
+     } while (num);
+     *len = (size_t)(buf_end - p);
+     return p;
+ }
+ 
+ /*
+  * l2_util_format(), the generic printf-style formatting routine
+  * and heart of this piece of source.
+  */
+ int
+ l2_util_format(
+     l2_util_format_t *vbuff,
+     const char *fmt,
+     va_list ap)
+ {
+     register char *sp;
+     register char *bep;
+     register int cc = 0;
+     register int i;
+ 
+     char *s = NULL;
+     char *q;
+     size_t s_len;
+ 
+     register int min_width = 0;
+     int precision = 0;
+     enum { LEFT, RIGHT } adjust;
+     char pad_char;
+     char prefix_char;
+ 
+     double fp_num;
+     quad_int i_quad = (quad_int)0;
+     u_quad_int ui_quad;
+     long_int i_num = (long_int)0;
+     u_long_int ui_num;
+ 
+     char num_buf[NUM_BUF_SIZE];
+     char char_buf[2]; /* for printing %% and %<unknown> */
+ 
+     enum var_type_enum { IS_QUAD, IS_LONG, IS_SHORT, IS_INT };
+     enum var_type_enum var_type = IS_INT;
+ 
+     int alternate_form;
+     int print_sign;
+     int print_blank;
+     int adjust_precision;
+     int adjust_width;
+     int is_negative;
+ 
+     char extinfo[20];
+ 
+     sp = vbuff->curpos;
+     bep = vbuff->endpos;
+ 
+     while (*fmt != NUL) {
+         if (*fmt != '%') {
+             INS_CHAR(*fmt, sp, bep, cc);
+         }
+         else {
+             /*
+              * Default variable settings
+              */
+             adjust = RIGHT;
+             alternate_form = print_sign = print_blank = FALSE;
+             pad_char = ' ';
+             prefix_char = NUL;
+             extinfo[0] = NUL;
+ 
+             fmt++;
+ 
+             /*
+              * Try to avoid checking for flags, width or precision
+              */
+             if (!l2_util_islower(*fmt)) {
+                 /*
+                  * Recognize flags: -, #, BLANK, +
+                  */
+                 for (;; fmt++) {
+                     if (*fmt == '{') {
+                         i = 0;
+                         for (fmt++; *fmt != '}' && *fmt != NUL; fmt++) {
+                             if (i < sizeof(extinfo)-1)
+                                 extinfo[i++] = *fmt;
+                         }
+                         extinfo[i] = NUL;
+                     }
+                     else if (*fmt == '-')
+                         adjust = LEFT;
+                     else if (*fmt == '+')
+                         print_sign = TRUE;
+                     else if (*fmt == '#')
+                         alternate_form = TRUE;
+                     else if (*fmt == ' ')
+                         print_blank = TRUE;
+                     else if (*fmt == '0')
+                         pad_char = '0';
+                     else
+                         break;
+                 }
+ 
+                 /*
+                  * Check if a width was specified
+                  */
+                 if (l2_util_isdigit(*fmt)) {
+                     STR_TO_DEC(fmt, min_width);
+                     adjust_width = TRUE;
+                 }
+                 else if (*fmt == '*') {
+                     min_width = va_arg(ap, int);
+                     fmt++;
+                     adjust_width = TRUE;
+                     if (min_width < 0) {
+                         adjust = LEFT;
+                         min_width = -min_width;
+                     }
+                 }
+                 else
+                     adjust_width = FALSE;
+ 
+                 /*
+                  * Check if a precision was specified
+                  *
+                  * XXX: an unreasonable amount of precision may be specified
+                  * resulting in overflow of num_buf. Currently we
+                  * ignore this possibility.
+                  */
+                 if (*fmt == '.') {
+                     adjust_precision = TRUE;
+                     fmt++;
+                     if (l2_util_isdigit(*fmt)) {
+                         STR_TO_DEC(fmt, precision);
+                     }
+                     else if (*fmt == '*') {
+                         precision = va_arg(ap, int);
+                         fmt++;
+                         if (precision < 0)
+                             precision = 0;
+                     }
+                     else
+                         precision = 0;
+                 }
+                 else
+                     adjust_precision = FALSE;
+             }
+             else
+                 adjust_precision = adjust_width = FALSE;
+ 
+             /*
+              * Modifier check
+              */
+             if (*fmt == 'q') {
+                 var_type = IS_QUAD;
+                 fmt++;
+             }
+             else if (*fmt == 'l') {
+                 var_type = IS_LONG;
+                 fmt++;
+             }
+             else if (*fmt == 'h') {
+                 var_type = IS_SHORT;
+                 fmt++;
+             }
+             else {
+                 var_type = IS_INT;
+             }
+ 
+             /*
+              * Argument extraction and printing.
+              * First we determine the argument type.
+              * Then, we convert the argument to a string.
+              * On exit from the switch, s points to the string that
+              * must be printed, s_len has the length of the string
+              * The precision requirements, if any, are reflected in s_len.
+              *
+              * NOTE: pad_char may be set to '0' because of the 0 flag.
+              *   It is reset to ' ' by non-numeric formats
+              */
+             switch (*fmt) {
+ 
+                 /* Unsigned Decimal Integer */
+                 case 'u':
+                     if (var_type == IS_QUAD) {
+                         i_quad = va_arg(ap, u_quad_int);
+                         s = conv_10_quad(i_quad, 1, &is_negative,
+                                          &num_buf[NUM_BUF_SIZE], &s_len);
+                     }
+                     else {
+                         if (var_type == IS_LONG)
+                             i_num = (long_int)va_arg(ap, u_long_int);
+                         else if (var_type == IS_SHORT)
+                             i_num = (long_int)(unsigned short)va_arg(ap, unsigned int);
+                         else
+                             i_num = (long_int)va_arg(ap, unsigned int);
+                         s = conv_10(i_num, 1, &is_negative,
+                                     &num_buf[NUM_BUF_SIZE], &s_len);
+                     }
+                     FIX_PRECISION(adjust_precision, precision, s, s_len);
+                     break;
+ 
+                 /* Signed Decimal Integer */
+                 case 'd':
+                 case 'i':
+                     if (var_type == IS_QUAD) {
+                         i_quad = va_arg(ap, quad_int);
+                         s = conv_10_quad(i_quad, 0, &is_negative,
+                                          &num_buf[NUM_BUF_SIZE], &s_len);
+                     }
+                     else {
+                         if (var_type == IS_LONG)
+                             i_num = (long_int)va_arg(ap, long_int);
+                         else if (var_type == IS_SHORT)
+                             i_num = (long_int)(short)va_arg(ap, int);
+                         else
+                             i_num = (long_int)va_arg(ap, int);
+                         s = conv_10(i_num, 0, &is_negative,
+                                     &num_buf[NUM_BUF_SIZE], &s_len);
+                     }
+                     FIX_PRECISION(adjust_precision, precision, s, s_len);
+ 
+                     if (is_negative)
+                         prefix_char = '-';
+                     else if (print_sign)
+                         prefix_char = '+';
+                     else if (print_blank)
+                         prefix_char = ' ';
+                     break;
+ 
+                 /* Unsigned Octal Integer */
+                 case 'o':
+                     if (var_type == IS_QUAD) {
+                         ui_quad = va_arg(ap, u_quad_int);
+                         s = conv_p2_quad(ui_quad, 3, *fmt,
+                                          &num_buf[NUM_BUF_SIZE], &s_len);
+                     }
+                     else {
+                         if (var_type == IS_LONG)
+                             ui_num = (u_long_int) va_arg(ap, u_long_int);
+                         else if (var_type == IS_SHORT)
+                             ui_num = (u_long_int)(unsigned short)va_arg(ap, unsigned int);
+                         else
+                             ui_num = (u_long_int)va_arg(ap, unsigned int);
+                         s = conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
+                     }
+                     FIX_PRECISION(adjust_precision, precision, s, s_len);
+                     if (alternate_form && *s != '0') {
+                         *--s = '0';
+                         s_len++;
+                     }
+                     break;
+ 
+                 /* Unsigned Hexadecimal Integer */
+                 case 'x':
+                 case 'X':
+                     if (var_type == IS_QUAD) {
+                         ui_quad = va_arg(ap, u_quad_int);
+                         s = conv_p2_quad(ui_quad, 4, *fmt,
+                                          &num_buf[NUM_BUF_SIZE], &s_len);
+                     }
+                     else {
+                         if (var_type == IS_LONG)
+                             ui_num = (u_long_int)va_arg(ap, u_long_int);
+                         else if (var_type == IS_SHORT)
+                             ui_num = (u_long_int)(unsigned short)va_arg(ap, unsigned int);
+                         else
+                             ui_num = (u_long_int)va_arg(ap, unsigned int);
+                         s = conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
+                     }
+                     FIX_PRECISION(adjust_precision, precision, s, s_len);
+                     if (alternate_form && i_num != 0) {
+                         *--s = *fmt; /* 'x' or 'X' */
+                         *--s = '0';
+                         s_len += 2;
+                     }
+                     break;
+ 
+                 /* String */
+                 case 's':
+                     s = va_arg(ap, char *);
+                     if (s != NULL) {
+                         s_len = strlen(s);
+                         if (adjust_precision && precision < s_len)
+                             s_len = precision;
+                     }
+                     else {
+                         s = S_NULL;
+                         s_len = S_NULL_LEN;
+                     }
+                     pad_char = ' ';
+                     break;
+ 
+                 /* Double Floating Point (style 1) */
+                 case 'f':
+                 case 'e':
+                 case 'E':
+                     fp_num = va_arg(ap, double);
+                     if (isnan(fp_num)) {
+                         s = "NaN";
+                         s_len = 3;
+                     }
+                     else if (isinf(fp_num)) {
+                         s = "Inf";
+                         s_len = 3;
+                     }
+                     else {
+                         /* use &num_buf[1], so that we have room for the sign */
+                         s = conv_fp(*fmt, fp_num, alternate_form,
+                                     (adjust_precision == FALSE) ? FLOAT_DIGITS : precision,
+                                     &is_negative, &num_buf[1], &s_len);
+                         if (is_negative)
+                             prefix_char = '-';
+                         else if (print_sign)
+                             prefix_char = '+';
+                         else if (print_blank)
+                             prefix_char = ' ';
+                     }
+                     break;
+ 
+                 /* Double Floating Point (style 2) */
+                 case 'g':
+                 case 'G':
+                     fp_num = va_arg(ap, double);
+                     if (isnan(fp_num)) {
+                         s = "NaN";
+                         s_len = 3;
+                     }
+                     else if (isinf(fp_num)) {
+                         s = "Inf";
+                         s_len = 3;
+                     }
+                     else {
+                         if (adjust_precision == FALSE)
+                             precision = FLOAT_DIGITS;
+                         else if (precision == 0)
+                             precision = 1;
+                         /* use &num_buf[1], so that we have room for the sign */
+                         s = l2_util_gcvt(fp_num, precision, &num_buf[1], alternate_form);
+                         if (*s == '-')
+                             prefix_char = *s++;
+                         else if (print_sign)
+                             prefix_char = '+';
+                         else if (print_blank)
+                             prefix_char = ' ';
+                         s_len = strlen(s);
+                         if (alternate_form && (q = strchr(s, '.')) == NULL) {
+                             s[s_len++] = '.';
+                             s[s_len] = NUL; /* delimit for following strchr() */
+                         }
+                         if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
+                             *q = 'E';
+                     }
+                     break;
+ 
+                 /* Single Character */
+                 case 'c':
+                     char_buf[0] = (char) (va_arg(ap, int));
+                     s = &char_buf[0];
+                     s_len = 1;
+                     pad_char = ' ';
+                     break;
+ 
+                 /* The '%' Character */
+                 case '%':
+                     char_buf[0] = '%';
+                     s = &char_buf[0];
+                     s_len = 1;
+                     pad_char = ' ';
+                     break;
+ 
+                 /* Special: Number of already written characters */
+                 case 'n':
+                     if (var_type == IS_QUAD)
+                         *(va_arg(ap, quad_int *)) = cc;
+                     else if (var_type == IS_LONG)
+                         *(va_arg(ap, long *)) = cc;
+                     else if (var_type == IS_SHORT)
+                         *(va_arg(ap, short *)) = cc;
+                     else
+                         *(va_arg(ap, int *)) = cc;
+                     break;
+ 
+                 /*
+                  * Pointer argument type.
+                  */
+                 case 'p':
+ #if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == SIZEOF_VOID_P)
+                     ui_quad = (u_quad_int) va_arg(ap, void *);
+                     s = conv_p2_quad(ui_quad, 4, 'x', &num_buf[NUM_BUF_SIZE], &s_len);
+ #else
+                     ui_num = (u_long_int) va_arg(ap, void *);
+                     s = conv_p2(ui_num, 4, 'x', &num_buf[NUM_BUF_SIZE], &s_len);
+ #endif
+                     pad_char = ' ';
+                     break;
+ 
+                 case NUL:
+                     /*
+                      * The last character of the format string was %.
+                      * We ignore it.
+                      */
+                     continue;
+ 
+                 /*
+                  * The default case is for unrecognized %'s. We print
+                  * %<char> to help the user identify what option is not
+                  * understood. This is also useful in case the user
+                  * wants to pass the output of format_converter to
+                  * another function that understands some other %<char>
+                  * (like syslog). Note that we can't point s inside fmt
+                  * because the unknown <char> could be preceded by width
+                  * etc.
+                  */
+                 default:
+                     s = NULL;
+                     if (vbuff->format != NULL) {
+                         vbuff->format(vbuff,
+                                       &prefix_char, &pad_char, &s, &s_len,
+                                       num_buf, NUM_BUF_SIZE, extinfo, *fmt, &ap);
+                         if (s == NULL)
+                             return -1;
+                     }
+                     if (s == NULL) {
+                         char_buf[0] = '%';
+                         char_buf[1] = *fmt;
+                         s = char_buf;
+                         s_len = 2;
+                         pad_char = ' ';
+                     }
+                     break;
+             }
+ 
+             if (prefix_char != NUL && s != S_NULL && s != char_buf) {
+                 *--s = prefix_char;
+                 s_len++;
+             }
+ 
+             if (adjust_width && adjust == RIGHT && min_width > s_len) {
+                 if (pad_char == '0' && prefix_char != NUL) {
+                     INS_CHAR(*s, sp, bep, cc);
+                     s++;
+                     s_len--;
+                     min_width--;
+                 }
+                 PAD(min_width, s_len, pad_char);
+             }
+ 
+             /*
+              * Print the string s.
+              */
+             for (i = s_len; i != 0; i--) {
+                 INS_CHAR(*s, sp, bep, cc);
+                 s++;
+             }
+ 
+             if (adjust_width && adjust == LEFT && min_width > s_len)
+                 PAD(min_width, s_len, pad_char);
+         }
+         fmt++;
+     }
+     vbuff->curpos = sp;
+     return cc;
+ }
+ 
+ /*
+  * l2_util_format -- format a new string.
+  * This is inspired by POSIX sprintf(3), but mainly provides the
+  * following differences: first it is actually a snprintf(3) style, i.e.
+  * it allows one to specify the maximum number of characters which are
+  * allowed to write. Second, it allows one to just count the number of
+  * characters which have to be written.
+  */
+ 
+ #define STR_FORMAT_BUFLEN 20
+ 
+ static int l2_util_flush_fake(l2_util_format_t *out_handle)
+ {
+     out_handle->data[1].i += out_handle->data[2].i;
+     out_handle->curpos = (char *)out_handle->data[0].vp;
+     return 0;
+ }
+ 
+ static int l2_util_flush_real(l2_util_format_t *out_handle)
+ {
+     return -1;
+ }
+ 
+ int l2_util_vsprintf(char *s, size_t n, const char *fmt, va_list ap)
+ {
+     l2_util_format_t handle;
+     char buf[STR_FORMAT_BUFLEN];
+     int rv;
+ 
+     if (n == 0)
+         return 0;
+     if (s == NULL) {
+         /* fake formatting, i.e., calculate output length only */
+         handle.curpos     = buf;
+         handle.endpos     = buf + sizeof(buf) - 1;
+         handle.flush      = l2_util_flush_fake;
+         handle.format     = NULL;
+         handle.data[0].vp = buf;
+         handle.data[1].i  = 0;
+         handle.data[2].i  = sizeof(buf);
+         rv = l2_util_format(&handle, fmt, ap);
+         if (rv == -1)
+             rv = (int)n;
+     }
+     else {
+         /* real formatting, i.e., create output */
+         handle.curpos  = s;
+         handle.endpos  = s + n - 1;
+         handle.flush   = l2_util_flush_real;
+         handle.format  = NULL;
+         rv = l2_util_format(&handle, fmt, ap);
+         *(handle.curpos) = NUL;
+         if (rv == -1)
+             rv = (int)n;
+     }
+     return rv;
+ }
+ 
+ char *l2_util_vasprintf(const char *fmt, va_list ap)
+ {
+     va_list apbak;
+     char *s;
+     int rv;
+ 
+     apbak = ap;
+     if ((rv = l2_util_vsprintf(NULL, -1, fmt, ap)) == -1)
+         return NULL;
+     if ((s = malloc(rv+1)) == NULL)
+         return NULL;
+     ap = apbak;
+     if ((rv = l2_util_vsprintf(s, rv+1, fmt, ap)) == -1) {
+         free(s);
+         return NULL;
+     }
+     return s;
+ }
+ 
+ int l2_util_sprintf(char *s, size_t n, const char *fmt, ...)
+ {
+     va_list ap;
+     int rv;
+ 
+     va_start(ap, fmt);
+     rv = l2_util_vsprintf(s, n, fmt, ap);
+     va_end(ap);
+     return rv;
+ }
+ 
+ char *l2_util_asprintf(const char *fmt, ...)
+ {
+     va_list ap;
+     char *rv;
+ 
+     va_start(ap, fmt);
+     rv = l2_util_vasprintf(fmt, ap);
+     va_end(ap);
+     return rv;
+ }
+ 

CVSTrac 2.0.1