1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker */
24*6236dae4SAndroid Build Coastguard Worker
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker #include "dynbuf.h"
27*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
28*6236dae4SAndroid Build Coastguard Worker
29*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
30*6236dae4SAndroid Build Coastguard Worker /* The last #include file should be: */
31*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
32*6236dae4SAndroid Build Coastguard Worker
33*6236dae4SAndroid Build Coastguard Worker /*
34*6236dae4SAndroid Build Coastguard Worker * If SIZEOF_SIZE_T has not been defined, default to the size of long.
35*6236dae4SAndroid Build Coastguard Worker */
36*6236dae4SAndroid Build Coastguard Worker
37*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_LONGLONG
38*6236dae4SAndroid Build Coastguard Worker # define LONG_LONG_TYPE long long
39*6236dae4SAndroid Build Coastguard Worker # define HAVE_LONG_LONG_TYPE
40*6236dae4SAndroid Build Coastguard Worker #else
41*6236dae4SAndroid Build Coastguard Worker # if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
42*6236dae4SAndroid Build Coastguard Worker # define LONG_LONG_TYPE __int64
43*6236dae4SAndroid Build Coastguard Worker # define HAVE_LONG_LONG_TYPE
44*6236dae4SAndroid Build Coastguard Worker # else
45*6236dae4SAndroid Build Coastguard Worker # undef LONG_LONG_TYPE
46*6236dae4SAndroid Build Coastguard Worker # undef HAVE_LONG_LONG_TYPE
47*6236dae4SAndroid Build Coastguard Worker # endif
48*6236dae4SAndroid Build Coastguard Worker #endif
49*6236dae4SAndroid Build Coastguard Worker
50*6236dae4SAndroid Build Coastguard Worker /*
51*6236dae4SAndroid Build Coastguard Worker * Max integer data types that mprintf.c is capable
52*6236dae4SAndroid Build Coastguard Worker */
53*6236dae4SAndroid Build Coastguard Worker
54*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_LONG_LONG_TYPE
55*6236dae4SAndroid Build Coastguard Worker # define mp_intmax_t LONG_LONG_TYPE
56*6236dae4SAndroid Build Coastguard Worker # define mp_uintmax_t unsigned LONG_LONG_TYPE
57*6236dae4SAndroid Build Coastguard Worker #else
58*6236dae4SAndroid Build Coastguard Worker # define mp_intmax_t long
59*6236dae4SAndroid Build Coastguard Worker # define mp_uintmax_t unsigned long
60*6236dae4SAndroid Build Coastguard Worker #endif
61*6236dae4SAndroid Build Coastguard Worker
62*6236dae4SAndroid Build Coastguard Worker #define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should
63*6236dae4SAndroid Build Coastguard Worker fit negative DBL_MAX (317 letters) */
64*6236dae4SAndroid Build Coastguard Worker #define MAX_PARAMETERS 128 /* number of input arguments */
65*6236dae4SAndroid Build Coastguard Worker #define MAX_SEGMENTS 128 /* number of output segments */
66*6236dae4SAndroid Build Coastguard Worker
67*6236dae4SAndroid Build Coastguard Worker #ifdef __AMIGA__
68*6236dae4SAndroid Build Coastguard Worker # undef FORMAT_INT
69*6236dae4SAndroid Build Coastguard Worker #endif
70*6236dae4SAndroid Build Coastguard Worker
71*6236dae4SAndroid Build Coastguard Worker /* Lower-case digits. */
72*6236dae4SAndroid Build Coastguard Worker static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
73*6236dae4SAndroid Build Coastguard Worker
74*6236dae4SAndroid Build Coastguard Worker /* Upper-case digits. */
75*6236dae4SAndroid Build Coastguard Worker static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
76*6236dae4SAndroid Build Coastguard Worker
77*6236dae4SAndroid Build Coastguard Worker #define OUTCHAR(x) \
78*6236dae4SAndroid Build Coastguard Worker do { \
79*6236dae4SAndroid Build Coastguard Worker if(!stream((unsigned char)x, userp)) \
80*6236dae4SAndroid Build Coastguard Worker done++; \
81*6236dae4SAndroid Build Coastguard Worker else \
82*6236dae4SAndroid Build Coastguard Worker return done; /* return on failure */ \
83*6236dae4SAndroid Build Coastguard Worker } while(0)
84*6236dae4SAndroid Build Coastguard Worker
85*6236dae4SAndroid Build Coastguard Worker /* Data type to read from the arglist */
86*6236dae4SAndroid Build Coastguard Worker typedef enum {
87*6236dae4SAndroid Build Coastguard Worker FORMAT_STRING,
88*6236dae4SAndroid Build Coastguard Worker FORMAT_PTR,
89*6236dae4SAndroid Build Coastguard Worker FORMAT_INTPTR,
90*6236dae4SAndroid Build Coastguard Worker FORMAT_INT,
91*6236dae4SAndroid Build Coastguard Worker FORMAT_LONG,
92*6236dae4SAndroid Build Coastguard Worker FORMAT_LONGLONG,
93*6236dae4SAndroid Build Coastguard Worker FORMAT_INTU,
94*6236dae4SAndroid Build Coastguard Worker FORMAT_LONGU,
95*6236dae4SAndroid Build Coastguard Worker FORMAT_LONGLONGU,
96*6236dae4SAndroid Build Coastguard Worker FORMAT_DOUBLE,
97*6236dae4SAndroid Build Coastguard Worker FORMAT_LONGDOUBLE,
98*6236dae4SAndroid Build Coastguard Worker FORMAT_WIDTH,
99*6236dae4SAndroid Build Coastguard Worker FORMAT_PRECISION
100*6236dae4SAndroid Build Coastguard Worker } FormatType;
101*6236dae4SAndroid Build Coastguard Worker
102*6236dae4SAndroid Build Coastguard Worker /* conversion and display flags */
103*6236dae4SAndroid Build Coastguard Worker enum {
104*6236dae4SAndroid Build Coastguard Worker FLAGS_SPACE = 1 << 0,
105*6236dae4SAndroid Build Coastguard Worker FLAGS_SHOWSIGN = 1 << 1,
106*6236dae4SAndroid Build Coastguard Worker FLAGS_LEFT = 1 << 2,
107*6236dae4SAndroid Build Coastguard Worker FLAGS_ALT = 1 << 3,
108*6236dae4SAndroid Build Coastguard Worker FLAGS_SHORT = 1 << 4,
109*6236dae4SAndroid Build Coastguard Worker FLAGS_LONG = 1 << 5,
110*6236dae4SAndroid Build Coastguard Worker FLAGS_LONGLONG = 1 << 6,
111*6236dae4SAndroid Build Coastguard Worker FLAGS_LONGDOUBLE = 1 << 7,
112*6236dae4SAndroid Build Coastguard Worker FLAGS_PAD_NIL = 1 << 8,
113*6236dae4SAndroid Build Coastguard Worker FLAGS_UNSIGNED = 1 << 9,
114*6236dae4SAndroid Build Coastguard Worker FLAGS_OCTAL = 1 << 10,
115*6236dae4SAndroid Build Coastguard Worker FLAGS_HEX = 1 << 11,
116*6236dae4SAndroid Build Coastguard Worker FLAGS_UPPER = 1 << 12,
117*6236dae4SAndroid Build Coastguard Worker FLAGS_WIDTH = 1 << 13, /* '*' or '*<num>$' used */
118*6236dae4SAndroid Build Coastguard Worker FLAGS_WIDTHPARAM = 1 << 14, /* width PARAMETER was specified */
119*6236dae4SAndroid Build Coastguard Worker FLAGS_PREC = 1 << 15, /* precision was specified */
120*6236dae4SAndroid Build Coastguard Worker FLAGS_PRECPARAM = 1 << 16, /* precision PARAMETER was specified */
121*6236dae4SAndroid Build Coastguard Worker FLAGS_CHAR = 1 << 17, /* %c story */
122*6236dae4SAndroid Build Coastguard Worker FLAGS_FLOATE = 1 << 18, /* %e or %E */
123*6236dae4SAndroid Build Coastguard Worker FLAGS_FLOATG = 1 << 19, /* %g or %G */
124*6236dae4SAndroid Build Coastguard Worker FLAGS_SUBSTR = 1 << 20 /* no input, only substring */
125*6236dae4SAndroid Build Coastguard Worker };
126*6236dae4SAndroid Build Coastguard Worker
127*6236dae4SAndroid Build Coastguard Worker enum {
128*6236dae4SAndroid Build Coastguard Worker DOLLAR_UNKNOWN,
129*6236dae4SAndroid Build Coastguard Worker DOLLAR_NOPE,
130*6236dae4SAndroid Build Coastguard Worker DOLLAR_USE
131*6236dae4SAndroid Build Coastguard Worker };
132*6236dae4SAndroid Build Coastguard Worker
133*6236dae4SAndroid Build Coastguard Worker /*
134*6236dae4SAndroid Build Coastguard Worker * Describes an input va_arg type and hold its value.
135*6236dae4SAndroid Build Coastguard Worker */
136*6236dae4SAndroid Build Coastguard Worker struct va_input {
137*6236dae4SAndroid Build Coastguard Worker FormatType type; /* FormatType */
138*6236dae4SAndroid Build Coastguard Worker union {
139*6236dae4SAndroid Build Coastguard Worker char *str;
140*6236dae4SAndroid Build Coastguard Worker void *ptr;
141*6236dae4SAndroid Build Coastguard Worker mp_intmax_t nums; /* signed */
142*6236dae4SAndroid Build Coastguard Worker mp_uintmax_t numu; /* unsigned */
143*6236dae4SAndroid Build Coastguard Worker double dnum;
144*6236dae4SAndroid Build Coastguard Worker } val;
145*6236dae4SAndroid Build Coastguard Worker };
146*6236dae4SAndroid Build Coastguard Worker
147*6236dae4SAndroid Build Coastguard Worker /*
148*6236dae4SAndroid Build Coastguard Worker * Describes an output segment.
149*6236dae4SAndroid Build Coastguard Worker */
150*6236dae4SAndroid Build Coastguard Worker struct outsegment {
151*6236dae4SAndroid Build Coastguard Worker int width; /* width OR width parameter number */
152*6236dae4SAndroid Build Coastguard Worker int precision; /* precision OR precision parameter number */
153*6236dae4SAndroid Build Coastguard Worker unsigned int flags;
154*6236dae4SAndroid Build Coastguard Worker unsigned int input; /* input argument array index */
155*6236dae4SAndroid Build Coastguard Worker char *start; /* format string start to output */
156*6236dae4SAndroid Build Coastguard Worker size_t outlen; /* number of bytes from the format string to output */
157*6236dae4SAndroid Build Coastguard Worker };
158*6236dae4SAndroid Build Coastguard Worker
159*6236dae4SAndroid Build Coastguard Worker struct nsprintf {
160*6236dae4SAndroid Build Coastguard Worker char *buffer;
161*6236dae4SAndroid Build Coastguard Worker size_t length;
162*6236dae4SAndroid Build Coastguard Worker size_t max;
163*6236dae4SAndroid Build Coastguard Worker };
164*6236dae4SAndroid Build Coastguard Worker
165*6236dae4SAndroid Build Coastguard Worker struct asprintf {
166*6236dae4SAndroid Build Coastguard Worker struct dynbuf *b;
167*6236dae4SAndroid Build Coastguard Worker char merr;
168*6236dae4SAndroid Build Coastguard Worker };
169*6236dae4SAndroid Build Coastguard Worker
170*6236dae4SAndroid Build Coastguard Worker /* the provided input number is 1-based but this returns the number 0-based.
171*6236dae4SAndroid Build Coastguard Worker
172*6236dae4SAndroid Build Coastguard Worker returns -1 if no valid number was provided.
173*6236dae4SAndroid Build Coastguard Worker */
dollarstring(char * input,char ** end)174*6236dae4SAndroid Build Coastguard Worker static int dollarstring(char *input, char **end)
175*6236dae4SAndroid Build Coastguard Worker {
176*6236dae4SAndroid Build Coastguard Worker if(ISDIGIT(*input)) {
177*6236dae4SAndroid Build Coastguard Worker int number = 0;
178*6236dae4SAndroid Build Coastguard Worker do {
179*6236dae4SAndroid Build Coastguard Worker if(number < MAX_PARAMETERS) {
180*6236dae4SAndroid Build Coastguard Worker number *= 10;
181*6236dae4SAndroid Build Coastguard Worker number += *input - '0';
182*6236dae4SAndroid Build Coastguard Worker }
183*6236dae4SAndroid Build Coastguard Worker input++;
184*6236dae4SAndroid Build Coastguard Worker } while(ISDIGIT(*input));
185*6236dae4SAndroid Build Coastguard Worker
186*6236dae4SAndroid Build Coastguard Worker if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) {
187*6236dae4SAndroid Build Coastguard Worker *end = ++input;
188*6236dae4SAndroid Build Coastguard Worker return number - 1;
189*6236dae4SAndroid Build Coastguard Worker }
190*6236dae4SAndroid Build Coastguard Worker }
191*6236dae4SAndroid Build Coastguard Worker return -1;
192*6236dae4SAndroid Build Coastguard Worker }
193*6236dae4SAndroid Build Coastguard Worker
194*6236dae4SAndroid Build Coastguard Worker /*
195*6236dae4SAndroid Build Coastguard Worker * Parse the format string.
196*6236dae4SAndroid Build Coastguard Worker *
197*6236dae4SAndroid Build Coastguard Worker * Create two arrays. One describes the inputs, one describes the outputs.
198*6236dae4SAndroid Build Coastguard Worker *
199*6236dae4SAndroid Build Coastguard Worker * Returns zero on success.
200*6236dae4SAndroid Build Coastguard Worker */
201*6236dae4SAndroid Build Coastguard Worker
202*6236dae4SAndroid Build Coastguard Worker #define PFMT_OK 0
203*6236dae4SAndroid Build Coastguard Worker #define PFMT_DOLLAR 1 /* bad dollar for main param */
204*6236dae4SAndroid Build Coastguard Worker #define PFMT_DOLLARWIDTH 2 /* bad dollar use for width */
205*6236dae4SAndroid Build Coastguard Worker #define PFMT_DOLLARPREC 3 /* bad dollar use for precision */
206*6236dae4SAndroid Build Coastguard Worker #define PFMT_MANYARGS 4 /* too many input arguments used */
207*6236dae4SAndroid Build Coastguard Worker #define PFMT_PREC 5 /* precision overflow */
208*6236dae4SAndroid Build Coastguard Worker #define PFMT_PRECMIX 6 /* bad mix of precision specifiers */
209*6236dae4SAndroid Build Coastguard Worker #define PFMT_WIDTH 7 /* width overflow */
210*6236dae4SAndroid Build Coastguard Worker #define PFMT_INPUTGAP 8 /* gap in arguments */
211*6236dae4SAndroid Build Coastguard Worker #define PFMT_WIDTHARG 9 /* attempted to use same arg twice, for width */
212*6236dae4SAndroid Build Coastguard Worker #define PFMT_PRECARG 10 /* attempted to use same arg twice, for prec */
213*6236dae4SAndroid Build Coastguard Worker #define PFMT_MANYSEGS 11 /* maxed out output segments */
214*6236dae4SAndroid Build Coastguard Worker
parsefmt(const char * format,struct outsegment * out,struct va_input * in,int * opieces,int * ipieces,va_list arglist)215*6236dae4SAndroid Build Coastguard Worker static int parsefmt(const char *format,
216*6236dae4SAndroid Build Coastguard Worker struct outsegment *out,
217*6236dae4SAndroid Build Coastguard Worker struct va_input *in,
218*6236dae4SAndroid Build Coastguard Worker int *opieces,
219*6236dae4SAndroid Build Coastguard Worker int *ipieces, va_list arglist)
220*6236dae4SAndroid Build Coastguard Worker {
221*6236dae4SAndroid Build Coastguard Worker char *fmt = (char *)format;
222*6236dae4SAndroid Build Coastguard Worker int param_num = 0;
223*6236dae4SAndroid Build Coastguard Worker int param;
224*6236dae4SAndroid Build Coastguard Worker int width;
225*6236dae4SAndroid Build Coastguard Worker int precision;
226*6236dae4SAndroid Build Coastguard Worker unsigned int flags;
227*6236dae4SAndroid Build Coastguard Worker FormatType type;
228*6236dae4SAndroid Build Coastguard Worker int max_param = -1;
229*6236dae4SAndroid Build Coastguard Worker int i;
230*6236dae4SAndroid Build Coastguard Worker int ocount = 0;
231*6236dae4SAndroid Build Coastguard Worker unsigned char usedinput[MAX_PARAMETERS/8];
232*6236dae4SAndroid Build Coastguard Worker size_t outlen = 0;
233*6236dae4SAndroid Build Coastguard Worker struct outsegment *optr;
234*6236dae4SAndroid Build Coastguard Worker int use_dollar = DOLLAR_UNKNOWN;
235*6236dae4SAndroid Build Coastguard Worker char *start = fmt;
236*6236dae4SAndroid Build Coastguard Worker
237*6236dae4SAndroid Build Coastguard Worker /* clear, set a bit for each used input */
238*6236dae4SAndroid Build Coastguard Worker memset(usedinput, 0, sizeof(usedinput));
239*6236dae4SAndroid Build Coastguard Worker
240*6236dae4SAndroid Build Coastguard Worker while(*fmt) {
241*6236dae4SAndroid Build Coastguard Worker if(*fmt == '%') {
242*6236dae4SAndroid Build Coastguard Worker struct va_input *iptr;
243*6236dae4SAndroid Build Coastguard Worker bool loopit = TRUE;
244*6236dae4SAndroid Build Coastguard Worker fmt++;
245*6236dae4SAndroid Build Coastguard Worker outlen = (size_t)(fmt - start - 1);
246*6236dae4SAndroid Build Coastguard Worker if(*fmt == '%') {
247*6236dae4SAndroid Build Coastguard Worker /* this means a %% that should be output only as %. Create an output
248*6236dae4SAndroid Build Coastguard Worker segment. */
249*6236dae4SAndroid Build Coastguard Worker if(outlen) {
250*6236dae4SAndroid Build Coastguard Worker optr = &out[ocount++];
251*6236dae4SAndroid Build Coastguard Worker if(ocount > MAX_SEGMENTS)
252*6236dae4SAndroid Build Coastguard Worker return PFMT_MANYSEGS;
253*6236dae4SAndroid Build Coastguard Worker optr->input = 0;
254*6236dae4SAndroid Build Coastguard Worker optr->flags = FLAGS_SUBSTR;
255*6236dae4SAndroid Build Coastguard Worker optr->start = start;
256*6236dae4SAndroid Build Coastguard Worker optr->outlen = outlen;
257*6236dae4SAndroid Build Coastguard Worker }
258*6236dae4SAndroid Build Coastguard Worker start = fmt;
259*6236dae4SAndroid Build Coastguard Worker fmt++;
260*6236dae4SAndroid Build Coastguard Worker continue; /* while */
261*6236dae4SAndroid Build Coastguard Worker }
262*6236dae4SAndroid Build Coastguard Worker
263*6236dae4SAndroid Build Coastguard Worker flags = 0;
264*6236dae4SAndroid Build Coastguard Worker width = precision = 0;
265*6236dae4SAndroid Build Coastguard Worker
266*6236dae4SAndroid Build Coastguard Worker if(use_dollar != DOLLAR_NOPE) {
267*6236dae4SAndroid Build Coastguard Worker param = dollarstring(fmt, &fmt);
268*6236dae4SAndroid Build Coastguard Worker if(param < 0) {
269*6236dae4SAndroid Build Coastguard Worker if(use_dollar == DOLLAR_USE)
270*6236dae4SAndroid Build Coastguard Worker /* illegal combo */
271*6236dae4SAndroid Build Coastguard Worker return PFMT_DOLLAR;
272*6236dae4SAndroid Build Coastguard Worker
273*6236dae4SAndroid Build Coastguard Worker /* we got no positional, just get the next arg */
274*6236dae4SAndroid Build Coastguard Worker param = -1;
275*6236dae4SAndroid Build Coastguard Worker use_dollar = DOLLAR_NOPE;
276*6236dae4SAndroid Build Coastguard Worker }
277*6236dae4SAndroid Build Coastguard Worker else
278*6236dae4SAndroid Build Coastguard Worker use_dollar = DOLLAR_USE;
279*6236dae4SAndroid Build Coastguard Worker }
280*6236dae4SAndroid Build Coastguard Worker else
281*6236dae4SAndroid Build Coastguard Worker param = -1;
282*6236dae4SAndroid Build Coastguard Worker
283*6236dae4SAndroid Build Coastguard Worker /* Handle the flags */
284*6236dae4SAndroid Build Coastguard Worker while(loopit) {
285*6236dae4SAndroid Build Coastguard Worker switch(*fmt++) {
286*6236dae4SAndroid Build Coastguard Worker case ' ':
287*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_SPACE;
288*6236dae4SAndroid Build Coastguard Worker break;
289*6236dae4SAndroid Build Coastguard Worker case '+':
290*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_SHOWSIGN;
291*6236dae4SAndroid Build Coastguard Worker break;
292*6236dae4SAndroid Build Coastguard Worker case '-':
293*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LEFT;
294*6236dae4SAndroid Build Coastguard Worker flags &= ~(unsigned int)FLAGS_PAD_NIL;
295*6236dae4SAndroid Build Coastguard Worker break;
296*6236dae4SAndroid Build Coastguard Worker case '#':
297*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_ALT;
298*6236dae4SAndroid Build Coastguard Worker break;
299*6236dae4SAndroid Build Coastguard Worker case '.':
300*6236dae4SAndroid Build Coastguard Worker if('*' == *fmt) {
301*6236dae4SAndroid Build Coastguard Worker /* The precision is picked from a specified parameter */
302*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_PRECPARAM;
303*6236dae4SAndroid Build Coastguard Worker fmt++;
304*6236dae4SAndroid Build Coastguard Worker
305*6236dae4SAndroid Build Coastguard Worker if(use_dollar == DOLLAR_USE) {
306*6236dae4SAndroid Build Coastguard Worker precision = dollarstring(fmt, &fmt);
307*6236dae4SAndroid Build Coastguard Worker if(precision < 0)
308*6236dae4SAndroid Build Coastguard Worker /* illegal combo */
309*6236dae4SAndroid Build Coastguard Worker return PFMT_DOLLARPREC;
310*6236dae4SAndroid Build Coastguard Worker }
311*6236dae4SAndroid Build Coastguard Worker else
312*6236dae4SAndroid Build Coastguard Worker /* get it from the next argument */
313*6236dae4SAndroid Build Coastguard Worker precision = -1;
314*6236dae4SAndroid Build Coastguard Worker }
315*6236dae4SAndroid Build Coastguard Worker else {
316*6236dae4SAndroid Build Coastguard Worker bool is_neg = FALSE;
317*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_PREC;
318*6236dae4SAndroid Build Coastguard Worker precision = 0;
319*6236dae4SAndroid Build Coastguard Worker if('-' == *fmt) {
320*6236dae4SAndroid Build Coastguard Worker is_neg = TRUE;
321*6236dae4SAndroid Build Coastguard Worker fmt++;
322*6236dae4SAndroid Build Coastguard Worker }
323*6236dae4SAndroid Build Coastguard Worker while(ISDIGIT(*fmt)) {
324*6236dae4SAndroid Build Coastguard Worker if(precision > INT_MAX/10)
325*6236dae4SAndroid Build Coastguard Worker return PFMT_PREC;
326*6236dae4SAndroid Build Coastguard Worker precision *= 10;
327*6236dae4SAndroid Build Coastguard Worker precision += *fmt - '0';
328*6236dae4SAndroid Build Coastguard Worker fmt++;
329*6236dae4SAndroid Build Coastguard Worker }
330*6236dae4SAndroid Build Coastguard Worker if(is_neg)
331*6236dae4SAndroid Build Coastguard Worker precision = -precision;
332*6236dae4SAndroid Build Coastguard Worker }
333*6236dae4SAndroid Build Coastguard Worker if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) ==
334*6236dae4SAndroid Build Coastguard Worker (FLAGS_PREC | FLAGS_PRECPARAM))
335*6236dae4SAndroid Build Coastguard Worker /* it is not permitted to use both kinds of precision for the same
336*6236dae4SAndroid Build Coastguard Worker argument */
337*6236dae4SAndroid Build Coastguard Worker return PFMT_PRECMIX;
338*6236dae4SAndroid Build Coastguard Worker break;
339*6236dae4SAndroid Build Coastguard Worker case 'h':
340*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_SHORT;
341*6236dae4SAndroid Build Coastguard Worker break;
342*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) || defined(_WIN32_WCE)
343*6236dae4SAndroid Build Coastguard Worker case 'I':
344*6236dae4SAndroid Build Coastguard Worker /* Non-ANSI integer extensions I32 I64 */
345*6236dae4SAndroid Build Coastguard Worker if((fmt[0] == '3') && (fmt[1] == '2')) {
346*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONG;
347*6236dae4SAndroid Build Coastguard Worker fmt += 2;
348*6236dae4SAndroid Build Coastguard Worker }
349*6236dae4SAndroid Build Coastguard Worker else if((fmt[0] == '6') && (fmt[1] == '4')) {
350*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONGLONG;
351*6236dae4SAndroid Build Coastguard Worker fmt += 2;
352*6236dae4SAndroid Build Coastguard Worker }
353*6236dae4SAndroid Build Coastguard Worker else {
354*6236dae4SAndroid Build Coastguard Worker #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
355*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONGLONG;
356*6236dae4SAndroid Build Coastguard Worker #else
357*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONG;
358*6236dae4SAndroid Build Coastguard Worker #endif
359*6236dae4SAndroid Build Coastguard Worker }
360*6236dae4SAndroid Build Coastguard Worker break;
361*6236dae4SAndroid Build Coastguard Worker #endif /* _WIN32 || _WIN32_WCE */
362*6236dae4SAndroid Build Coastguard Worker case 'l':
363*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONG)
364*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONGLONG;
365*6236dae4SAndroid Build Coastguard Worker else
366*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONG;
367*6236dae4SAndroid Build Coastguard Worker break;
368*6236dae4SAndroid Build Coastguard Worker case 'L':
369*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONGDOUBLE;
370*6236dae4SAndroid Build Coastguard Worker break;
371*6236dae4SAndroid Build Coastguard Worker case 'q':
372*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONGLONG;
373*6236dae4SAndroid Build Coastguard Worker break;
374*6236dae4SAndroid Build Coastguard Worker case 'z':
375*6236dae4SAndroid Build Coastguard Worker /* the code below generates a warning if -Wunreachable-code is
376*6236dae4SAndroid Build Coastguard Worker used */
377*6236dae4SAndroid Build Coastguard Worker #if (SIZEOF_SIZE_T > SIZEOF_LONG)
378*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONGLONG;
379*6236dae4SAndroid Build Coastguard Worker #else
380*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONG;
381*6236dae4SAndroid Build Coastguard Worker #endif
382*6236dae4SAndroid Build Coastguard Worker break;
383*6236dae4SAndroid Build Coastguard Worker case 'O':
384*6236dae4SAndroid Build Coastguard Worker #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
385*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONGLONG;
386*6236dae4SAndroid Build Coastguard Worker #else
387*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LONG;
388*6236dae4SAndroid Build Coastguard Worker #endif
389*6236dae4SAndroid Build Coastguard Worker break;
390*6236dae4SAndroid Build Coastguard Worker case '0':
391*6236dae4SAndroid Build Coastguard Worker if(!(flags & FLAGS_LEFT))
392*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_PAD_NIL;
393*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
394*6236dae4SAndroid Build Coastguard Worker case '1': case '2': case '3': case '4':
395*6236dae4SAndroid Build Coastguard Worker case '5': case '6': case '7': case '8': case '9':
396*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_WIDTH;
397*6236dae4SAndroid Build Coastguard Worker width = 0;
398*6236dae4SAndroid Build Coastguard Worker fmt--;
399*6236dae4SAndroid Build Coastguard Worker do {
400*6236dae4SAndroid Build Coastguard Worker if(width > INT_MAX/10)
401*6236dae4SAndroid Build Coastguard Worker return PFMT_WIDTH;
402*6236dae4SAndroid Build Coastguard Worker width *= 10;
403*6236dae4SAndroid Build Coastguard Worker width += *fmt - '0';
404*6236dae4SAndroid Build Coastguard Worker fmt++;
405*6236dae4SAndroid Build Coastguard Worker } while(ISDIGIT(*fmt));
406*6236dae4SAndroid Build Coastguard Worker break;
407*6236dae4SAndroid Build Coastguard Worker case '*': /* read width from argument list */
408*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_WIDTHPARAM;
409*6236dae4SAndroid Build Coastguard Worker if(use_dollar == DOLLAR_USE) {
410*6236dae4SAndroid Build Coastguard Worker width = dollarstring(fmt, &fmt);
411*6236dae4SAndroid Build Coastguard Worker if(width < 0)
412*6236dae4SAndroid Build Coastguard Worker /* illegal combo */
413*6236dae4SAndroid Build Coastguard Worker return PFMT_DOLLARWIDTH;
414*6236dae4SAndroid Build Coastguard Worker }
415*6236dae4SAndroid Build Coastguard Worker else
416*6236dae4SAndroid Build Coastguard Worker /* pick from the next argument */
417*6236dae4SAndroid Build Coastguard Worker width = -1;
418*6236dae4SAndroid Build Coastguard Worker break;
419*6236dae4SAndroid Build Coastguard Worker default:
420*6236dae4SAndroid Build Coastguard Worker loopit = FALSE;
421*6236dae4SAndroid Build Coastguard Worker fmt--;
422*6236dae4SAndroid Build Coastguard Worker break;
423*6236dae4SAndroid Build Coastguard Worker } /* switch */
424*6236dae4SAndroid Build Coastguard Worker } /* while */
425*6236dae4SAndroid Build Coastguard Worker
426*6236dae4SAndroid Build Coastguard Worker switch(*fmt) {
427*6236dae4SAndroid Build Coastguard Worker case 'S':
428*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_ALT;
429*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
430*6236dae4SAndroid Build Coastguard Worker case 's':
431*6236dae4SAndroid Build Coastguard Worker type = FORMAT_STRING;
432*6236dae4SAndroid Build Coastguard Worker break;
433*6236dae4SAndroid Build Coastguard Worker case 'n':
434*6236dae4SAndroid Build Coastguard Worker type = FORMAT_INTPTR;
435*6236dae4SAndroid Build Coastguard Worker break;
436*6236dae4SAndroid Build Coastguard Worker case 'p':
437*6236dae4SAndroid Build Coastguard Worker type = FORMAT_PTR;
438*6236dae4SAndroid Build Coastguard Worker break;
439*6236dae4SAndroid Build Coastguard Worker case 'd':
440*6236dae4SAndroid Build Coastguard Worker case 'i':
441*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONGLONG)
442*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGLONG;
443*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_LONG)
444*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONG;
445*6236dae4SAndroid Build Coastguard Worker else
446*6236dae4SAndroid Build Coastguard Worker type = FORMAT_INT;
447*6236dae4SAndroid Build Coastguard Worker break;
448*6236dae4SAndroid Build Coastguard Worker case 'u':
449*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONGLONG)
450*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGLONGU;
451*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_LONG)
452*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGU;
453*6236dae4SAndroid Build Coastguard Worker else
454*6236dae4SAndroid Build Coastguard Worker type = FORMAT_INTU;
455*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_UNSIGNED;
456*6236dae4SAndroid Build Coastguard Worker break;
457*6236dae4SAndroid Build Coastguard Worker case 'o':
458*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONGLONG)
459*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGLONGU;
460*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_LONG)
461*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGU;
462*6236dae4SAndroid Build Coastguard Worker else
463*6236dae4SAndroid Build Coastguard Worker type = FORMAT_INTU;
464*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_OCTAL|FLAGS_UNSIGNED;
465*6236dae4SAndroid Build Coastguard Worker break;
466*6236dae4SAndroid Build Coastguard Worker case 'x':
467*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONGLONG)
468*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGLONGU;
469*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_LONG)
470*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGU;
471*6236dae4SAndroid Build Coastguard Worker else
472*6236dae4SAndroid Build Coastguard Worker type = FORMAT_INTU;
473*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_HEX|FLAGS_UNSIGNED;
474*6236dae4SAndroid Build Coastguard Worker break;
475*6236dae4SAndroid Build Coastguard Worker case 'X':
476*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONGLONG)
477*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGLONGU;
478*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_LONG)
479*6236dae4SAndroid Build Coastguard Worker type = FORMAT_LONGU;
480*6236dae4SAndroid Build Coastguard Worker else
481*6236dae4SAndroid Build Coastguard Worker type = FORMAT_INTU;
482*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
483*6236dae4SAndroid Build Coastguard Worker break;
484*6236dae4SAndroid Build Coastguard Worker case 'c':
485*6236dae4SAndroid Build Coastguard Worker type = FORMAT_INT;
486*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_CHAR;
487*6236dae4SAndroid Build Coastguard Worker break;
488*6236dae4SAndroid Build Coastguard Worker case 'f':
489*6236dae4SAndroid Build Coastguard Worker type = FORMAT_DOUBLE;
490*6236dae4SAndroid Build Coastguard Worker break;
491*6236dae4SAndroid Build Coastguard Worker case 'e':
492*6236dae4SAndroid Build Coastguard Worker type = FORMAT_DOUBLE;
493*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_FLOATE;
494*6236dae4SAndroid Build Coastguard Worker break;
495*6236dae4SAndroid Build Coastguard Worker case 'E':
496*6236dae4SAndroid Build Coastguard Worker type = FORMAT_DOUBLE;
497*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_FLOATE|FLAGS_UPPER;
498*6236dae4SAndroid Build Coastguard Worker break;
499*6236dae4SAndroid Build Coastguard Worker case 'g':
500*6236dae4SAndroid Build Coastguard Worker type = FORMAT_DOUBLE;
501*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_FLOATG;
502*6236dae4SAndroid Build Coastguard Worker break;
503*6236dae4SAndroid Build Coastguard Worker case 'G':
504*6236dae4SAndroid Build Coastguard Worker type = FORMAT_DOUBLE;
505*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_FLOATG|FLAGS_UPPER;
506*6236dae4SAndroid Build Coastguard Worker break;
507*6236dae4SAndroid Build Coastguard Worker default:
508*6236dae4SAndroid Build Coastguard Worker /* invalid instruction, disregard and continue */
509*6236dae4SAndroid Build Coastguard Worker continue;
510*6236dae4SAndroid Build Coastguard Worker } /* switch */
511*6236dae4SAndroid Build Coastguard Worker
512*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_WIDTHPARAM) {
513*6236dae4SAndroid Build Coastguard Worker if(width < 0)
514*6236dae4SAndroid Build Coastguard Worker width = param_num++;
515*6236dae4SAndroid Build Coastguard Worker else {
516*6236dae4SAndroid Build Coastguard Worker /* if this identifies a parameter already used, this
517*6236dae4SAndroid Build Coastguard Worker is illegal */
518*6236dae4SAndroid Build Coastguard Worker if(usedinput[width/8] & (1 << (width&7)))
519*6236dae4SAndroid Build Coastguard Worker return PFMT_WIDTHARG;
520*6236dae4SAndroid Build Coastguard Worker }
521*6236dae4SAndroid Build Coastguard Worker if(width >= MAX_PARAMETERS)
522*6236dae4SAndroid Build Coastguard Worker return PFMT_MANYARGS;
523*6236dae4SAndroid Build Coastguard Worker if(width >= max_param)
524*6236dae4SAndroid Build Coastguard Worker max_param = width;
525*6236dae4SAndroid Build Coastguard Worker
526*6236dae4SAndroid Build Coastguard Worker in[width].type = FORMAT_WIDTH;
527*6236dae4SAndroid Build Coastguard Worker /* mark as used */
528*6236dae4SAndroid Build Coastguard Worker usedinput[width/8] |= (unsigned char)(1 << (width&7));
529*6236dae4SAndroid Build Coastguard Worker }
530*6236dae4SAndroid Build Coastguard Worker
531*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_PRECPARAM) {
532*6236dae4SAndroid Build Coastguard Worker if(precision < 0)
533*6236dae4SAndroid Build Coastguard Worker precision = param_num++;
534*6236dae4SAndroid Build Coastguard Worker else {
535*6236dae4SAndroid Build Coastguard Worker /* if this identifies a parameter already used, this
536*6236dae4SAndroid Build Coastguard Worker is illegal */
537*6236dae4SAndroid Build Coastguard Worker if(usedinput[precision/8] & (1 << (precision&7)))
538*6236dae4SAndroid Build Coastguard Worker return PFMT_PRECARG;
539*6236dae4SAndroid Build Coastguard Worker }
540*6236dae4SAndroid Build Coastguard Worker if(precision >= MAX_PARAMETERS)
541*6236dae4SAndroid Build Coastguard Worker return PFMT_MANYARGS;
542*6236dae4SAndroid Build Coastguard Worker if(precision >= max_param)
543*6236dae4SAndroid Build Coastguard Worker max_param = precision;
544*6236dae4SAndroid Build Coastguard Worker
545*6236dae4SAndroid Build Coastguard Worker in[precision].type = FORMAT_PRECISION;
546*6236dae4SAndroid Build Coastguard Worker usedinput[precision/8] |= (unsigned char)(1 << (precision&7));
547*6236dae4SAndroid Build Coastguard Worker }
548*6236dae4SAndroid Build Coastguard Worker
549*6236dae4SAndroid Build Coastguard Worker /* Handle the specifier */
550*6236dae4SAndroid Build Coastguard Worker if(param < 0)
551*6236dae4SAndroid Build Coastguard Worker param = param_num++;
552*6236dae4SAndroid Build Coastguard Worker if(param >= MAX_PARAMETERS)
553*6236dae4SAndroid Build Coastguard Worker return PFMT_MANYARGS;
554*6236dae4SAndroid Build Coastguard Worker if(param >= max_param)
555*6236dae4SAndroid Build Coastguard Worker max_param = param;
556*6236dae4SAndroid Build Coastguard Worker
557*6236dae4SAndroid Build Coastguard Worker iptr = &in[param];
558*6236dae4SAndroid Build Coastguard Worker iptr->type = type;
559*6236dae4SAndroid Build Coastguard Worker
560*6236dae4SAndroid Build Coastguard Worker /* mark this input as used */
561*6236dae4SAndroid Build Coastguard Worker usedinput[param/8] |= (unsigned char)(1 << (param&7));
562*6236dae4SAndroid Build Coastguard Worker
563*6236dae4SAndroid Build Coastguard Worker fmt++;
564*6236dae4SAndroid Build Coastguard Worker optr = &out[ocount++];
565*6236dae4SAndroid Build Coastguard Worker if(ocount > MAX_SEGMENTS)
566*6236dae4SAndroid Build Coastguard Worker return PFMT_MANYSEGS;
567*6236dae4SAndroid Build Coastguard Worker optr->input = (unsigned int)param;
568*6236dae4SAndroid Build Coastguard Worker optr->flags = flags;
569*6236dae4SAndroid Build Coastguard Worker optr->width = width;
570*6236dae4SAndroid Build Coastguard Worker optr->precision = precision;
571*6236dae4SAndroid Build Coastguard Worker optr->start = start;
572*6236dae4SAndroid Build Coastguard Worker optr->outlen = outlen;
573*6236dae4SAndroid Build Coastguard Worker start = fmt;
574*6236dae4SAndroid Build Coastguard Worker }
575*6236dae4SAndroid Build Coastguard Worker else
576*6236dae4SAndroid Build Coastguard Worker fmt++;
577*6236dae4SAndroid Build Coastguard Worker }
578*6236dae4SAndroid Build Coastguard Worker
579*6236dae4SAndroid Build Coastguard Worker /* is there a trailing piece */
580*6236dae4SAndroid Build Coastguard Worker outlen = (size_t)(fmt - start);
581*6236dae4SAndroid Build Coastguard Worker if(outlen) {
582*6236dae4SAndroid Build Coastguard Worker optr = &out[ocount++];
583*6236dae4SAndroid Build Coastguard Worker if(ocount > MAX_SEGMENTS)
584*6236dae4SAndroid Build Coastguard Worker return PFMT_MANYSEGS;
585*6236dae4SAndroid Build Coastguard Worker optr->input = 0;
586*6236dae4SAndroid Build Coastguard Worker optr->flags = FLAGS_SUBSTR;
587*6236dae4SAndroid Build Coastguard Worker optr->start = start;
588*6236dae4SAndroid Build Coastguard Worker optr->outlen = outlen;
589*6236dae4SAndroid Build Coastguard Worker }
590*6236dae4SAndroid Build Coastguard Worker
591*6236dae4SAndroid Build Coastguard Worker /* Read the arg list parameters into our data list */
592*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < max_param + 1; i++) {
593*6236dae4SAndroid Build Coastguard Worker struct va_input *iptr = &in[i];
594*6236dae4SAndroid Build Coastguard Worker if(!(usedinput[i/8] & (1 << (i&7))))
595*6236dae4SAndroid Build Coastguard Worker /* bad input */
596*6236dae4SAndroid Build Coastguard Worker return PFMT_INPUTGAP;
597*6236dae4SAndroid Build Coastguard Worker
598*6236dae4SAndroid Build Coastguard Worker /* based on the type, read the correct argument */
599*6236dae4SAndroid Build Coastguard Worker switch(iptr->type) {
600*6236dae4SAndroid Build Coastguard Worker case FORMAT_STRING:
601*6236dae4SAndroid Build Coastguard Worker iptr->val.str = va_arg(arglist, char *);
602*6236dae4SAndroid Build Coastguard Worker break;
603*6236dae4SAndroid Build Coastguard Worker
604*6236dae4SAndroid Build Coastguard Worker case FORMAT_INTPTR:
605*6236dae4SAndroid Build Coastguard Worker case FORMAT_PTR:
606*6236dae4SAndroid Build Coastguard Worker iptr->val.ptr = va_arg(arglist, void *);
607*6236dae4SAndroid Build Coastguard Worker break;
608*6236dae4SAndroid Build Coastguard Worker
609*6236dae4SAndroid Build Coastguard Worker case FORMAT_LONGLONGU:
610*6236dae4SAndroid Build Coastguard Worker iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
611*6236dae4SAndroid Build Coastguard Worker break;
612*6236dae4SAndroid Build Coastguard Worker
613*6236dae4SAndroid Build Coastguard Worker case FORMAT_LONGLONG:
614*6236dae4SAndroid Build Coastguard Worker iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t);
615*6236dae4SAndroid Build Coastguard Worker break;
616*6236dae4SAndroid Build Coastguard Worker
617*6236dae4SAndroid Build Coastguard Worker case FORMAT_LONGU:
618*6236dae4SAndroid Build Coastguard Worker iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long);
619*6236dae4SAndroid Build Coastguard Worker break;
620*6236dae4SAndroid Build Coastguard Worker
621*6236dae4SAndroid Build Coastguard Worker case FORMAT_LONG:
622*6236dae4SAndroid Build Coastguard Worker iptr->val.nums = (mp_intmax_t)va_arg(arglist, long);
623*6236dae4SAndroid Build Coastguard Worker break;
624*6236dae4SAndroid Build Coastguard Worker
625*6236dae4SAndroid Build Coastguard Worker case FORMAT_INTU:
626*6236dae4SAndroid Build Coastguard Worker iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int);
627*6236dae4SAndroid Build Coastguard Worker break;
628*6236dae4SAndroid Build Coastguard Worker
629*6236dae4SAndroid Build Coastguard Worker case FORMAT_INT:
630*6236dae4SAndroid Build Coastguard Worker case FORMAT_WIDTH:
631*6236dae4SAndroid Build Coastguard Worker case FORMAT_PRECISION:
632*6236dae4SAndroid Build Coastguard Worker iptr->val.nums = (mp_intmax_t)va_arg(arglist, int);
633*6236dae4SAndroid Build Coastguard Worker break;
634*6236dae4SAndroid Build Coastguard Worker
635*6236dae4SAndroid Build Coastguard Worker case FORMAT_DOUBLE:
636*6236dae4SAndroid Build Coastguard Worker iptr->val.dnum = va_arg(arglist, double);
637*6236dae4SAndroid Build Coastguard Worker break;
638*6236dae4SAndroid Build Coastguard Worker
639*6236dae4SAndroid Build Coastguard Worker default:
640*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(NULL); /* unexpected */
641*6236dae4SAndroid Build Coastguard Worker break;
642*6236dae4SAndroid Build Coastguard Worker }
643*6236dae4SAndroid Build Coastguard Worker }
644*6236dae4SAndroid Build Coastguard Worker *ipieces = max_param + 1;
645*6236dae4SAndroid Build Coastguard Worker *opieces = ocount;
646*6236dae4SAndroid Build Coastguard Worker
647*6236dae4SAndroid Build Coastguard Worker return PFMT_OK;
648*6236dae4SAndroid Build Coastguard Worker }
649*6236dae4SAndroid Build Coastguard Worker
650*6236dae4SAndroid Build Coastguard Worker /*
651*6236dae4SAndroid Build Coastguard Worker * formatf() - the general printf function.
652*6236dae4SAndroid Build Coastguard Worker *
653*6236dae4SAndroid Build Coastguard Worker * It calls parsefmt() to parse the format string. It populates two arrays;
654*6236dae4SAndroid Build Coastguard Worker * one that describes the input arguments and one that describes a number of
655*6236dae4SAndroid Build Coastguard Worker * output segments.
656*6236dae4SAndroid Build Coastguard Worker *
657*6236dae4SAndroid Build Coastguard Worker * On success, the input array describes the type of all arguments and their
658*6236dae4SAndroid Build Coastguard Worker * values.
659*6236dae4SAndroid Build Coastguard Worker *
660*6236dae4SAndroid Build Coastguard Worker * The function then iterates over the output segments and outputs them one
661*6236dae4SAndroid Build Coastguard Worker * by one until done. Using the appropriate input arguments (if any).
662*6236dae4SAndroid Build Coastguard Worker *
663*6236dae4SAndroid Build Coastguard Worker * All output is sent to the 'stream()' callback, one byte at a time.
664*6236dae4SAndroid Build Coastguard Worker */
665*6236dae4SAndroid Build Coastguard Worker
formatf(void * userp,int (* stream)(unsigned char,void *),const char * format,va_list ap_save)666*6236dae4SAndroid Build Coastguard Worker static int formatf(
667*6236dae4SAndroid Build Coastguard Worker void *userp, /* untouched by format(), just sent to the stream() function in
668*6236dae4SAndroid Build Coastguard Worker the second argument */
669*6236dae4SAndroid Build Coastguard Worker /* function pointer called for each output character */
670*6236dae4SAndroid Build Coastguard Worker int (*stream)(unsigned char, void *),
671*6236dae4SAndroid Build Coastguard Worker const char *format, /* %-formatted string */
672*6236dae4SAndroid Build Coastguard Worker va_list ap_save) /* list of parameters */
673*6236dae4SAndroid Build Coastguard Worker {
674*6236dae4SAndroid Build Coastguard Worker static const char nilstr[] = "(nil)";
675*6236dae4SAndroid Build Coastguard Worker const char *digits = lower_digits; /* Base-36 digits for numbers. */
676*6236dae4SAndroid Build Coastguard Worker int done = 0; /* number of characters written */
677*6236dae4SAndroid Build Coastguard Worker int i;
678*6236dae4SAndroid Build Coastguard Worker int ocount = 0; /* number of output segments */
679*6236dae4SAndroid Build Coastguard Worker int icount = 0; /* number of input arguments */
680*6236dae4SAndroid Build Coastguard Worker
681*6236dae4SAndroid Build Coastguard Worker struct outsegment output[MAX_SEGMENTS];
682*6236dae4SAndroid Build Coastguard Worker struct va_input input[MAX_PARAMETERS];
683*6236dae4SAndroid Build Coastguard Worker char work[BUFFSIZE];
684*6236dae4SAndroid Build Coastguard Worker
685*6236dae4SAndroid Build Coastguard Worker /* 'workend' points to the final buffer byte position, but with an extra
686*6236dae4SAndroid Build Coastguard Worker byte as margin to avoid the (FALSE?) warning Coverity gives us
687*6236dae4SAndroid Build Coastguard Worker otherwise */
688*6236dae4SAndroid Build Coastguard Worker char *workend = &work[sizeof(work) - 2];
689*6236dae4SAndroid Build Coastguard Worker
690*6236dae4SAndroid Build Coastguard Worker /* Parse the format string */
691*6236dae4SAndroid Build Coastguard Worker if(parsefmt(format, output, input, &ocount, &icount, ap_save))
692*6236dae4SAndroid Build Coastguard Worker return 0;
693*6236dae4SAndroid Build Coastguard Worker
694*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < ocount; i++) {
695*6236dae4SAndroid Build Coastguard Worker struct outsegment *optr = &output[i];
696*6236dae4SAndroid Build Coastguard Worker struct va_input *iptr;
697*6236dae4SAndroid Build Coastguard Worker bool is_alt; /* Format spec modifiers. */
698*6236dae4SAndroid Build Coastguard Worker int width; /* Width of a field. */
699*6236dae4SAndroid Build Coastguard Worker int prec; /* Precision of a field. */
700*6236dae4SAndroid Build Coastguard Worker bool is_neg; /* Decimal integer is negative. */
701*6236dae4SAndroid Build Coastguard Worker unsigned long base; /* Base of a number to be written. */
702*6236dae4SAndroid Build Coastguard Worker mp_uintmax_t num; /* Integral values to be written. */
703*6236dae4SAndroid Build Coastguard Worker mp_intmax_t signed_num; /* Used to convert negative in positive. */
704*6236dae4SAndroid Build Coastguard Worker char *w;
705*6236dae4SAndroid Build Coastguard Worker size_t outlen = optr->outlen;
706*6236dae4SAndroid Build Coastguard Worker unsigned int flags = optr->flags;
707*6236dae4SAndroid Build Coastguard Worker
708*6236dae4SAndroid Build Coastguard Worker if(outlen) {
709*6236dae4SAndroid Build Coastguard Worker char *str = optr->start;
710*6236dae4SAndroid Build Coastguard Worker for(; outlen && *str; outlen--)
711*6236dae4SAndroid Build Coastguard Worker OUTCHAR(*str++);
712*6236dae4SAndroid Build Coastguard Worker if(optr->flags & FLAGS_SUBSTR)
713*6236dae4SAndroid Build Coastguard Worker /* this is just a substring */
714*6236dae4SAndroid Build Coastguard Worker continue;
715*6236dae4SAndroid Build Coastguard Worker }
716*6236dae4SAndroid Build Coastguard Worker
717*6236dae4SAndroid Build Coastguard Worker /* pick up the specified width */
718*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_WIDTHPARAM) {
719*6236dae4SAndroid Build Coastguard Worker width = (int)input[optr->width].val.nums;
720*6236dae4SAndroid Build Coastguard Worker if(width < 0) {
721*6236dae4SAndroid Build Coastguard Worker /* "A negative field width is taken as a '-' flag followed by a
722*6236dae4SAndroid Build Coastguard Worker positive field width." */
723*6236dae4SAndroid Build Coastguard Worker if(width == INT_MIN)
724*6236dae4SAndroid Build Coastguard Worker width = INT_MAX;
725*6236dae4SAndroid Build Coastguard Worker else
726*6236dae4SAndroid Build Coastguard Worker width = -width;
727*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_LEFT;
728*6236dae4SAndroid Build Coastguard Worker flags &= ~(unsigned int)FLAGS_PAD_NIL;
729*6236dae4SAndroid Build Coastguard Worker }
730*6236dae4SAndroid Build Coastguard Worker }
731*6236dae4SAndroid Build Coastguard Worker else
732*6236dae4SAndroid Build Coastguard Worker width = optr->width;
733*6236dae4SAndroid Build Coastguard Worker
734*6236dae4SAndroid Build Coastguard Worker /* pick up the specified precision */
735*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_PRECPARAM) {
736*6236dae4SAndroid Build Coastguard Worker prec = (int)input[optr->precision].val.nums;
737*6236dae4SAndroid Build Coastguard Worker if(prec < 0)
738*6236dae4SAndroid Build Coastguard Worker /* "A negative precision is taken as if the precision were
739*6236dae4SAndroid Build Coastguard Worker omitted." */
740*6236dae4SAndroid Build Coastguard Worker prec = -1;
741*6236dae4SAndroid Build Coastguard Worker }
742*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_PREC)
743*6236dae4SAndroid Build Coastguard Worker prec = optr->precision;
744*6236dae4SAndroid Build Coastguard Worker else
745*6236dae4SAndroid Build Coastguard Worker prec = -1;
746*6236dae4SAndroid Build Coastguard Worker
747*6236dae4SAndroid Build Coastguard Worker is_alt = (flags & FLAGS_ALT) ? 1 : 0;
748*6236dae4SAndroid Build Coastguard Worker iptr = &input[optr->input];
749*6236dae4SAndroid Build Coastguard Worker
750*6236dae4SAndroid Build Coastguard Worker switch(iptr->type) {
751*6236dae4SAndroid Build Coastguard Worker case FORMAT_INTU:
752*6236dae4SAndroid Build Coastguard Worker case FORMAT_LONGU:
753*6236dae4SAndroid Build Coastguard Worker case FORMAT_LONGLONGU:
754*6236dae4SAndroid Build Coastguard Worker flags |= FLAGS_UNSIGNED;
755*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
756*6236dae4SAndroid Build Coastguard Worker case FORMAT_INT:
757*6236dae4SAndroid Build Coastguard Worker case FORMAT_LONG:
758*6236dae4SAndroid Build Coastguard Worker case FORMAT_LONGLONG:
759*6236dae4SAndroid Build Coastguard Worker num = iptr->val.numu;
760*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_CHAR) {
761*6236dae4SAndroid Build Coastguard Worker /* Character. */
762*6236dae4SAndroid Build Coastguard Worker if(!(flags & FLAGS_LEFT))
763*6236dae4SAndroid Build Coastguard Worker while(--width > 0)
764*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
765*6236dae4SAndroid Build Coastguard Worker OUTCHAR((char) num);
766*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LEFT)
767*6236dae4SAndroid Build Coastguard Worker while(--width > 0)
768*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
769*6236dae4SAndroid Build Coastguard Worker break;
770*6236dae4SAndroid Build Coastguard Worker }
771*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_OCTAL) {
772*6236dae4SAndroid Build Coastguard Worker /* Octal unsigned integer */
773*6236dae4SAndroid Build Coastguard Worker base = 8;
774*6236dae4SAndroid Build Coastguard Worker is_neg = FALSE;
775*6236dae4SAndroid Build Coastguard Worker }
776*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_HEX) {
777*6236dae4SAndroid Build Coastguard Worker /* Hexadecimal unsigned integer */
778*6236dae4SAndroid Build Coastguard Worker digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
779*6236dae4SAndroid Build Coastguard Worker base = 16;
780*6236dae4SAndroid Build Coastguard Worker is_neg = FALSE;
781*6236dae4SAndroid Build Coastguard Worker }
782*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_UNSIGNED) {
783*6236dae4SAndroid Build Coastguard Worker /* Decimal unsigned integer */
784*6236dae4SAndroid Build Coastguard Worker base = 10;
785*6236dae4SAndroid Build Coastguard Worker is_neg = FALSE;
786*6236dae4SAndroid Build Coastguard Worker }
787*6236dae4SAndroid Build Coastguard Worker else {
788*6236dae4SAndroid Build Coastguard Worker /* Decimal integer. */
789*6236dae4SAndroid Build Coastguard Worker base = 10;
790*6236dae4SAndroid Build Coastguard Worker
791*6236dae4SAndroid Build Coastguard Worker is_neg = (iptr->val.nums < (mp_intmax_t)0);
792*6236dae4SAndroid Build Coastguard Worker if(is_neg) {
793*6236dae4SAndroid Build Coastguard Worker /* signed_num might fail to hold absolute negative minimum by 1 */
794*6236dae4SAndroid Build Coastguard Worker signed_num = iptr->val.nums + (mp_intmax_t)1;
795*6236dae4SAndroid Build Coastguard Worker signed_num = -signed_num;
796*6236dae4SAndroid Build Coastguard Worker num = (mp_uintmax_t)signed_num;
797*6236dae4SAndroid Build Coastguard Worker num += (mp_uintmax_t)1;
798*6236dae4SAndroid Build Coastguard Worker }
799*6236dae4SAndroid Build Coastguard Worker }
800*6236dae4SAndroid Build Coastguard Worker number:
801*6236dae4SAndroid Build Coastguard Worker /* Supply a default precision if none was given. */
802*6236dae4SAndroid Build Coastguard Worker if(prec == -1)
803*6236dae4SAndroid Build Coastguard Worker prec = 1;
804*6236dae4SAndroid Build Coastguard Worker
805*6236dae4SAndroid Build Coastguard Worker /* Put the number in WORK. */
806*6236dae4SAndroid Build Coastguard Worker w = workend;
807*6236dae4SAndroid Build Coastguard Worker switch(base) {
808*6236dae4SAndroid Build Coastguard Worker case 10:
809*6236dae4SAndroid Build Coastguard Worker while(num > 0) {
810*6236dae4SAndroid Build Coastguard Worker *w-- = (char)('0' + (num % 10));
811*6236dae4SAndroid Build Coastguard Worker num /= 10;
812*6236dae4SAndroid Build Coastguard Worker }
813*6236dae4SAndroid Build Coastguard Worker break;
814*6236dae4SAndroid Build Coastguard Worker default:
815*6236dae4SAndroid Build Coastguard Worker while(num > 0) {
816*6236dae4SAndroid Build Coastguard Worker *w-- = digits[num % base];
817*6236dae4SAndroid Build Coastguard Worker num /= base;
818*6236dae4SAndroid Build Coastguard Worker }
819*6236dae4SAndroid Build Coastguard Worker break;
820*6236dae4SAndroid Build Coastguard Worker }
821*6236dae4SAndroid Build Coastguard Worker width -= (int)(workend - w);
822*6236dae4SAndroid Build Coastguard Worker prec -= (int)(workend - w);
823*6236dae4SAndroid Build Coastguard Worker
824*6236dae4SAndroid Build Coastguard Worker if(is_alt && base == 8 && prec <= 0) {
825*6236dae4SAndroid Build Coastguard Worker *w-- = '0';
826*6236dae4SAndroid Build Coastguard Worker --width;
827*6236dae4SAndroid Build Coastguard Worker }
828*6236dae4SAndroid Build Coastguard Worker
829*6236dae4SAndroid Build Coastguard Worker if(prec > 0) {
830*6236dae4SAndroid Build Coastguard Worker width -= prec;
831*6236dae4SAndroid Build Coastguard Worker while(prec-- > 0 && w >= work)
832*6236dae4SAndroid Build Coastguard Worker *w-- = '0';
833*6236dae4SAndroid Build Coastguard Worker }
834*6236dae4SAndroid Build Coastguard Worker
835*6236dae4SAndroid Build Coastguard Worker if(is_alt && base == 16)
836*6236dae4SAndroid Build Coastguard Worker width -= 2;
837*6236dae4SAndroid Build Coastguard Worker
838*6236dae4SAndroid Build Coastguard Worker if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
839*6236dae4SAndroid Build Coastguard Worker --width;
840*6236dae4SAndroid Build Coastguard Worker
841*6236dae4SAndroid Build Coastguard Worker if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL))
842*6236dae4SAndroid Build Coastguard Worker while(width-- > 0)
843*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
844*6236dae4SAndroid Build Coastguard Worker
845*6236dae4SAndroid Build Coastguard Worker if(is_neg)
846*6236dae4SAndroid Build Coastguard Worker OUTCHAR('-');
847*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_SHOWSIGN)
848*6236dae4SAndroid Build Coastguard Worker OUTCHAR('+');
849*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_SPACE)
850*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
851*6236dae4SAndroid Build Coastguard Worker
852*6236dae4SAndroid Build Coastguard Worker if(is_alt && base == 16) {
853*6236dae4SAndroid Build Coastguard Worker OUTCHAR('0');
854*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_UPPER)
855*6236dae4SAndroid Build Coastguard Worker OUTCHAR('X');
856*6236dae4SAndroid Build Coastguard Worker else
857*6236dae4SAndroid Build Coastguard Worker OUTCHAR('x');
858*6236dae4SAndroid Build Coastguard Worker }
859*6236dae4SAndroid Build Coastguard Worker
860*6236dae4SAndroid Build Coastguard Worker if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL))
861*6236dae4SAndroid Build Coastguard Worker while(width-- > 0)
862*6236dae4SAndroid Build Coastguard Worker OUTCHAR('0');
863*6236dae4SAndroid Build Coastguard Worker
864*6236dae4SAndroid Build Coastguard Worker /* Write the number. */
865*6236dae4SAndroid Build Coastguard Worker while(++w <= workend) {
866*6236dae4SAndroid Build Coastguard Worker OUTCHAR(*w);
867*6236dae4SAndroid Build Coastguard Worker }
868*6236dae4SAndroid Build Coastguard Worker
869*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LEFT)
870*6236dae4SAndroid Build Coastguard Worker while(width-- > 0)
871*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
872*6236dae4SAndroid Build Coastguard Worker break;
873*6236dae4SAndroid Build Coastguard Worker
874*6236dae4SAndroid Build Coastguard Worker case FORMAT_STRING: {
875*6236dae4SAndroid Build Coastguard Worker const char *str;
876*6236dae4SAndroid Build Coastguard Worker size_t len;
877*6236dae4SAndroid Build Coastguard Worker
878*6236dae4SAndroid Build Coastguard Worker str = (char *)iptr->val.str;
879*6236dae4SAndroid Build Coastguard Worker if(!str) {
880*6236dae4SAndroid Build Coastguard Worker /* Write null string if there is space. */
881*6236dae4SAndroid Build Coastguard Worker if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
882*6236dae4SAndroid Build Coastguard Worker str = nilstr;
883*6236dae4SAndroid Build Coastguard Worker len = sizeof(nilstr) - 1;
884*6236dae4SAndroid Build Coastguard Worker /* Disable quotes around (nil) */
885*6236dae4SAndroid Build Coastguard Worker flags &= ~(unsigned int)FLAGS_ALT;
886*6236dae4SAndroid Build Coastguard Worker }
887*6236dae4SAndroid Build Coastguard Worker else {
888*6236dae4SAndroid Build Coastguard Worker str = "";
889*6236dae4SAndroid Build Coastguard Worker len = 0;
890*6236dae4SAndroid Build Coastguard Worker }
891*6236dae4SAndroid Build Coastguard Worker }
892*6236dae4SAndroid Build Coastguard Worker else if(prec != -1)
893*6236dae4SAndroid Build Coastguard Worker len = (size_t)prec;
894*6236dae4SAndroid Build Coastguard Worker else if(*str == '\0')
895*6236dae4SAndroid Build Coastguard Worker len = 0;
896*6236dae4SAndroid Build Coastguard Worker else
897*6236dae4SAndroid Build Coastguard Worker len = strlen(str);
898*6236dae4SAndroid Build Coastguard Worker
899*6236dae4SAndroid Build Coastguard Worker width -= (len > INT_MAX) ? INT_MAX : (int)len;
900*6236dae4SAndroid Build Coastguard Worker
901*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_ALT)
902*6236dae4SAndroid Build Coastguard Worker OUTCHAR('"');
903*6236dae4SAndroid Build Coastguard Worker
904*6236dae4SAndroid Build Coastguard Worker if(!(flags & FLAGS_LEFT))
905*6236dae4SAndroid Build Coastguard Worker while(width-- > 0)
906*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
907*6236dae4SAndroid Build Coastguard Worker
908*6236dae4SAndroid Build Coastguard Worker for(; len && *str; len--)
909*6236dae4SAndroid Build Coastguard Worker OUTCHAR(*str++);
910*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LEFT)
911*6236dae4SAndroid Build Coastguard Worker while(width-- > 0)
912*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
913*6236dae4SAndroid Build Coastguard Worker
914*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_ALT)
915*6236dae4SAndroid Build Coastguard Worker OUTCHAR('"');
916*6236dae4SAndroid Build Coastguard Worker break;
917*6236dae4SAndroid Build Coastguard Worker }
918*6236dae4SAndroid Build Coastguard Worker
919*6236dae4SAndroid Build Coastguard Worker case FORMAT_PTR:
920*6236dae4SAndroid Build Coastguard Worker /* Generic pointer. */
921*6236dae4SAndroid Build Coastguard Worker if(iptr->val.ptr) {
922*6236dae4SAndroid Build Coastguard Worker /* If the pointer is not NULL, write it as a %#x spec. */
923*6236dae4SAndroid Build Coastguard Worker base = 16;
924*6236dae4SAndroid Build Coastguard Worker digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
925*6236dae4SAndroid Build Coastguard Worker is_alt = TRUE;
926*6236dae4SAndroid Build Coastguard Worker num = (size_t) iptr->val.ptr;
927*6236dae4SAndroid Build Coastguard Worker is_neg = FALSE;
928*6236dae4SAndroid Build Coastguard Worker goto number;
929*6236dae4SAndroid Build Coastguard Worker }
930*6236dae4SAndroid Build Coastguard Worker else {
931*6236dae4SAndroid Build Coastguard Worker /* Write "(nil)" for a nil pointer. */
932*6236dae4SAndroid Build Coastguard Worker const char *point;
933*6236dae4SAndroid Build Coastguard Worker
934*6236dae4SAndroid Build Coastguard Worker width -= (int)(sizeof(nilstr) - 1);
935*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LEFT)
936*6236dae4SAndroid Build Coastguard Worker while(width-- > 0)
937*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
938*6236dae4SAndroid Build Coastguard Worker for(point = nilstr; *point != '\0'; ++point)
939*6236dae4SAndroid Build Coastguard Worker OUTCHAR(*point);
940*6236dae4SAndroid Build Coastguard Worker if(!(flags & FLAGS_LEFT))
941*6236dae4SAndroid Build Coastguard Worker while(width-- > 0)
942*6236dae4SAndroid Build Coastguard Worker OUTCHAR(' ');
943*6236dae4SAndroid Build Coastguard Worker }
944*6236dae4SAndroid Build Coastguard Worker break;
945*6236dae4SAndroid Build Coastguard Worker
946*6236dae4SAndroid Build Coastguard Worker case FORMAT_DOUBLE: {
947*6236dae4SAndroid Build Coastguard Worker char formatbuf[32]="%";
948*6236dae4SAndroid Build Coastguard Worker char *fptr = &formatbuf[1];
949*6236dae4SAndroid Build Coastguard Worker size_t left = sizeof(formatbuf)-strlen(formatbuf);
950*6236dae4SAndroid Build Coastguard Worker int len;
951*6236dae4SAndroid Build Coastguard Worker
952*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_WIDTH)
953*6236dae4SAndroid Build Coastguard Worker width = optr->width;
954*6236dae4SAndroid Build Coastguard Worker
955*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_PREC)
956*6236dae4SAndroid Build Coastguard Worker prec = optr->precision;
957*6236dae4SAndroid Build Coastguard Worker
958*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LEFT)
959*6236dae4SAndroid Build Coastguard Worker *fptr++ = '-';
960*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_SHOWSIGN)
961*6236dae4SAndroid Build Coastguard Worker *fptr++ = '+';
962*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_SPACE)
963*6236dae4SAndroid Build Coastguard Worker *fptr++ = ' ';
964*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_ALT)
965*6236dae4SAndroid Build Coastguard Worker *fptr++ = '#';
966*6236dae4SAndroid Build Coastguard Worker
967*6236dae4SAndroid Build Coastguard Worker *fptr = 0;
968*6236dae4SAndroid Build Coastguard Worker
969*6236dae4SAndroid Build Coastguard Worker if(width >= 0) {
970*6236dae4SAndroid Build Coastguard Worker size_t dlen;
971*6236dae4SAndroid Build Coastguard Worker if(width >= (int)sizeof(work))
972*6236dae4SAndroid Build Coastguard Worker width = sizeof(work)-1;
973*6236dae4SAndroid Build Coastguard Worker /* RECURSIVE USAGE */
974*6236dae4SAndroid Build Coastguard Worker dlen = (size_t)curl_msnprintf(fptr, left, "%d", width);
975*6236dae4SAndroid Build Coastguard Worker fptr += dlen;
976*6236dae4SAndroid Build Coastguard Worker left -= dlen;
977*6236dae4SAndroid Build Coastguard Worker }
978*6236dae4SAndroid Build Coastguard Worker if(prec >= 0) {
979*6236dae4SAndroid Build Coastguard Worker /* for each digit in the integer part, we can have one less
980*6236dae4SAndroid Build Coastguard Worker precision */
981*6236dae4SAndroid Build Coastguard Worker size_t maxprec = sizeof(work) - 2;
982*6236dae4SAndroid Build Coastguard Worker double val = iptr->val.dnum;
983*6236dae4SAndroid Build Coastguard Worker if(width > 0 && prec <= width)
984*6236dae4SAndroid Build Coastguard Worker maxprec -= (size_t)width;
985*6236dae4SAndroid Build Coastguard Worker while(val >= 10.0) {
986*6236dae4SAndroid Build Coastguard Worker val /= 10;
987*6236dae4SAndroid Build Coastguard Worker maxprec--;
988*6236dae4SAndroid Build Coastguard Worker }
989*6236dae4SAndroid Build Coastguard Worker
990*6236dae4SAndroid Build Coastguard Worker if(prec > (int)maxprec)
991*6236dae4SAndroid Build Coastguard Worker prec = (int)maxprec-1;
992*6236dae4SAndroid Build Coastguard Worker if(prec < 0)
993*6236dae4SAndroid Build Coastguard Worker prec = 0;
994*6236dae4SAndroid Build Coastguard Worker /* RECURSIVE USAGE */
995*6236dae4SAndroid Build Coastguard Worker len = curl_msnprintf(fptr, left, ".%d", prec);
996*6236dae4SAndroid Build Coastguard Worker fptr += len;
997*6236dae4SAndroid Build Coastguard Worker }
998*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONG)
999*6236dae4SAndroid Build Coastguard Worker *fptr++ = 'l';
1000*6236dae4SAndroid Build Coastguard Worker
1001*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_FLOATE)
1002*6236dae4SAndroid Build Coastguard Worker *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E' : 'e');
1003*6236dae4SAndroid Build Coastguard Worker else if(flags & FLAGS_FLOATG)
1004*6236dae4SAndroid Build Coastguard Worker *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g');
1005*6236dae4SAndroid Build Coastguard Worker else
1006*6236dae4SAndroid Build Coastguard Worker *fptr++ = 'f';
1007*6236dae4SAndroid Build Coastguard Worker
1008*6236dae4SAndroid Build Coastguard Worker *fptr = 0; /* and a final null-termination */
1009*6236dae4SAndroid Build Coastguard Worker
1010*6236dae4SAndroid Build Coastguard Worker #ifdef __clang__
1011*6236dae4SAndroid Build Coastguard Worker #pragma clang diagnostic push
1012*6236dae4SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wformat-nonliteral"
1013*6236dae4SAndroid Build Coastguard Worker #endif
1014*6236dae4SAndroid Build Coastguard Worker /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
1015*6236dae4SAndroid Build Coastguard Worker output characters */
1016*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SNPRINTF
1017*6236dae4SAndroid Build Coastguard Worker (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum);
1018*6236dae4SAndroid Build Coastguard Worker #else
1019*6236dae4SAndroid Build Coastguard Worker (sprintf)(work, formatbuf, iptr->val.dnum);
1020*6236dae4SAndroid Build Coastguard Worker #endif
1021*6236dae4SAndroid Build Coastguard Worker #ifdef __clang__
1022*6236dae4SAndroid Build Coastguard Worker #pragma clang diagnostic pop
1023*6236dae4SAndroid Build Coastguard Worker #endif
1024*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(strlen(work) <= sizeof(work));
1025*6236dae4SAndroid Build Coastguard Worker for(fptr = work; *fptr; fptr++)
1026*6236dae4SAndroid Build Coastguard Worker OUTCHAR(*fptr);
1027*6236dae4SAndroid Build Coastguard Worker break;
1028*6236dae4SAndroid Build Coastguard Worker }
1029*6236dae4SAndroid Build Coastguard Worker
1030*6236dae4SAndroid Build Coastguard Worker case FORMAT_INTPTR:
1031*6236dae4SAndroid Build Coastguard Worker /* Answer the count of characters written. */
1032*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_LONG_LONG_TYPE
1033*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONGLONG)
1034*6236dae4SAndroid Build Coastguard Worker *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done;
1035*6236dae4SAndroid Build Coastguard Worker else
1036*6236dae4SAndroid Build Coastguard Worker #endif
1037*6236dae4SAndroid Build Coastguard Worker if(flags & FLAGS_LONG)
1038*6236dae4SAndroid Build Coastguard Worker *(long *) iptr->val.ptr = (long)done;
1039*6236dae4SAndroid Build Coastguard Worker else if(!(flags & FLAGS_SHORT))
1040*6236dae4SAndroid Build Coastguard Worker *(int *) iptr->val.ptr = (int)done;
1041*6236dae4SAndroid Build Coastguard Worker else
1042*6236dae4SAndroid Build Coastguard Worker *(short *) iptr->val.ptr = (short)done;
1043*6236dae4SAndroid Build Coastguard Worker break;
1044*6236dae4SAndroid Build Coastguard Worker
1045*6236dae4SAndroid Build Coastguard Worker default:
1046*6236dae4SAndroid Build Coastguard Worker break;
1047*6236dae4SAndroid Build Coastguard Worker }
1048*6236dae4SAndroid Build Coastguard Worker }
1049*6236dae4SAndroid Build Coastguard Worker return done;
1050*6236dae4SAndroid Build Coastguard Worker }
1051*6236dae4SAndroid Build Coastguard Worker
1052*6236dae4SAndroid Build Coastguard Worker /* fputc() look-alike */
addbyter(unsigned char outc,void * f)1053*6236dae4SAndroid Build Coastguard Worker static int addbyter(unsigned char outc, void *f)
1054*6236dae4SAndroid Build Coastguard Worker {
1055*6236dae4SAndroid Build Coastguard Worker struct nsprintf *infop = f;
1056*6236dae4SAndroid Build Coastguard Worker if(infop->length < infop->max) {
1057*6236dae4SAndroid Build Coastguard Worker /* only do this if we have not reached max length yet */
1058*6236dae4SAndroid Build Coastguard Worker *infop->buffer++ = (char)outc; /* store */
1059*6236dae4SAndroid Build Coastguard Worker infop->length++; /* we are now one byte larger */
1060*6236dae4SAndroid Build Coastguard Worker return 0; /* fputc() returns like this on success */
1061*6236dae4SAndroid Build Coastguard Worker }
1062*6236dae4SAndroid Build Coastguard Worker return 1;
1063*6236dae4SAndroid Build Coastguard Worker }
1064*6236dae4SAndroid Build Coastguard Worker
curl_mvsnprintf(char * buffer,size_t maxlength,const char * format,va_list ap_save)1065*6236dae4SAndroid Build Coastguard Worker int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1066*6236dae4SAndroid Build Coastguard Worker va_list ap_save)
1067*6236dae4SAndroid Build Coastguard Worker {
1068*6236dae4SAndroid Build Coastguard Worker int retcode;
1069*6236dae4SAndroid Build Coastguard Worker struct nsprintf info;
1070*6236dae4SAndroid Build Coastguard Worker
1071*6236dae4SAndroid Build Coastguard Worker info.buffer = buffer;
1072*6236dae4SAndroid Build Coastguard Worker info.length = 0;
1073*6236dae4SAndroid Build Coastguard Worker info.max = maxlength;
1074*6236dae4SAndroid Build Coastguard Worker
1075*6236dae4SAndroid Build Coastguard Worker retcode = formatf(&info, addbyter, format, ap_save);
1076*6236dae4SAndroid Build Coastguard Worker if(info.max) {
1077*6236dae4SAndroid Build Coastguard Worker /* we terminate this with a zero byte */
1078*6236dae4SAndroid Build Coastguard Worker if(info.max == info.length) {
1079*6236dae4SAndroid Build Coastguard Worker /* we are at maximum, scrap the last letter */
1080*6236dae4SAndroid Build Coastguard Worker info.buffer[-1] = 0;
1081*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(retcode);
1082*6236dae4SAndroid Build Coastguard Worker retcode--; /* do not count the nul byte */
1083*6236dae4SAndroid Build Coastguard Worker }
1084*6236dae4SAndroid Build Coastguard Worker else
1085*6236dae4SAndroid Build Coastguard Worker info.buffer[0] = 0;
1086*6236dae4SAndroid Build Coastguard Worker }
1087*6236dae4SAndroid Build Coastguard Worker return retcode;
1088*6236dae4SAndroid Build Coastguard Worker }
1089*6236dae4SAndroid Build Coastguard Worker
curl_msnprintf(char * buffer,size_t maxlength,const char * format,...)1090*6236dae4SAndroid Build Coastguard Worker int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1091*6236dae4SAndroid Build Coastguard Worker {
1092*6236dae4SAndroid Build Coastguard Worker int retcode;
1093*6236dae4SAndroid Build Coastguard Worker va_list ap_save; /* argument pointer */
1094*6236dae4SAndroid Build Coastguard Worker va_start(ap_save, format);
1095*6236dae4SAndroid Build Coastguard Worker retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1096*6236dae4SAndroid Build Coastguard Worker va_end(ap_save);
1097*6236dae4SAndroid Build Coastguard Worker return retcode;
1098*6236dae4SAndroid Build Coastguard Worker }
1099*6236dae4SAndroid Build Coastguard Worker
1100*6236dae4SAndroid Build Coastguard Worker /* fputc() look-alike */
alloc_addbyter(unsigned char outc,void * f)1101*6236dae4SAndroid Build Coastguard Worker static int alloc_addbyter(unsigned char outc, void *f)
1102*6236dae4SAndroid Build Coastguard Worker {
1103*6236dae4SAndroid Build Coastguard Worker struct asprintf *infop = f;
1104*6236dae4SAndroid Build Coastguard Worker CURLcode result = Curl_dyn_addn(infop->b, &outc, 1);
1105*6236dae4SAndroid Build Coastguard Worker if(result) {
1106*6236dae4SAndroid Build Coastguard Worker infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM;
1107*6236dae4SAndroid Build Coastguard Worker return 1 ; /* fail */
1108*6236dae4SAndroid Build Coastguard Worker }
1109*6236dae4SAndroid Build Coastguard Worker return 0;
1110*6236dae4SAndroid Build Coastguard Worker }
1111*6236dae4SAndroid Build Coastguard Worker
1112*6236dae4SAndroid Build Coastguard Worker /* appends the formatted string, returns MERR error code */
Curl_dyn_vprintf(struct dynbuf * dyn,const char * format,va_list ap_save)1113*6236dae4SAndroid Build Coastguard Worker int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
1114*6236dae4SAndroid Build Coastguard Worker {
1115*6236dae4SAndroid Build Coastguard Worker struct asprintf info;
1116*6236dae4SAndroid Build Coastguard Worker info.b = dyn;
1117*6236dae4SAndroid Build Coastguard Worker info.merr = MERR_OK;
1118*6236dae4SAndroid Build Coastguard Worker
1119*6236dae4SAndroid Build Coastguard Worker (void)formatf(&info, alloc_addbyter, format, ap_save);
1120*6236dae4SAndroid Build Coastguard Worker if(info.merr) {
1121*6236dae4SAndroid Build Coastguard Worker Curl_dyn_free(info.b);
1122*6236dae4SAndroid Build Coastguard Worker return info.merr;
1123*6236dae4SAndroid Build Coastguard Worker }
1124*6236dae4SAndroid Build Coastguard Worker return 0;
1125*6236dae4SAndroid Build Coastguard Worker }
1126*6236dae4SAndroid Build Coastguard Worker
curl_mvaprintf(const char * format,va_list ap_save)1127*6236dae4SAndroid Build Coastguard Worker char *curl_mvaprintf(const char *format, va_list ap_save)
1128*6236dae4SAndroid Build Coastguard Worker {
1129*6236dae4SAndroid Build Coastguard Worker struct asprintf info;
1130*6236dae4SAndroid Build Coastguard Worker struct dynbuf dyn;
1131*6236dae4SAndroid Build Coastguard Worker info.b = &dyn;
1132*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(info.b, DYN_APRINTF);
1133*6236dae4SAndroid Build Coastguard Worker info.merr = MERR_OK;
1134*6236dae4SAndroid Build Coastguard Worker
1135*6236dae4SAndroid Build Coastguard Worker (void)formatf(&info, alloc_addbyter, format, ap_save);
1136*6236dae4SAndroid Build Coastguard Worker if(info.merr) {
1137*6236dae4SAndroid Build Coastguard Worker Curl_dyn_free(info.b);
1138*6236dae4SAndroid Build Coastguard Worker return NULL;
1139*6236dae4SAndroid Build Coastguard Worker }
1140*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_len(info.b))
1141*6236dae4SAndroid Build Coastguard Worker return Curl_dyn_ptr(info.b);
1142*6236dae4SAndroid Build Coastguard Worker return strdup("");
1143*6236dae4SAndroid Build Coastguard Worker }
1144*6236dae4SAndroid Build Coastguard Worker
curl_maprintf(const char * format,...)1145*6236dae4SAndroid Build Coastguard Worker char *curl_maprintf(const char *format, ...)
1146*6236dae4SAndroid Build Coastguard Worker {
1147*6236dae4SAndroid Build Coastguard Worker va_list ap_save;
1148*6236dae4SAndroid Build Coastguard Worker char *s;
1149*6236dae4SAndroid Build Coastguard Worker va_start(ap_save, format);
1150*6236dae4SAndroid Build Coastguard Worker s = curl_mvaprintf(format, ap_save);
1151*6236dae4SAndroid Build Coastguard Worker va_end(ap_save);
1152*6236dae4SAndroid Build Coastguard Worker return s;
1153*6236dae4SAndroid Build Coastguard Worker }
1154*6236dae4SAndroid Build Coastguard Worker
storebuffer(unsigned char outc,void * f)1155*6236dae4SAndroid Build Coastguard Worker static int storebuffer(unsigned char outc, void *f)
1156*6236dae4SAndroid Build Coastguard Worker {
1157*6236dae4SAndroid Build Coastguard Worker char **buffer = f;
1158*6236dae4SAndroid Build Coastguard Worker **buffer = (char)outc;
1159*6236dae4SAndroid Build Coastguard Worker (*buffer)++;
1160*6236dae4SAndroid Build Coastguard Worker return 0;
1161*6236dae4SAndroid Build Coastguard Worker }
1162*6236dae4SAndroid Build Coastguard Worker
curl_msprintf(char * buffer,const char * format,...)1163*6236dae4SAndroid Build Coastguard Worker int curl_msprintf(char *buffer, const char *format, ...)
1164*6236dae4SAndroid Build Coastguard Worker {
1165*6236dae4SAndroid Build Coastguard Worker va_list ap_save; /* argument pointer */
1166*6236dae4SAndroid Build Coastguard Worker int retcode;
1167*6236dae4SAndroid Build Coastguard Worker va_start(ap_save, format);
1168*6236dae4SAndroid Build Coastguard Worker retcode = formatf(&buffer, storebuffer, format, ap_save);
1169*6236dae4SAndroid Build Coastguard Worker va_end(ap_save);
1170*6236dae4SAndroid Build Coastguard Worker *buffer = 0; /* we terminate this with a zero byte */
1171*6236dae4SAndroid Build Coastguard Worker return retcode;
1172*6236dae4SAndroid Build Coastguard Worker }
1173*6236dae4SAndroid Build Coastguard Worker
fputc_wrapper(unsigned char outc,void * f)1174*6236dae4SAndroid Build Coastguard Worker static int fputc_wrapper(unsigned char outc, void *f)
1175*6236dae4SAndroid Build Coastguard Worker {
1176*6236dae4SAndroid Build Coastguard Worker int out = outc;
1177*6236dae4SAndroid Build Coastguard Worker FILE *s = f;
1178*6236dae4SAndroid Build Coastguard Worker int rc = fputc(out, s);
1179*6236dae4SAndroid Build Coastguard Worker return rc == EOF;
1180*6236dae4SAndroid Build Coastguard Worker }
1181*6236dae4SAndroid Build Coastguard Worker
curl_mprintf(const char * format,...)1182*6236dae4SAndroid Build Coastguard Worker int curl_mprintf(const char *format, ...)
1183*6236dae4SAndroid Build Coastguard Worker {
1184*6236dae4SAndroid Build Coastguard Worker int retcode;
1185*6236dae4SAndroid Build Coastguard Worker va_list ap_save; /* argument pointer */
1186*6236dae4SAndroid Build Coastguard Worker va_start(ap_save, format);
1187*6236dae4SAndroid Build Coastguard Worker
1188*6236dae4SAndroid Build Coastguard Worker retcode = formatf(stdout, fputc_wrapper, format, ap_save);
1189*6236dae4SAndroid Build Coastguard Worker va_end(ap_save);
1190*6236dae4SAndroid Build Coastguard Worker return retcode;
1191*6236dae4SAndroid Build Coastguard Worker }
1192*6236dae4SAndroid Build Coastguard Worker
curl_mfprintf(FILE * whereto,const char * format,...)1193*6236dae4SAndroid Build Coastguard Worker int curl_mfprintf(FILE *whereto, const char *format, ...)
1194*6236dae4SAndroid Build Coastguard Worker {
1195*6236dae4SAndroid Build Coastguard Worker int retcode;
1196*6236dae4SAndroid Build Coastguard Worker va_list ap_save; /* argument pointer */
1197*6236dae4SAndroid Build Coastguard Worker va_start(ap_save, format);
1198*6236dae4SAndroid Build Coastguard Worker retcode = formatf(whereto, fputc_wrapper, format, ap_save);
1199*6236dae4SAndroid Build Coastguard Worker va_end(ap_save);
1200*6236dae4SAndroid Build Coastguard Worker return retcode;
1201*6236dae4SAndroid Build Coastguard Worker }
1202*6236dae4SAndroid Build Coastguard Worker
curl_mvsprintf(char * buffer,const char * format,va_list ap_save)1203*6236dae4SAndroid Build Coastguard Worker int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1204*6236dae4SAndroid Build Coastguard Worker {
1205*6236dae4SAndroid Build Coastguard Worker int retcode = formatf(&buffer, storebuffer, format, ap_save);
1206*6236dae4SAndroid Build Coastguard Worker *buffer = 0; /* we terminate this with a zero byte */
1207*6236dae4SAndroid Build Coastguard Worker return retcode;
1208*6236dae4SAndroid Build Coastguard Worker }
1209*6236dae4SAndroid Build Coastguard Worker
curl_mvprintf(const char * format,va_list ap_save)1210*6236dae4SAndroid Build Coastguard Worker int curl_mvprintf(const char *format, va_list ap_save)
1211*6236dae4SAndroid Build Coastguard Worker {
1212*6236dae4SAndroid Build Coastguard Worker return formatf(stdout, fputc_wrapper, format, ap_save);
1213*6236dae4SAndroid Build Coastguard Worker }
1214*6236dae4SAndroid Build Coastguard Worker
curl_mvfprintf(FILE * whereto,const char * format,va_list ap_save)1215*6236dae4SAndroid Build Coastguard Worker int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1216*6236dae4SAndroid Build Coastguard Worker {
1217*6236dae4SAndroid Build Coastguard Worker return formatf(whereto, fputc_wrapper, format, ap_save);
1218*6236dae4SAndroid Build Coastguard Worker }
1219