2008-06-30 20:58:15 +08:00
/***************************************************************************
* _ _ ____ _
* Project ___ | | | | _ \ | |
* / __ | | | | | _ ) | |
* | ( __ | | _ | | _ < | | ___
* \ ___ | \ ___ / | _ | \ _ \ _____ |
1999-12-29 22:20:26 +08:00
*
2009-04-21 19:46:16 +08:00
* Copyright ( C ) 1999 - 2009 , Daniel Stenberg , < daniel @ haxx . se > , et al .
2008-06-30 20:58:15 +08:00
*
* This software is licensed as described in the file COPYING , which
* you should have received as part of this distribution . The terms
* are also available at http : //curl.haxx.se/docs/copyright.html.
2003-01-17 05:10:10 +08:00
*
2008-06-30 20:58:15 +08:00
* You may opt to use , copy , modify , merge , publish , distribute and / or sell
* copies of the Software , and permit persons to whom the Software is
* furnished to do so , under the terms of the COPYING file .
2003-01-17 05:10:10 +08:00
*
2008-06-30 20:58:15 +08:00
* This software is distributed on an " AS IS " basis , WITHOUT WARRANTY OF ANY
* KIND , either express or implied .
2003-01-17 05:10:10 +08:00
*
2008-06-30 20:58:15 +08:00
* $ Id $
2003-01-17 05:10:10 +08:00
*
* Purpose :
* A merge of Bjorn Reese ' s format ( ) function and Daniel ' s dsprintf ( )
* 1.0 . A full blooded printf ( ) clone with full support for < num > $
* everywhere ( parameters , widths and precisions ) including variabled
* sized parameters ( like doubles , long longs , long doubles and even
* void * in 64 - bit architectures ) .
*
* Current restrictions :
* - Max 128 parameters
* - No ' long double ' support .
*
* If you ever want truly portable and good * printf ( ) clones , the project that
* took on from here is named ' Trio ' and you find more details on the trio web
* page at http : //daniel.haxx.se/trio/
*/
# include "setup.h"
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <ctype.h>
# include <string.h>
2006-07-05 22:23:09 +08:00
# if defined(DJGPP) && (DJGPP_MINOR < 4)
2006-07-06 21:33:56 +08:00
# undef _MPRINTF_REPLACE /* don't use x_was_used() here */
2006-07-05 22:23:09 +08:00
# endif
2004-01-29 21:56:45 +08:00
# include <curl/mprintf.h>
2009-04-21 19:46:16 +08:00
# include "curl_memory.h"
2008-08-22 19:11:33 +08:00
/* The last #include file should be: */
# include "memdebug.h"
2003-01-17 05:10:10 +08:00
# ifndef SIZEOF_LONG_DOUBLE
# define SIZEOF_LONG_DOUBLE 0
# endif
2008-08-21 08:10:27 +08:00
/*
* If SIZEOF_SIZE_T has not been defined , default to the size of long .
*/
2004-05-05 14:57:26 +08:00
# ifndef SIZEOF_SIZE_T
2008-08-21 08:10:27 +08:00
# define SIZEOF_SIZE_T CURL_SIZEOF_LONG
2004-05-05 14:57:26 +08:00
# endif
2008-08-21 08:06:15 +08:00
# ifdef HAVE_LONGLONG
# define LONG_LONG_TYPE long long
# define HAVE_LONG_LONG_TYPE
# else
2008-08-21 14:58:12 +08:00
# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
2008-08-21 08:06:15 +08:00
# define LONG_LONG_TYPE __int64
# define HAVE_LONG_LONG_TYPE
# else
# undef LONG_LONG_TYPE
# undef HAVE_LONG_LONG_TYPE
# endif
2004-02-25 22:15:38 +08:00
# endif
2003-01-17 05:10:10 +08:00
2008-08-22 19:11:33 +08:00
/*
* Max integer data types that mprintf . c is capable
*/
# ifdef HAVE_LONG_LONG_TYPE
# define mp_intmax_t LONG_LONG_TYPE
# define mp_uintmax_t unsigned LONG_LONG_TYPE
# else
# define mp_intmax_t long
# define mp_uintmax_t unsigned long
# endif
2003-01-17 05:10:10 +08:00
# define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
# define MAX_PARAMETERS 128 /* lame static limit */
2007-02-28 22:45:48 +08:00
# ifdef __AMIGA__
2005-07-14 02:06:40 +08:00
# undef FORMAT_INT
# endif
2003-01-17 05:10:10 +08:00
/* Lower-case digits. */
static const char lower_digits [ ] = " 0123456789abcdefghijklmnopqrstuvwxyz " ;
/* Upper-case digits. */
static const char upper_digits [ ] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " ;
2004-06-24 19:54:11 +08:00
# define OUTCHAR(x) \
2004-05-12 20:05:13 +08:00
do { \
if ( stream ( ( unsigned char ) ( x ) , ( FILE * ) data ) ! = - 1 ) \
done + + ; \
else \
return done ; /* return immediately on failure */ \
} while ( 0 )
2003-01-17 05:10:10 +08:00
/* Data type to read from the arglist */
typedef enum {
FORMAT_UNKNOWN = 0 ,
FORMAT_STRING ,
FORMAT_PTR ,
FORMAT_INT ,
FORMAT_INTPTR ,
FORMAT_LONG ,
FORMAT_LONGLONG ,
FORMAT_DOUBLE ,
FORMAT_LONGDOUBLE ,
FORMAT_WIDTH /* For internal use */
} FormatType ;
/* convertion and display flags */
enum {
FLAGS_NEW = 0 ,
FLAGS_SPACE = 1 < < 0 ,
FLAGS_SHOWSIGN = 1 < < 1 ,
FLAGS_LEFT = 1 < < 2 ,
FLAGS_ALT = 1 < < 3 ,
FLAGS_SHORT = 1 < < 4 ,
FLAGS_LONG = 1 < < 5 ,
FLAGS_LONGLONG = 1 < < 6 ,
FLAGS_LONGDOUBLE = 1 < < 7 ,
FLAGS_PAD_NIL = 1 < < 8 ,
FLAGS_UNSIGNED = 1 < < 9 ,
FLAGS_OCTAL = 1 < < 10 ,
FLAGS_HEX = 1 < < 11 ,
FLAGS_UPPER = 1 < < 12 ,
FLAGS_WIDTH = 1 < < 13 , /* '*' or '*<num>$' used */
FLAGS_WIDTHPARAM = 1 < < 14 , /* width PARAMETER was specified */
FLAGS_PREC = 1 < < 15 , /* precision was specified */
FLAGS_PRECPARAM = 1 < < 16 , /* precision PARAMETER was specified */
FLAGS_CHAR = 1 < < 17 , /* %c story */
FLAGS_FLOATE = 1 < < 18 , /* %e or %E */
FLAGS_FLOATG = 1 < < 19 /* %g or %G */
} ;
typedef struct {
FormatType type ;
int flags ;
2004-03-23 23:25:54 +08:00
long width ; /* width OR width parameter number */
long precision ; /* precision OR precision parameter number */
2003-01-17 05:10:10 +08:00
union {
char * str ;
void * ptr ;
2008-08-22 19:11:33 +08:00
union {
mp_intmax_t as_signed ;
mp_uintmax_t as_unsigned ;
} num ;
2003-01-17 05:10:10 +08:00
double dnum ;
} data ;
} va_stack_t ;
struct nsprintf {
char * buffer ;
size_t length ;
size_t max ;
} ;
struct asprintf {
char * buffer ; /* allocated buffer */
size_t len ; /* length of string */
size_t alloc ; /* length of alloc */
2008-08-22 14:53:01 +08:00
int fail ; /* (!= 0) if an alloc has failed and thus
the output is not the complete data */
2003-01-17 05:10:10 +08:00
} ;
2004-03-08 19:28:14 +08:00
static long dprintf_DollarString ( char * input , char * * end )
2003-01-17 05:10:10 +08:00
{
int number = 0 ;
2006-10-18 05:32:56 +08:00
while ( ISDIGIT ( * input ) ) {
2003-01-17 05:10:10 +08:00
number * = 10 ;
number + = * input - ' 0 ' ;
input + + ;
}
if ( number & & ( ' $ ' = = * input + + ) ) {
* end = input ;
return number ;
}
return 0 ;
}
2008-08-22 14:53:01 +08:00
static int dprintf_IsQualifierNoDollar ( char c )
2003-01-17 05:10:10 +08:00
{
switch ( c ) {
case ' - ' : case ' + ' : case ' ' : case ' # ' : case ' . ' :
case ' 0 ' : case ' 1 ' : case ' 2 ' : case ' 3 ' : case ' 4 ' :
case ' 5 ' : case ' 6 ' : case ' 7 ' : case ' 8 ' : case ' 9 ' :
2004-03-01 20:44:07 +08:00
case ' h ' : case ' l ' : case ' L ' : case ' z ' : case ' q ' :
2004-01-06 06:29:29 +08:00
case ' * ' : case ' O ' :
2008-08-22 14:53:01 +08:00
return 1 ; /* true */
2003-01-17 05:10:10 +08:00
default :
2008-08-22 14:53:01 +08:00
return 0 ; /* false */
2003-01-17 05:10:10 +08:00
}
}
# ifdef DPRINTF_DEBUG2
2008-08-21 09:49:19 +08:00
static void dprintf_Pass1Report ( va_stack_t * vto , int max )
2003-01-17 05:10:10 +08:00
{
int i ;
2008-08-21 09:49:19 +08:00
char buffer [ 256 ] ;
2003-01-17 05:10:10 +08:00
int bit ;
int flags ;
for ( i = 0 ; i < max ; i + + ) {
char * type ;
switch ( vto [ i ] . type ) {
case FORMAT_UNKNOWN :
type = " unknown " ;
break ;
case FORMAT_STRING :
type = " string " ;
break ;
case FORMAT_PTR :
type = " pointer " ;
break ;
case FORMAT_INT :
type = " int " ;
break ;
2008-08-21 09:49:19 +08:00
case FORMAT_INTPTR :
type = " intptr " ;
break ;
2003-01-17 05:10:10 +08:00
case FORMAT_LONG :
type = " long " ;
break ;
case FORMAT_LONGLONG :
type = " long long " ;
break ;
case FORMAT_DOUBLE :
type = " double " ;
break ;
case FORMAT_LONGDOUBLE :
type = " long double " ;
2004-06-24 15:43:48 +08:00
break ;
2003-01-17 05:10:10 +08:00
}
buffer [ 0 ] = 0 ;
for ( bit = 0 ; bit < 31 ; bit + + ) {
flags = vto [ i ] . flags & ( 1 < < bit ) ;
if ( flags & FLAGS_SPACE )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " space " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_SHOWSIGN )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " plus " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_LEFT )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " left " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_ALT )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " alt " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_SHORT )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " short " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_LONG )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " long " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_LONGLONG )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " longlong " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_LONGDOUBLE )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " longdouble " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_PAD_NIL )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " padnil " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_UNSIGNED )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " unsigned " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_OCTAL )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " octal " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_HEX )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " hex " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_UPPER )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " upper " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_WIDTH )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " width " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_WIDTHPARAM )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " widthparam " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_PREC )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " precision " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_PRECPARAM )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " precparam " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_CHAR )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " char " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_FLOATE )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " floate " ) ;
2003-01-17 05:10:10 +08:00
else if ( flags & FLAGS_FLOATG )
2004-06-24 19:54:11 +08:00
strcat ( buffer , " floatg " ) ;
2003-01-17 05:10:10 +08:00
}
printf ( " REPORT: %d. %s [%s] \n " , i , type , buffer ) ;
}
}
# endif
/******************************************************************
*
* Pass 1 :
* Create an index with the type of each parameter entry and its
* value ( may vary in size )
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-29 22:20:26 +08:00
2007-08-10 05:05:05 +08:00
static long dprintf_Pass1 ( const char * format , va_stack_t * vto , char * * endpos ,
2004-03-23 23:25:54 +08:00
va_list arglist )
1999-12-29 22:20:26 +08:00
{
2007-08-10 05:05:05 +08:00
char * fmt = ( char * ) format ;
1999-12-29 22:20:26 +08:00
int param_num = 0 ;
2004-03-08 19:28:14 +08:00
long this_param ;
long width ;
long precision ;
1999-12-29 22:20:26 +08:00
int flags ;
2004-03-08 19:28:14 +08:00
long max_param = 0 ;
long i ;
2008-08-24 11:59:43 +08:00
2007-11-05 17:45:09 +08:00
while ( * fmt ) {
if ( * fmt + + = = ' % ' ) {
if ( * fmt = = ' % ' ) {
2004-06-24 19:54:11 +08:00
fmt + + ;
continue ; /* while */
1999-12-29 22:20:26 +08:00
}
flags = FLAGS_NEW ;
/* Handle the positional case (N$) */
param_num + + ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
this_param = dprintf_DollarString ( fmt , & fmt ) ;
2007-11-05 17:45:09 +08:00
if ( 0 = = this_param )
2004-06-24 19:54:11 +08:00
/* we got no positional, get the next counter */
this_param = param_num ;
1999-12-29 22:20:26 +08:00
2007-11-05 17:45:09 +08:00
if ( this_param > max_param )
2004-06-24 19:54:11 +08:00
max_param = this_param ;
1999-12-29 22:20:26 +08:00
/*
* The parameter with number ' i ' should be used . Next , we need
* to get SIZE and TYPE of the parameter . Add the information
* to our array .
*/
width = 0 ;
precision = 0 ;
/* Handle the flags */
2007-11-05 17:45:09 +08:00
while ( dprintf_IsQualifierNoDollar ( * fmt ) ) {
2004-06-24 19:54:11 +08:00
switch ( * fmt + + ) {
case ' ' :
flags | = FLAGS_SPACE ;
break ;
case ' + ' :
flags | = FLAGS_SHOWSIGN ;
break ;
case ' - ' :
flags | = FLAGS_LEFT ;
flags & = ~ FLAGS_PAD_NIL ;
break ;
case ' # ' :
flags | = FLAGS_ALT ;
break ;
case ' . ' :
flags | = FLAGS_PREC ;
2007-11-05 17:45:09 +08:00
if ( ' * ' = = * fmt ) {
2004-06-24 19:54:11 +08:00
/* The precision is picked from a specified parameter */
flags | = FLAGS_PRECPARAM ;
fmt + + ;
param_num + + ;
i = dprintf_DollarString ( fmt , & fmt ) ;
2007-11-05 17:45:09 +08:00
if ( i )
2004-06-24 19:54:11 +08:00
precision = i ;
else
precision = param_num ;
2007-11-05 17:45:09 +08:00
if ( precision > max_param )
2004-06-24 19:54:11 +08:00
max_param = precision ;
}
else {
flags | = FLAGS_PREC ;
precision = strtol ( fmt , & fmt , 10 ) ;
}
break ;
case ' h ' :
flags | = FLAGS_SHORT ;
break ;
case ' l ' :
2007-11-05 17:45:09 +08:00
if ( flags & FLAGS_LONG )
2004-06-24 19:54:11 +08:00
flags | = FLAGS_LONGLONG ;
else
flags | = FLAGS_LONG ;
break ;
case ' L ' :
flags | = FLAGS_LONGDOUBLE ;
break ;
case ' q ' :
flags | = FLAGS_LONGLONG ;
break ;
case ' z ' :
2004-03-01 20:44:07 +08:00
/* the code below generates a warning if -Wunreachable-code is
used */
2008-08-21 08:10:27 +08:00
# if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG)
2004-05-05 14:57:26 +08:00
flags | = FLAGS_LONGLONG ;
# else
flags | = FLAGS_LONG ;
# endif
break ;
2004-03-02 00:22:17 +08:00
case ' O ' :
2008-08-21 08:10:27 +08:00
# if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
2004-02-20 23:16:31 +08:00
flags | = FLAGS_LONGLONG ;
# else
flags | = FLAGS_LONG ;
# endif
2004-03-02 00:22:17 +08:00
break ;
2004-06-24 19:54:11 +08:00
case ' 0 ' :
2007-11-05 17:45:09 +08:00
if ( ! ( flags & FLAGS_LEFT ) )
2004-06-24 19:54:11 +08:00
flags | = FLAGS_PAD_NIL ;
/* FALLTHROUGH */
case ' 1 ' : case ' 2 ' : case ' 3 ' : case ' 4 ' :
case ' 5 ' : case ' 6 ' : case ' 7 ' : case ' 8 ' : case ' 9 ' :
flags | = FLAGS_WIDTH ;
width = strtol ( fmt - 1 , & fmt , 10 ) ;
break ;
case ' * ' : /* Special case */
flags | = FLAGS_WIDTHPARAM ;
param_num + + ;
i = dprintf_DollarString ( fmt , & fmt ) ;
if ( i )
width = i ;
else
width = param_num ;
if ( width > max_param )
max_param = width ;
break ;
default :
break ;
}
1999-12-29 22:20:26 +08:00
} /* switch */
/* Handle the specifier */
i = this_param - 1 ;
switch ( * fmt ) {
case ' S ' :
2004-06-24 19:54:11 +08:00
flags | = FLAGS_ALT ;
/* FALLTHROUGH */
1999-12-29 22:20:26 +08:00
case ' s ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_STRING ;
break ;
1999-12-29 22:20:26 +08:00
case ' n ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_INTPTR ;
break ;
1999-12-29 22:20:26 +08:00
case ' p ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_PTR ;
break ;
1999-12-29 22:20:26 +08:00
case ' d ' : case ' i ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_INT ;
break ;
1999-12-29 22:20:26 +08:00
case ' u ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_INT ;
flags | = FLAGS_UNSIGNED ;
break ;
1999-12-29 22:20:26 +08:00
case ' o ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_INT ;
flags | = FLAGS_OCTAL ;
break ;
1999-12-29 22:20:26 +08:00
case ' x ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_INT ;
flags | = FLAGS_HEX ;
break ;
1999-12-29 22:20:26 +08:00
case ' X ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_INT ;
flags | = FLAGS_HEX | FLAGS_UPPER ;
break ;
1999-12-29 22:20:26 +08:00
case ' c ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_INT ;
flags | = FLAGS_CHAR ;
break ;
1999-12-29 22:20:26 +08:00
case ' f ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_DOUBLE ;
break ;
2004-03-08 19:28:14 +08:00
case ' e ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_DOUBLE ;
flags | = FLAGS_FLOATE ;
break ;
2004-03-08 19:28:14 +08:00
case ' E ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_DOUBLE ;
flags | = FLAGS_FLOATE | FLAGS_UPPER ;
break ;
2004-03-08 19:28:14 +08:00
case ' g ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_DOUBLE ;
flags | = FLAGS_FLOATG ;
break ;
2004-03-08 19:28:14 +08:00
case ' G ' :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_DOUBLE ;
flags | = FLAGS_FLOATG | FLAGS_UPPER ;
break ;
1999-12-29 22:20:26 +08:00
default :
2004-06-24 19:54:11 +08:00
vto [ i ] . type = FORMAT_UNKNOWN ;
break ;
1999-12-29 22:20:26 +08:00
} /* switch */
vto [ i ] . flags = flags ;
vto [ i ] . width = width ;
vto [ i ] . precision = precision ;
2004-06-24 15:43:48 +08:00
2007-11-05 17:45:09 +08:00
if ( flags & FLAGS_WIDTHPARAM ) {
2004-06-24 19:54:11 +08:00
/* we have the width specified from a parameter, so we make that
parameter ' s info setup properly */
vto [ i ] . width = width - 1 ;
i = width - 1 ;
vto [ i ] . type = FORMAT_WIDTH ;
vto [ i ] . flags = FLAGS_NEW ;
vto [ i ] . precision = vto [ i ] . width = 0 ; /* can't use width or precision
of width ! */
1999-12-29 22:20:26 +08:00
}
2007-11-05 17:45:09 +08:00
if ( flags & FLAGS_PRECPARAM ) {
2004-06-24 19:54:11 +08:00
/* we have the precision specified from a parameter, so we make that
parameter ' s info setup properly */
vto [ i ] . precision = precision - 1 ;
i = precision - 1 ;
vto [ i ] . type = FORMAT_WIDTH ;
vto [ i ] . flags = FLAGS_NEW ;
vto [ i ] . precision = vto [ i ] . width = 0 ; /* can't use width or precision
of width ! */
1999-12-29 22:20:26 +08:00
}
* endpos + + = fmt + 1 ; /* end of this sequence */
}
}
# ifdef DPRINTF_DEBUG2
dprintf_Pass1Report ( vto , max_param ) ;
# endif
/* Read the arg list parameters into our data list */
for ( i = 0 ; i < max_param ; i + + ) {
2007-11-05 17:45:09 +08:00
if ( ( i + 1 < max_param ) & & ( vto [ i + 1 ] . type = = FORMAT_WIDTH ) )
1999-12-29 22:20:26 +08:00
{
2004-06-24 19:54:11 +08:00
/* Width/precision arguments must be read before the main argument
* they are attached to
*/
2008-08-22 19:11:33 +08:00
vto [ i + 1 ] . data . num . as_signed = ( mp_intmax_t ) va_arg ( arglist , int ) ;
1999-12-29 22:20:26 +08:00
}
switch ( vto [ i ] . type )
{
case FORMAT_STRING :
2004-06-24 19:54:11 +08:00
vto [ i ] . data . str = va_arg ( arglist , char * ) ;
break ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
case FORMAT_INTPTR :
case FORMAT_UNKNOWN :
case FORMAT_PTR :
2004-06-24 19:54:11 +08:00
vto [ i ] . data . ptr = va_arg ( arglist , void * ) ;
break ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
case FORMAT_INT :
2008-08-21 08:06:15 +08:00
# ifdef HAVE_LONG_LONG_TYPE
2008-08-25 07:21:46 +08:00
if ( ( vto [ i ] . flags & FLAGS_LONGLONG ) & & ( vto [ i ] . flags & FLAGS_UNSIGNED ) )
vto [ i ] . data . num . as_unsigned =
( mp_uintmax_t ) va_arg ( arglist , mp_uintmax_t ) ;
else if ( vto [ i ] . flags & FLAGS_LONGLONG )
vto [ i ] . data . num . as_signed =
( mp_intmax_t ) va_arg ( arglist , mp_intmax_t ) ;
2004-06-24 19:54:11 +08:00
else
1999-12-29 22:20:26 +08:00
# endif
2008-06-30 20:58:15 +08:00
{
2008-08-25 07:21:46 +08:00
if ( ( vto [ i ] . flags & FLAGS_LONG ) & & ( vto [ i ] . flags & FLAGS_UNSIGNED ) )
vto [ i ] . data . num . as_unsigned =
( mp_uintmax_t ) va_arg ( arglist , unsigned long ) ;
else if ( vto [ i ] . flags & FLAGS_LONG )
vto [ i ] . data . num . as_signed =
( mp_intmax_t ) va_arg ( arglist , long ) ;
else if ( vto [ i ] . flags & FLAGS_UNSIGNED )
vto [ i ] . data . num . as_unsigned =
( mp_uintmax_t ) va_arg ( arglist , unsigned int ) ;
else
vto [ i ] . data . num . as_signed =
( mp_intmax_t ) va_arg ( arglist , int ) ;
2008-06-30 20:58:15 +08:00
}
2004-06-24 19:54:11 +08:00
break ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
case FORMAT_DOUBLE :
2004-06-24 15:43:48 +08:00
vto [ i ] . data . dnum = va_arg ( arglist , double ) ;
2004-06-24 19:54:11 +08:00
break ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
case FORMAT_WIDTH :
2004-06-24 19:54:11 +08:00
/* Argument has been read. Silently convert it into an integer
* for later use
*/
vto [ i ] . type = FORMAT_INT ;
break ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
default :
2004-06-24 19:54:11 +08:00
break ;
1999-12-29 22:20:26 +08:00
}
}
return max_param ;
}
static int dprintf_formatf (
2004-05-12 20:05:13 +08:00
void * data , /* untouched by format(), just sent to the stream() function in
the second argument */
/* function pointer called for each output character */
int ( * stream ) ( int , FILE * ) ,
const char * format , /* %-formatted string */
va_list ap_save ) /* list of parameters */
1999-12-29 22:20:26 +08:00
{
/* Base-36 digits for numbers. */
const char * digits = lower_digits ;
/* Pointer into the format string. */
char * f ;
/* Number of characters written. */
2004-03-08 19:28:14 +08:00
int done = 0 ;
1999-12-29 22:20:26 +08:00
long param ; /* current parameter to read */
long param_num = 0 ; /* parameter counter */
va_stack_t vto [ MAX_PARAMETERS ] ;
char * endpos [ MAX_PARAMETERS ] ;
char * * end ;
char work [ BUFFSIZE ] ;
va_stack_t * p ;
/* Do the actual %-code parsing */
2007-08-10 05:05:05 +08:00
dprintf_Pass1 ( format , vto , endpos , ap_save ) ;
1999-12-29 22:20:26 +08:00
end = & endpos [ 0 ] ; /* the initial end-position from the list dprintf_Pass1()
created for us */
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
f = ( char * ) format ;
2007-11-05 17:45:09 +08:00
while ( * f ! = ' \0 ' ) {
1999-12-29 22:20:26 +08:00
/* Format spec modifiers. */
2008-08-22 14:53:01 +08:00
int is_alt ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
/* Width of a field. */
2004-02-26 20:32:29 +08:00
long width ;
1999-12-29 22:20:26 +08:00
/* Precision of a field. */
long prec ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
/* Decimal integer is negative. */
2008-08-21 09:49:19 +08:00
int is_neg ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
/* Base of a number to be written. */
long base ;
/* Integral values to be written. */
2008-08-22 19:11:33 +08:00
mp_uintmax_t num ;
/* Used to convert negative in positive. */
mp_intmax_t signed_num ;
2004-06-24 15:43:48 +08:00
2007-11-05 17:45:09 +08:00
if ( * f ! = ' % ' ) {
1999-12-29 22:20:26 +08:00
/* This isn't a format spec, so write everything out until the next one
2004-06-24 19:54:11 +08:00
OR end of string is reached . */
1999-12-29 22:20:26 +08:00
do {
2004-06-24 19:54:11 +08:00
OUTCHAR ( * f ) ;
1999-12-29 22:20:26 +08:00
} while ( * + + f & & ( ' % ' ! = * f ) ) ;
continue ;
}
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
+ + f ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
/* Check for "%%". Note that although the ANSI standard lists
' % ' as a conversion specifier , it says " The complete format
specification shall be ` % % ' , " so we can avoid all the width
and precision processing . */
2007-11-05 17:45:09 +08:00
if ( * f = = ' % ' ) {
1999-12-29 22:20:26 +08:00
+ + f ;
OUTCHAR ( ' % ' ) ;
continue ;
}
/* If this is a positional parameter, the position must follow imediately
after the % , thus create a % < num > $ sequence */
param = dprintf_DollarString ( f , & f ) ;
if ( ! param )
param = param_num ;
else
- - param ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
param_num + + ; /* increase this always to allow "%2$s %1$s %s" and then the
2004-06-24 19:54:11 +08:00
third % s will pick the 3 rd argument */
1999-12-29 22:20:26 +08:00
p = & vto [ param ] ;
/* pick up the specified width */
if ( p - > flags & FLAGS_WIDTHPARAM )
2008-08-22 19:11:33 +08:00
width = ( long ) vto [ p - > width ] . data . num . as_signed ;
1999-12-29 22:20:26 +08:00
else
width = p - > width ;
/* pick up the specified precision */
2007-11-20 18:03:33 +08:00
if ( p - > flags & FLAGS_PRECPARAM ) {
2008-08-22 19:11:33 +08:00
prec = ( long ) vto [ p - > precision ] . data . num . as_signed ;
2007-11-20 18:03:33 +08:00
param_num + + ; /* since the precision is extraced from a parameter, we
must skip that to get to the next one properly */
}
1999-12-29 22:20:26 +08:00
else if ( p - > flags & FLAGS_PREC )
prec = p - > precision ;
else
prec = - 1 ;
2008-08-23 10:35:16 +08:00
is_alt = ( p - > flags & FLAGS_ALT ) ? 1 : 0 ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
switch ( p - > type ) {
case FORMAT_INT :
2008-08-22 19:11:33 +08:00
num = p - > data . num . as_unsigned ;
1999-12-29 22:20:26 +08:00
if ( p - > flags & FLAGS_CHAR ) {
2004-06-24 19:54:11 +08:00
/* Character. */
2007-11-05 17:45:09 +08:00
if ( ! ( p - > flags & FLAGS_LEFT ) )
while ( - - width > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
OUTCHAR ( ( char ) num ) ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_LEFT )
while ( - - width > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
break ;
1999-12-29 22:20:26 +08:00
}
if ( p - > flags & FLAGS_UNSIGNED ) {
2004-06-24 19:54:11 +08:00
/* Decimal unsigned integer. */
base = 10 ;
goto unsigned_number ;
1999-12-29 22:20:26 +08:00
}
if ( p - > flags & FLAGS_OCTAL ) {
2004-06-24 19:54:11 +08:00
/* Octal unsigned integer. */
base = 8 ;
goto unsigned_number ;
1999-12-29 22:20:26 +08:00
}
if ( p - > flags & FLAGS_HEX ) {
2004-06-24 19:54:11 +08:00
/* Hexadecimal unsigned integer. */
1999-12-29 22:20:26 +08:00
2004-06-24 19:54:11 +08:00
digits = ( p - > flags & FLAGS_UPPER ) ? upper_digits : lower_digits ;
base = 16 ;
goto unsigned_number ;
1999-12-29 22:20:26 +08:00
}
/* Decimal integer. */
base = 10 ;
2008-08-25 07:21:46 +08:00
is_neg = ( p - > data . num . as_signed < ( mp_intmax_t ) 0 ) ? 1 : 0 ;
2008-08-22 19:11:33 +08:00
if ( is_neg ) {
/* signed_num might fail to hold absolute negative minimum by 1 */
2008-08-25 07:21:46 +08:00
signed_num = p - > data . num . as_signed + ( mp_intmax_t ) 1 ;
2008-08-24 11:59:43 +08:00
signed_num = - signed_num ;
num = ( mp_uintmax_t ) signed_num ;
2008-08-25 07:21:46 +08:00
num + = ( mp_uintmax_t ) 1 ;
1999-12-29 22:20:26 +08:00
}
2008-08-22 19:11:33 +08:00
1999-12-29 22:20:26 +08:00
goto number ;
2004-06-24 15:43:48 +08:00
2004-06-24 19:54:11 +08:00
unsigned_number :
1999-12-29 22:20:26 +08:00
/* Unsigned number of base BASE. */
is_neg = 0 ;
2004-06-24 15:43:48 +08:00
2004-06-24 19:54:11 +08:00
number :
1999-12-29 22:20:26 +08:00
/* Number of base BASE. */
{
2004-06-24 19:54:11 +08:00
char * workend = & work [ sizeof ( work ) - 1 ] ;
char * w ;
/* Supply a default precision if none was given. */
2007-11-05 17:45:09 +08:00
if ( prec = = - 1 )
2004-06-24 19:54:11 +08:00
prec = 1 ;
/* Put the number in WORK. */
w = workend ;
2007-11-05 17:45:09 +08:00
while ( num > 0 ) {
2004-06-24 19:54:11 +08:00
* w - - = digits [ num % base ] ;
num / = base ;
}
2005-04-26 21:08:49 +08:00
width - = ( long ) ( workend - w ) ;
prec - = ( long ) ( workend - w ) ;
2004-06-24 19:54:11 +08:00
2008-08-22 14:53:01 +08:00
if ( is_alt & & base = = 8 & & prec < = 0 ) {
2004-06-24 19:54:11 +08:00
* w - - = ' 0 ' ;
- - width ;
}
2007-11-05 17:45:09 +08:00
if ( prec > 0 ) {
2004-06-24 19:54:11 +08:00
width - = prec ;
2007-11-05 17:45:09 +08:00
while ( prec - - > 0 )
2004-06-24 19:54:11 +08:00
* w - - = ' 0 ' ;
}
2008-08-22 14:53:01 +08:00
if ( is_alt & & base = = 16 )
2004-06-24 19:54:11 +08:00
width - = 2 ;
2007-11-05 17:45:09 +08:00
if ( is_neg | | ( p - > flags & FLAGS_SHOWSIGN ) | | ( p - > flags & FLAGS_SPACE ) )
2004-06-24 19:54:11 +08:00
- - width ;
2007-11-05 17:45:09 +08:00
if ( ! ( p - > flags & FLAGS_LEFT ) & & ! ( p - > flags & FLAGS_PAD_NIL ) )
while ( width - - > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
2007-11-05 17:45:09 +08:00
if ( is_neg )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' - ' ) ;
2007-11-05 17:45:09 +08:00
else if ( p - > flags & FLAGS_SHOWSIGN )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' + ' ) ;
2007-11-05 17:45:09 +08:00
else if ( p - > flags & FLAGS_SPACE )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
2008-08-22 14:53:01 +08:00
if ( is_alt & & base = = 16 ) {
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' 0 ' ) ;
if ( p - > flags & FLAGS_UPPER )
OUTCHAR ( ' X ' ) ;
else
OUTCHAR ( ' x ' ) ;
}
2007-11-05 17:45:09 +08:00
if ( ! ( p - > flags & FLAGS_LEFT ) & & ( p - > flags & FLAGS_PAD_NIL ) )
while ( width - - > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' 0 ' ) ;
/* Write the number. */
2007-11-05 17:45:09 +08:00
while ( + + w < = workend ) {
2004-06-24 19:54:11 +08:00
OUTCHAR ( * w ) ;
}
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_LEFT )
while ( width - - > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
1999-12-29 22:20:26 +08:00
}
break ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
case FORMAT_STRING :
2004-06-24 19:54:11 +08:00
/* String. */
1999-12-29 22:20:26 +08:00
{
2004-12-15 09:38:25 +08:00
static const char null [ ] = " (nil) " ;
const char * str ;
2004-06-24 19:54:11 +08:00
size_t len ;
str = ( char * ) p - > data . str ;
2007-11-05 17:45:09 +08:00
if ( str = = NULL ) {
2004-06-24 19:54:11 +08:00
/* Write null[] if there's space. */
2007-11-05 17:45:09 +08:00
if ( prec = = - 1 | | prec > = ( long ) sizeof ( null ) - 1 ) {
2004-06-24 19:54:11 +08:00
str = null ;
len = sizeof ( null ) - 1 ;
/* Disable quotes around (nil) */
p - > flags & = ( ~ FLAGS_ALT ) ;
}
else {
2004-12-15 09:38:25 +08:00
str = " " ;
2004-06-24 19:54:11 +08:00
len = 0 ;
}
}
else
len = strlen ( str ) ;
2007-11-05 17:45:09 +08:00
if ( prec ! = - 1 & & ( size_t ) prec < len )
2004-06-24 19:54:11 +08:00
len = prec ;
2005-04-26 21:08:49 +08:00
width - = ( long ) len ;
2004-06-24 19:54:11 +08:00
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_ALT )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' " ' ) ;
2007-11-05 17:45:09 +08:00
if ( ! ( p - > flags & FLAGS_LEFT ) )
while ( width - - > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
2007-11-05 17:45:09 +08:00
while ( len - - > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( * str + + ) ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_LEFT )
while ( width - - > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_ALT )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' " ' ) ;
1999-12-29 22:20:26 +08:00
}
break ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
case FORMAT_PTR :
/* Generic pointer. */
{
2004-06-24 19:54:11 +08:00
void * ptr ;
ptr = ( void * ) p - > data . ptr ;
2007-11-05 17:45:09 +08:00
if ( ptr ! = NULL ) {
2004-06-24 19:54:11 +08:00
/* If the pointer is not NULL, write it as a %#x spec. */
base = 16 ;
digits = ( p - > flags & FLAGS_UPPER ) ? upper_digits : lower_digits ;
2008-08-22 14:53:01 +08:00
is_alt = 1 ;
2005-04-26 21:08:49 +08:00
num = ( size_t ) ptr ;
2004-06-24 19:54:11 +08:00
is_neg = 0 ;
goto number ;
}
else {
/* Write "(nil)" for a nil pointer. */
2004-12-15 09:38:25 +08:00
static const char strnil [ ] = " (nil) " ;
const char * point ;
2004-06-24 19:54:11 +08:00
width - = sizeof ( strnil ) - 1 ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_LEFT )
while ( width - - > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
for ( point = strnil ; * point ! = ' \0 ' ; + + point )
OUTCHAR ( * point ) ;
2007-11-05 17:45:09 +08:00
if ( ! ( p - > flags & FLAGS_LEFT ) )
while ( width - - > 0 )
2004-06-24 19:54:11 +08:00
OUTCHAR ( ' ' ) ;
}
1999-12-29 22:20:26 +08:00
}
break ;
case FORMAT_DOUBLE :
{
2004-06-24 19:54:11 +08:00
char formatbuf [ 32 ] = " % " ;
char * fptr ;
size_t left = sizeof ( formatbuf ) - strlen ( formatbuf ) ;
int len ;
width = - 1 ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_WIDTH )
2004-06-24 19:54:11 +08:00
width = p - > width ;
2007-11-05 17:45:09 +08:00
else if ( p - > flags & FLAGS_WIDTHPARAM )
2008-08-22 19:11:33 +08:00
width = ( long ) vto [ p - > width ] . data . num . as_signed ;
2004-06-24 19:54:11 +08:00
prec = - 1 ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_PREC )
2004-06-24 19:54:11 +08:00
prec = p - > precision ;
2007-11-05 17:45:09 +08:00
else if ( p - > flags & FLAGS_PRECPARAM )
2008-08-22 19:11:33 +08:00
prec = ( long ) vto [ p - > precision ] . data . num . as_signed ;
2004-06-24 19:54:11 +08:00
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_LEFT )
2004-06-24 19:54:11 +08:00
strcat ( formatbuf , " - " ) ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_SHOWSIGN )
2004-06-24 19:54:11 +08:00
strcat ( formatbuf , " + " ) ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_SPACE )
2004-06-24 19:54:11 +08:00
strcat ( formatbuf , " " ) ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_ALT )
2004-06-24 19:54:11 +08:00
strcat ( formatbuf , " # " ) ;
fptr = & formatbuf [ strlen ( formatbuf ) ] ;
if ( width > = 0 ) {
/* RECURSIVE USAGE */
len = curl_msnprintf ( fptr , left , " %ld " , width ) ;
fptr + = len ;
left - = len ;
}
if ( prec > = 0 ) {
/* RECURSIVE USAGE */
len = curl_msnprintf ( fptr , left , " .%ld " , prec ) ;
fptr + = len ;
left - = len ;
}
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_LONG )
2004-06-24 19:54:11 +08:00
* fptr + + = ' l ' ;
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_FLOATE )
2007-02-01 09:42:13 +08:00
* fptr + + = ( char ) ( ( p - > flags & FLAGS_UPPER ) ? ' E ' : ' e ' ) ;
2007-11-05 17:45:09 +08:00
else if ( p - > flags & FLAGS_FLOATG )
2007-02-01 09:42:13 +08:00
* fptr + + = ( char ) ( ( p - > flags & FLAGS_UPPER ) ? ' G ' : ' g ' ) ;
2004-06-24 19:54:11 +08:00
else
* fptr + + = ' f ' ;
* fptr = 0 ; /* and a final zero termination */
/* NOTE NOTE NOTE!! Not all sprintf() implementations returns number
of output characters */
2004-06-24 15:43:48 +08:00
( sprintf ) ( work , formatbuf , p - > data . dnum ) ;
1999-12-29 22:20:26 +08:00
2004-06-24 19:54:11 +08:00
for ( fptr = work ; * fptr ; fptr + + )
OUTCHAR ( * fptr ) ;
1999-12-29 22:20:26 +08:00
}
break ;
case FORMAT_INTPTR :
/* Answer the count of characters written. */
2008-08-21 08:06:15 +08:00
# ifdef HAVE_LONG_LONG_TYPE
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_LONGLONG )
2008-08-21 08:06:15 +08:00
* ( LONG_LONG_TYPE * ) p - > data . ptr = ( LONG_LONG_TYPE ) done ;
1999-12-29 22:20:26 +08:00
else
# endif
2007-11-05 17:45:09 +08:00
if ( p - > flags & FLAGS_LONG )
2004-06-24 19:54:11 +08:00
* ( long * ) p - > data . ptr = ( long ) done ;
2007-11-05 17:45:09 +08:00
else if ( ! ( p - > flags & FLAGS_SHORT ) )
2004-06-24 19:54:11 +08:00
* ( int * ) p - > data . ptr = ( int ) done ;
1999-12-29 22:20:26 +08:00
else
2004-06-24 19:54:11 +08:00
* ( short * ) p - > data . ptr = ( short ) done ;
1999-12-29 22:20:26 +08:00
break ;
default :
break ;
}
f = * end + + ; /* goto end of %-code */
}
return done ;
}
/* fputc() look-alike */
2004-11-08 22:20:14 +08:00
static int addbyter ( int output , FILE * data )
1999-12-29 22:20:26 +08:00
{
struct nsprintf * infop = ( struct nsprintf * ) data ;
2004-05-12 20:05:13 +08:00
unsigned char outc = ( unsigned char ) output ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
if ( infop - > length < infop - > max ) {
/* only do this if we haven't reached max length yet */
2004-05-12 20:05:13 +08:00
infop - > buffer [ 0 ] = outc ; /* store */
2000-11-15 23:36:41 +08:00
infop - > buffer + + ; /* increase pointer */
infop - > length + + ; /* we are now one byte larger */
2004-05-12 20:05:13 +08:00
return outc ; /* fputc() returns like this on success */
1999-12-29 22:20:26 +08:00
}
return - 1 ;
}
2003-10-26 23:37:45 +08:00
int curl_mvsnprintf ( char * buffer , size_t maxlength , const char * format ,
va_list ap_save )
1999-12-29 22:20:26 +08:00
{
int retcode ;
struct nsprintf info ;
info . buffer = buffer ;
info . length = 0 ;
info . max = maxlength ;
retcode = dprintf_formatf ( & info , addbyter , format , ap_save ) ;
2003-10-26 23:37:45 +08:00
if ( info . max ) {
/* we terminate this with a zero byte */
if ( info . max = = info . length )
/* we're at maximum, scrap the last letter */
info . buffer [ - 1 ] = 0 ;
else
info . buffer [ 0 ] = 0 ;
}
1999-12-29 22:20:26 +08:00
return retcode ;
}
2003-10-26 23:37:45 +08:00
int curl_msnprintf ( char * buffer , size_t maxlength , const char * format , . . . )
1999-12-29 22:20:26 +08:00
{
int retcode ;
2003-10-26 23:37:45 +08:00
va_list ap_save ; /* argument pointer */
va_start ( ap_save , format ) ;
retcode = curl_mvsnprintf ( buffer , maxlength , format , ap_save ) ;
va_end ( ap_save ) ;
1999-12-29 22:20:26 +08:00
return retcode ;
}
/* fputc() look-alike */
2004-11-08 22:20:14 +08:00
static int alloc_addbyter ( int output , FILE * data )
1999-12-29 22:20:26 +08:00
{
struct asprintf * infop = ( struct asprintf * ) data ;
2004-05-12 20:05:13 +08:00
unsigned char outc = ( unsigned char ) output ;
2004-06-24 15:43:48 +08:00
1999-12-29 22:20:26 +08:00
if ( ! infop - > buffer ) {
2008-09-06 13:29:05 +08:00
infop - > buffer = malloc ( 32 ) ;
2004-05-10 18:50:43 +08:00
if ( ! infop - > buffer ) {
2008-08-22 14:53:01 +08:00
infop - > fail = 1 ;
1999-12-29 22:20:26 +08:00
return - 1 ; /* fail */
2004-05-10 18:50:43 +08:00
}
1999-12-29 22:20:26 +08:00
infop - > alloc = 32 ;
infop - > len = 0 ;
}
else if ( infop - > len + 1 > = infop - > alloc ) {
char * newptr ;
2008-09-06 12:28:43 +08:00
newptr = realloc ( infop - > buffer , infop - > alloc * 2 ) ;
1999-12-29 22:20:26 +08:00
if ( ! newptr ) {
2008-08-22 14:53:01 +08:00
infop - > fail = 1 ;
return - 1 ; /* fail */
1999-12-29 22:20:26 +08:00
}
infop - > buffer = newptr ;
infop - > alloc * = 2 ;
}
2004-05-12 20:05:13 +08:00
infop - > buffer [ infop - > len ] = outc ;
1999-12-29 22:20:26 +08:00
infop - > len + + ;
2004-05-12 20:05:13 +08:00
return outc ; /* fputc() returns like this on success */
1999-12-29 22:20:26 +08:00
}
2001-01-05 20:19:42 +08:00
char * curl_maprintf ( const char * format , . . . )
1999-12-29 22:20:26 +08:00
{
va_list ap_save ; /* argument pointer */
int retcode ;
struct asprintf info ;
info . buffer = NULL ;
info . len = 0 ;
info . alloc = 0 ;
2008-08-22 14:53:01 +08:00
info . fail = 0 ;
1999-12-29 22:20:26 +08:00
va_start ( ap_save , format ) ;
retcode = dprintf_formatf ( & info , alloc_addbyter , format , ap_save ) ;
va_end ( ap_save ) ;
2004-05-10 18:50:43 +08:00
if ( ( - 1 = = retcode ) | | info . fail ) {
2002-05-22 01:59:57 +08:00
if ( info . alloc )
free ( info . buffer ) ;
return NULL ;
}
if ( info . alloc ) {
1999-12-29 22:20:26 +08:00
info . buffer [ info . len ] = 0 ; /* we terminate this with a zero byte */
return info . buffer ;
}
else
2002-05-22 01:59:57 +08:00
return strdup ( " " ) ;
1999-12-29 22:20:26 +08:00
}
2001-01-05 20:19:42 +08:00
char * curl_mvaprintf ( const char * format , va_list ap_save )
1999-12-29 22:20:26 +08:00
{
int retcode ;
struct asprintf info ;
info . buffer = NULL ;
info . len = 0 ;
info . alloc = 0 ;
2008-08-22 14:53:01 +08:00
info . fail = 0 ;
1999-12-29 22:20:26 +08:00
retcode = dprintf_formatf ( & info , alloc_addbyter , format , ap_save ) ;
2004-05-10 18:50:43 +08:00
if ( ( - 1 = = retcode ) | | info . fail ) {
2002-05-22 01:59:57 +08:00
if ( info . alloc )
free ( info . buffer ) ;
return NULL ;
}
if ( info . alloc ) {
1999-12-29 22:20:26 +08:00
info . buffer [ info . len ] = 0 ; /* we terminate this with a zero byte */
return info . buffer ;
}
else
2002-05-22 01:59:57 +08:00
return strdup ( " " ) ;
1999-12-29 22:20:26 +08:00
}
2004-11-08 22:20:14 +08:00
static int storebuffer ( int output , FILE * data )
1999-12-29 22:20:26 +08:00
{
char * * buffer = ( char * * ) data ;
2004-05-12 20:05:13 +08:00
unsigned char outc = ( unsigned char ) output ;
* * buffer = outc ;
1999-12-29 22:20:26 +08:00
( * buffer ) + + ;
2004-05-12 20:05:13 +08:00
return outc ; /* act like fputc() ! */
1999-12-29 22:20:26 +08:00
}
2001-01-05 20:19:42 +08:00
int curl_msprintf ( char * buffer , const char * format , . . . )
1999-12-29 22:20:26 +08:00
{
va_list ap_save ; /* argument pointer */
int retcode ;
va_start ( ap_save , format ) ;
retcode = dprintf_formatf ( & buffer , storebuffer , format , ap_save ) ;
va_end ( ap_save ) ;
* buffer = 0 ; /* we terminate this with a zero byte */
return retcode ;
}
2001-01-05 20:19:42 +08:00
int curl_mprintf ( const char * format , . . . )
1999-12-29 22:20:26 +08:00
{
int retcode ;
va_list ap_save ; /* argument pointer */
va_start ( ap_save , format ) ;
2004-11-02 18:12:22 +08:00
1999-12-29 22:20:26 +08:00
retcode = dprintf_formatf ( stdout , fputc , format , ap_save ) ;
va_end ( ap_save ) ;
return retcode ;
}
2001-01-05 20:19:42 +08:00
int curl_mfprintf ( FILE * whereto , const char * format , . . . )
1999-12-29 22:20:26 +08:00
{
int retcode ;
va_list ap_save ; /* argument pointer */
va_start ( ap_save , format ) ;
retcode = dprintf_formatf ( whereto , fputc , format , ap_save ) ;
va_end ( ap_save ) ;
return retcode ;
}
2001-01-05 20:19:42 +08:00
int curl_mvsprintf ( char * buffer , const char * format , va_list ap_save )
1999-12-29 22:20:26 +08:00
{
int retcode ;
retcode = dprintf_formatf ( & buffer , storebuffer , format , ap_save ) ;
* buffer = 0 ; /* we terminate this with a zero byte */
return retcode ;
}
2001-01-05 20:19:42 +08:00
int curl_mvprintf ( const char * format , va_list ap_save )
1999-12-29 22:20:26 +08:00
{
return dprintf_formatf ( stdout , fputc , format , ap_save ) ;
}
2001-01-05 20:19:42 +08:00
int curl_mvfprintf ( FILE * whereto , const char * format , va_list ap_save )
1999-12-29 22:20:26 +08:00
{
return dprintf_formatf ( whereto , fputc , format , ap_save ) ;
}
# ifdef DPRINTF_DEBUG
int main ( )
{
char buffer [ 129 ] ;
char * ptr ;
2008-08-21 08:06:15 +08:00
# ifdef HAVE_LONG_LONG_TYPE
LONG_LONG_TYPE one = 99 ;
LONG_LONG_TYPE two = 100 ;
LONG_LONG_TYPE test = 0x1000000000LL ;
2004-03-02 00:22:17 +08:00
curl_mprintf ( " %lld %lld %lld \n " , one , two , test ) ;
1999-12-29 22:20:26 +08:00
# endif
2004-03-02 00:22:17 +08:00
curl_mprintf ( " %3d %5d \n " , 10 , 1998 ) ;
2004-06-24 15:43:48 +08:00
2004-03-02 00:22:17 +08:00
ptr = curl_maprintf ( " test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now! " , " " , " pretty long string pretty long string pretty long string pretty long string pretty long string " , " / " , " / " , " / " , " pretty long string " , 1998 , 1999 , 2001 ) ;
1999-12-29 22:20:26 +08:00
puts ( ptr ) ;
memset ( ptr , 55 , strlen ( ptr ) + 1 ) ;
free ( ptr ) ;
# if 1
2004-03-02 00:22:17 +08:00
curl_mprintf ( buffer , " %s %s %d " , " daniel " , " stenberg " , 19988 ) ;
1999-12-29 22:20:26 +08:00
puts ( buffer ) ;
2004-03-02 00:22:17 +08:00
curl_mfprintf ( stderr , " %s %#08x \n " , " dummy " , 65 ) ;
1999-12-29 22:20:26 +08:00
printf ( " %s %#08x \n " , " dummy " , 65 ) ;
{
double tryout = 3.14156592 ;
2004-03-02 00:22:17 +08:00
curl_mprintf ( buffer , " %.2g %G %f %e %E " , tryout , tryout , tryout , tryout , tryout ) ;
1999-12-29 22:20:26 +08:00
puts ( buffer ) ;
printf ( " %.2g %G %f %e %E \n " , tryout , tryout , tryout , tryout , tryout ) ;
}
# endif
return 0 ;
}
# endif