Newer
Older
/****************************************************************************
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
*
*************************************************************************
*
* 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 WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
*
* 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 <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <curl/mprintf.h>
#ifdef _WIN32_WCE
#define CURL_CDECL __cdecl
#else
#define CURL_CDECL
#endif
#ifndef SIZEOF_LONG_DOUBLE
#define SIZEOF_LONG_DOUBLE 0
#endif
#ifndef SIZEOF_SIZE_T
/* default to 4 bytes for size_t unless defined in the config.h */
#define SIZEOF_SIZE_T 4
#endif
#ifdef DPRINTF_DEBUG
#define HAVE_LONGLONG
#define LONG_LONG long long
#define ENABLE_64BIT
#endif
#include "memory.h"
/* The last #include file should be: */
#include "memdebug.h"
#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
#define MAX_PARAMETERS 128 /* lame static limit */
#undef TRUE
#undef FALSE
#undef BOOL
#ifdef __cplusplus
# define TRUE true
# define FALSE false
# define BOOL bool
#else
# define TRUE ((char)(1 == 1))
# define FALSE ((char)(0 == 1))
# define BOOL char
#endif
/* Lower-case digits. */
static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
/* Upper-case digits. */
static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
#define OUTCHAR(x) \
do{ \
if(stream((unsigned char)(x), (FILE *)data) != -1) \
done++; \
else \
return done; /* return immediately on failure */ \
} while(0)
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* 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;
long width; /* width OR width parameter number */
long precision; /* precision OR precision parameter number */
union {
char *str;
void *ptr;
long num;
#ifdef ENABLE_64BIT
LONG_LONG lnum;
#endif
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 */
Daniel Stenberg
committed
bool fail; /* TRUE if an alloc has failed and thus the output is not
the complete data */
};
int curl_msprintf(char *buffer, const char *format, ...);
static long dprintf_DollarString(char *input, char **end)
{
int number=0;
while(isdigit((int)*input)) {
number *= 10;
number += *input-'0';
input++;
}
if(number && ('$'==*input++)) {
*end = input;
return number;
}
return 0;
}
static BOOL dprintf_IsQualifierNoDollar(char c)
{
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':
case 'h': case 'l': case 'L': case 'z': case 'q':
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
return TRUE;
default:
return FALSE;
}
}
#ifdef DPRINTF_DEBUG2
int dprintf_Pass1Report(va_stack_t *vto, int max)
{
int i;
char buffer[128];
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;
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";
Daniel Stenberg
committed
break;
}
buffer[0]=0;
for(bit=0; bit<31; bit++) {
flags = vto[i].flags & (1<<bit);
if(flags & FLAGS_SPACE)
strcat(buffer, "space ");
strcat(buffer, "plus ");
strcat(buffer, "left ");
strcat(buffer, "alt ");
strcat(buffer, "short ");
strcat(buffer, "long ");
strcat(buffer, "longlong ");
strcat(buffer, "longdouble ");
strcat(buffer, "padnil ");
strcat(buffer, "unsigned ");
strcat(buffer, "octal ");
strcat(buffer, "hex ");
strcat(buffer, "upper ");
strcat(buffer, "width ");
strcat(buffer, "widthparam ");
strcat(buffer, "precision ");
strcat(buffer, "precparam ");
strcat(buffer, "char ");
strcat(buffer, "floate ");
strcat(buffer, "floatg ");
}
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)
*
******************************************************************/
static long dprintf_Pass1(char *format, va_stack_t *vto, char **endpos,
va_list arglist)
long this_param;
long width;
long precision;
while (*fmt) {
if (*fmt++ == '%') {
if (*fmt == '%') {
fmt++;
continue; /* while */
}
flags = FLAGS_NEW;
/* Handle the positional case (N$) */
param_num++;
Daniel Stenberg
committed
this_param = dprintf_DollarString(fmt, &fmt);
if (0 == this_param)
/* we got no positional, get the next counter */
this_param = param_num;
max_param = this_param;
/*
* 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 */
while (dprintf_IsQualifierNoDollar(*fmt)) {
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
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;
if ('*' == *fmt) {
/* The precision is picked from a specified parameter */
flags |= FLAGS_PRECPARAM;
fmt++;
param_num++;
i = dprintf_DollarString(fmt, &fmt);
if (i)
precision = i;
else
precision = param_num;
if (precision > max_param)
max_param = precision;
}
else {
flags |= FLAGS_PREC;
precision = strtol(fmt, &fmt, 10);
}
break;
case 'h':
flags |= FLAGS_SHORT;
break;
case 'l':
if (flags & FLAGS_LONG)
flags |= FLAGS_LONGLONG;
else
flags |= FLAGS_LONG;
break;
case 'L':
flags |= FLAGS_LONGDOUBLE;
break;
case 'q':
flags |= FLAGS_LONGLONG;
break;
case 'z':
/* the code below generates a warning if -Wunreachable-code is
used */
#if SIZEOF_SIZE_T>4
flags |= FLAGS_LONGLONG;
#else
flags |= FLAGS_LONG;
#endif
break;
#if SIZEOF_CURL_OFF_T > 4
flags |= FLAGS_LONGLONG;
#else
flags |= FLAGS_LONG;
#endif
case '0':
if (!(flags & FLAGS_LEFT))
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;
}
} /* switch */
/* Handle the specifier */
i = this_param - 1;
switch (*fmt) {
case 'S':
flags |= FLAGS_ALT;
/* FALLTHROUGH */
vto[i].type = FORMAT_STRING;
break;
vto[i].type = FORMAT_INTPTR;
break;
vto[i].type = FORMAT_PTR;
break;
vto[i].type = FORMAT_INT;
break;
vto[i].type = FORMAT_INT;
flags |= FLAGS_UNSIGNED;
break;
vto[i].type = FORMAT_INT;
flags |= FLAGS_OCTAL;
break;
vto[i].type = FORMAT_INT;
flags |= FLAGS_HEX;
break;
vto[i].type = FORMAT_INT;
flags |= FLAGS_HEX|FLAGS_UPPER;
break;
vto[i].type = FORMAT_INT;
flags |= FLAGS_CHAR;
break;
vto[i].type = FORMAT_DOUBLE;
break;
vto[i].type = FORMAT_DOUBLE;
flags |= FLAGS_FLOATE;
break;
vto[i].type = FORMAT_DOUBLE;
flags |= FLAGS_FLOATE|FLAGS_UPPER;
break;
vto[i].type = FORMAT_DOUBLE;
flags |= FLAGS_FLOATG;
break;
vto[i].type = FORMAT_DOUBLE;
flags |= FLAGS_FLOATG|FLAGS_UPPER;
break;
vto[i].type = FORMAT_UNKNOWN;
break;
} /* switch */
vto[i].flags = flags;
vto[i].width = width;
vto[i].precision = precision;
Daniel Stenberg
committed
/* 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! */
/* 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! */
}
*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++) {
if ((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH))
{
/* Width/precision arguments must be read before the main argument
* they are attached to
*/
vto[i + 1].data.num = va_arg(arglist, int);
}
switch (vto[i].type)
{
case FORMAT_STRING:
vto[i].data.str = va_arg(arglist, char *);
break;
Daniel Stenberg
committed
case FORMAT_INTPTR:
case FORMAT_UNKNOWN:
case FORMAT_PTR:
vto[i].data.ptr = va_arg(arglist, void *);
break;
Daniel Stenberg
committed
#ifdef ENABLE_64BIT
if(vto[i].flags & FLAGS_LONGLONG)
vto[i].data.lnum = va_arg(arglist, LONG_LONG);
else
if(vto[i].flags & FLAGS_LONG)
vto[i].data.num = va_arg(arglist, long);
else
vto[i].data.num = va_arg(arglist, int);
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
vto[i].data.dnum = va_arg(arglist, double);
break;
Daniel Stenberg
committed
/* Argument has been read. Silently convert it into an integer
* for later use
*/
vto[i].type = FORMAT_INT;
break;
Daniel Stenberg
committed
break;
}
}
return max_param;
}
static int dprintf_formatf(
void *data, /* untouched by format(), just sent to the stream() function in
the second argument */
/* function pointer called for each output character */
#if _WIN32_WCE
int (__cdecl *stream) (int, FILE *),
#else
int (*stream)(int, FILE *),
const char *format, /* %-formatted string */
va_list ap_save) /* list of parameters */
{
/* Base-36 digits for numbers. */
const char *digits = lower_digits;
/* Pointer into the format string. */
char *f;
/* Number of characters written. */
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 */
dprintf_Pass1((char *)format, vto, endpos, ap_save);
end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
created for us */
Daniel Stenberg
committed
f = (char *)format;
while (*f != '\0') {
/* Format spec modifiers. */
char alt;
Daniel Stenberg
committed
long width;
Daniel Stenberg
committed
Daniel Stenberg
committed
/* Base of a number to be written. */
long base;
/* Integral values to be written. */
#ifdef ENABLE_64BIT
unsigned LONG_LONG num;
#else
unsigned long num;
#endif
long signed_num;
Daniel Stenberg
committed
if (*f != '%') {
/* This isn't a format spec, so write everything out until the next one
OR end of string is reached. */
OUTCHAR(*f);
Daniel Stenberg
committed
Daniel Stenberg
committed
/* 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. */
if (*f == '%') {
++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;
Daniel Stenberg
committed
param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
third %s will pick the 3rd argument */
p = &vto[param];
/* pick up the specified width */
if(p->flags & FLAGS_WIDTHPARAM)
width = vto[p->width].data.num;
else
width = p->width;
/* pick up the specified precision */
if(p->flags & FLAGS_PRECPARAM)
prec = vto[p->precision].data.num;
else if(p->flags & FLAGS_PREC)
prec = p->precision;
else
prec = -1;
Daniel Stenberg
committed
switch (p->type) {
case FORMAT_INT:
num = p->data.num;
if(p->flags & FLAGS_CHAR) {
/* Character. */
if (!(p->flags & FLAGS_LEFT))
while (--width > 0)
OUTCHAR(' ');
OUTCHAR((char) num);
if (p->flags & FLAGS_LEFT)
while (--width > 0)
OUTCHAR(' ');
break;
/* Decimal unsigned integer. */
base = 10;
goto unsigned_number;
/* Octal unsigned integer. */
base = 8;
goto unsigned_number;
/* Hexadecimal unsigned integer. */
digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
base = 16;
goto unsigned_number;
#ifdef ENABLE_64BIT
is_neg = p->data.lnum < 0;
num = is_neg ? (- p->data.lnum) : p->data.lnum;
signed_num = (long) num;
is_neg = signed_num < 0;
num = is_neg ? (- signed_num) : signed_num;
Daniel Stenberg
committed
unsigned_number:
Daniel Stenberg
committed
number:
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
char *workend = &work[sizeof(work) - 1];
char *w;
/* Supply a default precision if none was given. */
if (prec == -1)
prec = 1;
/* Put the number in WORK. */
w = workend;
while (num > 0) {
*w-- = digits[num % base];
num /= base;
}
width -= workend - w;
prec -= workend - w;
if (alt && base == 8 && prec <= 0) {
*w-- = '0';
--width;
}
if (prec > 0) {
width -= prec;
while (prec-- > 0)
*w-- = '0';
}
if (alt && base == 16)
width -= 2;
if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
--width;
if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
while (width-- > 0)
OUTCHAR(' ');
if (is_neg)
OUTCHAR('-');
else if (p->flags & FLAGS_SHOWSIGN)
OUTCHAR('+');
else if (p->flags & FLAGS_SPACE)
OUTCHAR(' ');
if (alt && base == 16) {
OUTCHAR('0');
if(p->flags & FLAGS_UPPER)
OUTCHAR('X');
else
OUTCHAR('x');
}
if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
while (width-- > 0)
OUTCHAR('0');
/* Write the number. */
while (++w <= workend) {
OUTCHAR(*w);
}
if (p->flags & FLAGS_LEFT)
while (width-- > 0)
OUTCHAR(' ');
Daniel Stenberg
committed
/* String. */
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
static char null[] = "(nil)";
char *str;
size_t len;
str = (char *) p->data.str;
if ( str == NULL) {
/* Write null[] if there's space. */
if (prec == -1 || prec >= (long) sizeof(null) - 1) {
str = null;
len = sizeof(null) - 1;
/* Disable quotes around (nil) */
p->flags &= (~FLAGS_ALT);
}
else {
str = (char *)"";
len = 0;
}
}
else
len = strlen(str);
if (prec != -1 && (size_t) prec < len)
len = prec;
width -= len;
if (p->flags & FLAGS_ALT)
OUTCHAR('"');
if (!(p->flags&FLAGS_LEFT))
while (width-- > 0)
OUTCHAR(' ');
while (len-- > 0)
OUTCHAR(*str++);
if (p->flags&FLAGS_LEFT)
while (width-- > 0)
OUTCHAR(' ');
if (p->flags & FLAGS_ALT)
OUTCHAR('"');
Daniel Stenberg
committed
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
void *ptr;
ptr = (void *) p->data.ptr;
if (ptr != NULL) {
/* If the pointer is not NULL, write it as a %#x spec. */
base = 16;
digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
alt = 1;
num = (unsigned long) ptr;
is_neg = 0;
goto number;
}
else {
/* Write "(nil)" for a nil pointer. */
static char strnil[] = "(nil)";
char *point;
width -= sizeof(strnil) - 1;
if (p->flags & FLAGS_LEFT)
while (width-- > 0)
OUTCHAR(' ');
for (point = strnil; *point != '\0'; ++point)
OUTCHAR(*point);
if (! (p->flags & FLAGS_LEFT))
while (width-- > 0)
OUTCHAR(' ');
}
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
char formatbuf[32]="%";
char *fptr;
size_t left = sizeof(formatbuf)-strlen(formatbuf);
int len;
width = -1;
if (p->flags & FLAGS_WIDTH)
width = p->width;
else if (p->flags & FLAGS_WIDTHPARAM)
width = vto[p->width].data.num;
prec = -1;
if (p->flags & FLAGS_PREC)
prec = p->precision;
else if (p->flags & FLAGS_PRECPARAM)
prec = vto[p->precision].data.num;
if (p->flags & FLAGS_LEFT)
strcat(formatbuf, "-");
if (p->flags & FLAGS_SHOWSIGN)
strcat(formatbuf, "+");
if (p->flags & FLAGS_SPACE)
strcat(formatbuf, " ");
if (p->flags & FLAGS_ALT)
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;
}
if (p->flags & FLAGS_LONG)
*fptr++ = 'l';
if (p->flags & FLAGS_FLOATE)
*fptr++ = p->flags&FLAGS_UPPER ? 'E':'e';
else if (p->flags & FLAGS_FLOATG)
*fptr++ = p->flags & FLAGS_UPPER ? 'G' : 'g';
else
*fptr++ = 'f';
*fptr = 0; /* and a final zero termination */
/* NOTE NOTE NOTE!! Not all sprintf() implementations returns number
of output characters */
Daniel Stenberg
committed
(sprintf)(work, formatbuf, p->data.dnum);
for(fptr=work; *fptr; fptr++)
OUTCHAR(*fptr);
}
break;
case FORMAT_INTPTR:
/* Answer the count of characters written. */
#ifdef ENABLE_64BIT
*(LONG_LONG *) p->data.ptr = (LONG_LONG)done;
if (p->flags & FLAGS_LONG)
*(long *) p->data.ptr = (long)done;
*(int *) p->data.ptr = (int)done;
*(short *) p->data.ptr = (short)done;
break;
default:
break;
}
f = *end++; /* goto end of %-code */
}
return done;
}
/* fputc() look-alike */
static int CURL_CDECL addbyter(int output, FILE *data)
{
struct nsprintf *infop=(struct nsprintf *)data;
unsigned char outc = (unsigned char)output;
Daniel Stenberg
committed
if(infop->length < infop->max) {
/* only do this if we haven't reached max length yet */
infop->buffer[0] = outc; /* store */