113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci */ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci#include "dynbuf.h" 2713498266Sopenharmony_ci#include "curl_printf.h" 2813498266Sopenharmony_ci#include <curl/mprintf.h> 2913498266Sopenharmony_ci 3013498266Sopenharmony_ci#include "curl_memory.h" 3113498266Sopenharmony_ci/* The last #include file should be: */ 3213498266Sopenharmony_ci#include "memdebug.h" 3313498266Sopenharmony_ci 3413498266Sopenharmony_ci/* 3513498266Sopenharmony_ci * If SIZEOF_SIZE_T has not been defined, default to the size of long. 3613498266Sopenharmony_ci */ 3713498266Sopenharmony_ci 3813498266Sopenharmony_ci#ifdef HAVE_LONGLONG 3913498266Sopenharmony_ci# define LONG_LONG_TYPE long long 4013498266Sopenharmony_ci# define HAVE_LONG_LONG_TYPE 4113498266Sopenharmony_ci#else 4213498266Sopenharmony_ci# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) 4313498266Sopenharmony_ci# define LONG_LONG_TYPE __int64 4413498266Sopenharmony_ci# define HAVE_LONG_LONG_TYPE 4513498266Sopenharmony_ci# else 4613498266Sopenharmony_ci# undef LONG_LONG_TYPE 4713498266Sopenharmony_ci# undef HAVE_LONG_LONG_TYPE 4813498266Sopenharmony_ci# endif 4913498266Sopenharmony_ci#endif 5013498266Sopenharmony_ci 5113498266Sopenharmony_ci/* 5213498266Sopenharmony_ci * Non-ANSI integer extensions 5313498266Sopenharmony_ci */ 5413498266Sopenharmony_ci 5513498266Sopenharmony_ci#if (defined(_WIN32_WCE)) || \ 5613498266Sopenharmony_ci (defined(__MINGW32__)) || \ 5713498266Sopenharmony_ci (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)) 5813498266Sopenharmony_ci# define MP_HAVE_INT_EXTENSIONS 5913498266Sopenharmony_ci#endif 6013498266Sopenharmony_ci 6113498266Sopenharmony_ci/* 6213498266Sopenharmony_ci * Max integer data types that mprintf.c is capable 6313498266Sopenharmony_ci */ 6413498266Sopenharmony_ci 6513498266Sopenharmony_ci#ifdef HAVE_LONG_LONG_TYPE 6613498266Sopenharmony_ci# define mp_intmax_t LONG_LONG_TYPE 6713498266Sopenharmony_ci# define mp_uintmax_t unsigned LONG_LONG_TYPE 6813498266Sopenharmony_ci#else 6913498266Sopenharmony_ci# define mp_intmax_t long 7013498266Sopenharmony_ci# define mp_uintmax_t unsigned long 7113498266Sopenharmony_ci#endif 7213498266Sopenharmony_ci 7313498266Sopenharmony_ci#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should 7413498266Sopenharmony_ci fit negative DBL_MAX (317 letters) */ 7513498266Sopenharmony_ci#define MAX_PARAMETERS 128 /* number of input arguments */ 7613498266Sopenharmony_ci#define MAX_SEGMENTS 128 /* number of output segments */ 7713498266Sopenharmony_ci 7813498266Sopenharmony_ci#ifdef __AMIGA__ 7913498266Sopenharmony_ci# undef FORMAT_INT 8013498266Sopenharmony_ci#endif 8113498266Sopenharmony_ci 8213498266Sopenharmony_ci/* Lower-case digits. */ 8313498266Sopenharmony_cistatic const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 8413498266Sopenharmony_ci 8513498266Sopenharmony_ci/* Upper-case digits. */ 8613498266Sopenharmony_cistatic const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 8713498266Sopenharmony_ci 8813498266Sopenharmony_ci#define OUTCHAR(x) \ 8913498266Sopenharmony_ci do { \ 9013498266Sopenharmony_ci if(!stream(x, userp)) \ 9113498266Sopenharmony_ci done++; \ 9213498266Sopenharmony_ci else \ 9313498266Sopenharmony_ci return done; /* return on failure */ \ 9413498266Sopenharmony_ci } while(0) 9513498266Sopenharmony_ci 9613498266Sopenharmony_ci/* Data type to read from the arglist */ 9713498266Sopenharmony_citypedef enum { 9813498266Sopenharmony_ci FORMAT_STRING, 9913498266Sopenharmony_ci FORMAT_PTR, 10013498266Sopenharmony_ci FORMAT_INTPTR, 10113498266Sopenharmony_ci FORMAT_INT, 10213498266Sopenharmony_ci FORMAT_LONG, 10313498266Sopenharmony_ci FORMAT_LONGLONG, 10413498266Sopenharmony_ci FORMAT_INTU, 10513498266Sopenharmony_ci FORMAT_LONGU, 10613498266Sopenharmony_ci FORMAT_LONGLONGU, 10713498266Sopenharmony_ci FORMAT_DOUBLE, 10813498266Sopenharmony_ci FORMAT_LONGDOUBLE, 10913498266Sopenharmony_ci FORMAT_WIDTH, 11013498266Sopenharmony_ci FORMAT_PRECISION 11113498266Sopenharmony_ci} FormatType; 11213498266Sopenharmony_ci 11313498266Sopenharmony_ci/* conversion and display flags */ 11413498266Sopenharmony_cienum { 11513498266Sopenharmony_ci FLAGS_SPACE = 1<<0, 11613498266Sopenharmony_ci FLAGS_SHOWSIGN = 1<<1, 11713498266Sopenharmony_ci FLAGS_LEFT = 1<<2, 11813498266Sopenharmony_ci FLAGS_ALT = 1<<3, 11913498266Sopenharmony_ci FLAGS_SHORT = 1<<4, 12013498266Sopenharmony_ci FLAGS_LONG = 1<<5, 12113498266Sopenharmony_ci FLAGS_LONGLONG = 1<<6, 12213498266Sopenharmony_ci FLAGS_LONGDOUBLE = 1<<7, 12313498266Sopenharmony_ci FLAGS_PAD_NIL = 1<<8, 12413498266Sopenharmony_ci FLAGS_UNSIGNED = 1<<9, 12513498266Sopenharmony_ci FLAGS_OCTAL = 1<<10, 12613498266Sopenharmony_ci FLAGS_HEX = 1<<11, 12713498266Sopenharmony_ci FLAGS_UPPER = 1<<12, 12813498266Sopenharmony_ci FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */ 12913498266Sopenharmony_ci FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ 13013498266Sopenharmony_ci FLAGS_PREC = 1<<15, /* precision was specified */ 13113498266Sopenharmony_ci FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */ 13213498266Sopenharmony_ci FLAGS_CHAR = 1<<17, /* %c story */ 13313498266Sopenharmony_ci FLAGS_FLOATE = 1<<18, /* %e or %E */ 13413498266Sopenharmony_ci FLAGS_FLOATG = 1<<19, /* %g or %G */ 13513498266Sopenharmony_ci FLAGS_SUBSTR = 1<<20 /* no input, only substring */ 13613498266Sopenharmony_ci}; 13713498266Sopenharmony_ci 13813498266Sopenharmony_cienum { 13913498266Sopenharmony_ci DOLLAR_UNKNOWN, 14013498266Sopenharmony_ci DOLLAR_NOPE, 14113498266Sopenharmony_ci DOLLAR_USE 14213498266Sopenharmony_ci}; 14313498266Sopenharmony_ci 14413498266Sopenharmony_ci/* 14513498266Sopenharmony_ci * Describes an input va_arg type and hold its value. 14613498266Sopenharmony_ci */ 14713498266Sopenharmony_cistruct va_input { 14813498266Sopenharmony_ci FormatType type; /* FormatType */ 14913498266Sopenharmony_ci union { 15013498266Sopenharmony_ci char *str; 15113498266Sopenharmony_ci void *ptr; 15213498266Sopenharmony_ci mp_intmax_t nums; /* signed */ 15313498266Sopenharmony_ci mp_uintmax_t numu; /* unsigned */ 15413498266Sopenharmony_ci double dnum; 15513498266Sopenharmony_ci } val; 15613498266Sopenharmony_ci}; 15713498266Sopenharmony_ci 15813498266Sopenharmony_ci/* 15913498266Sopenharmony_ci * Describes an output segment. 16013498266Sopenharmony_ci */ 16113498266Sopenharmony_cistruct outsegment { 16213498266Sopenharmony_ci int width; /* width OR width parameter number */ 16313498266Sopenharmony_ci int precision; /* precision OR precision parameter number */ 16413498266Sopenharmony_ci unsigned int flags; 16513498266Sopenharmony_ci unsigned int input; /* input argument array index */ 16613498266Sopenharmony_ci char *start; /* format string start to output */ 16713498266Sopenharmony_ci size_t outlen; /* number of bytes from the format string to output */ 16813498266Sopenharmony_ci}; 16913498266Sopenharmony_ci 17013498266Sopenharmony_cistruct nsprintf { 17113498266Sopenharmony_ci char *buffer; 17213498266Sopenharmony_ci size_t length; 17313498266Sopenharmony_ci size_t max; 17413498266Sopenharmony_ci}; 17513498266Sopenharmony_ci 17613498266Sopenharmony_cistruct asprintf { 17713498266Sopenharmony_ci struct dynbuf *b; 17813498266Sopenharmony_ci char merr; 17913498266Sopenharmony_ci}; 18013498266Sopenharmony_ci 18113498266Sopenharmony_ci/* the provided input number is 1-based but this returns the number 0-based. 18213498266Sopenharmony_ci 18313498266Sopenharmony_ci returns -1 if no valid number was provided. 18413498266Sopenharmony_ci*/ 18513498266Sopenharmony_cistatic int dollarstring(char *input, char **end) 18613498266Sopenharmony_ci{ 18713498266Sopenharmony_ci if(ISDIGIT(*input)) { 18813498266Sopenharmony_ci int number = 0; 18913498266Sopenharmony_ci do { 19013498266Sopenharmony_ci if(number < MAX_PARAMETERS) { 19113498266Sopenharmony_ci number *= 10; 19213498266Sopenharmony_ci number += *input - '0'; 19313498266Sopenharmony_ci } 19413498266Sopenharmony_ci input++; 19513498266Sopenharmony_ci } while(ISDIGIT(*input)); 19613498266Sopenharmony_ci 19713498266Sopenharmony_ci if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) { 19813498266Sopenharmony_ci *end = ++input; 19913498266Sopenharmony_ci return number - 1; 20013498266Sopenharmony_ci } 20113498266Sopenharmony_ci } 20213498266Sopenharmony_ci return -1; 20313498266Sopenharmony_ci} 20413498266Sopenharmony_ci 20513498266Sopenharmony_ci/* 20613498266Sopenharmony_ci * Parse the format string. 20713498266Sopenharmony_ci * 20813498266Sopenharmony_ci * Create two arrays. One describes the inputs, one describes the outputs. 20913498266Sopenharmony_ci * 21013498266Sopenharmony_ci * Returns zero on success. 21113498266Sopenharmony_ci */ 21213498266Sopenharmony_ci 21313498266Sopenharmony_ci#define PFMT_OK 0 21413498266Sopenharmony_ci#define PFMT_DOLLAR 1 /* bad dollar for main param */ 21513498266Sopenharmony_ci#define PFMT_DOLLARWIDTH 2 /* bad dollar use for width */ 21613498266Sopenharmony_ci#define PFMT_DOLLARPREC 3 /* bad dollar use for precision */ 21713498266Sopenharmony_ci#define PFMT_MANYARGS 4 /* too many input arguments used */ 21813498266Sopenharmony_ci#define PFMT_PREC 5 /* precision overflow */ 21913498266Sopenharmony_ci#define PFMT_PRECMIX 6 /* bad mix of precision specifiers */ 22013498266Sopenharmony_ci#define PFMT_WIDTH 7 /* width overflow */ 22113498266Sopenharmony_ci#define PFMT_INPUTGAP 8 /* gap in arguments */ 22213498266Sopenharmony_ci#define PFMT_WIDTHARG 9 /* attempted to use same arg twice, for width */ 22313498266Sopenharmony_ci#define PFMT_PRECARG 10 /* attempted to use same arg twice, for prec */ 22413498266Sopenharmony_ci#define PFMT_MANYSEGS 11 /* maxed out output segments */ 22513498266Sopenharmony_ci 22613498266Sopenharmony_cistatic int parsefmt(const char *format, 22713498266Sopenharmony_ci struct outsegment *out, 22813498266Sopenharmony_ci struct va_input *in, 22913498266Sopenharmony_ci int *opieces, 23013498266Sopenharmony_ci int *ipieces, va_list arglist) 23113498266Sopenharmony_ci{ 23213498266Sopenharmony_ci char *fmt = (char *)format; 23313498266Sopenharmony_ci int param_num = 0; 23413498266Sopenharmony_ci int param; 23513498266Sopenharmony_ci int width; 23613498266Sopenharmony_ci int precision; 23713498266Sopenharmony_ci unsigned int flags; 23813498266Sopenharmony_ci FormatType type; 23913498266Sopenharmony_ci int max_param = -1; 24013498266Sopenharmony_ci int i; 24113498266Sopenharmony_ci int ocount = 0; 24213498266Sopenharmony_ci unsigned char usedinput[MAX_PARAMETERS/8]; 24313498266Sopenharmony_ci size_t outlen = 0; 24413498266Sopenharmony_ci struct outsegment *optr; 24513498266Sopenharmony_ci int use_dollar = DOLLAR_UNKNOWN; 24613498266Sopenharmony_ci char *start = fmt; 24713498266Sopenharmony_ci 24813498266Sopenharmony_ci /* clear, set a bit for each used input */ 24913498266Sopenharmony_ci memset(usedinput, 0, sizeof(usedinput)); 25013498266Sopenharmony_ci 25113498266Sopenharmony_ci while(*fmt) { 25213498266Sopenharmony_ci if(*fmt == '%') { 25313498266Sopenharmony_ci struct va_input *iptr; 25413498266Sopenharmony_ci bool loopit = TRUE; 25513498266Sopenharmony_ci fmt++; 25613498266Sopenharmony_ci outlen = fmt - start - 1; 25713498266Sopenharmony_ci if(*fmt == '%') { 25813498266Sopenharmony_ci /* this means a %% that should be output only as %. Create an output 25913498266Sopenharmony_ci segment. */ 26013498266Sopenharmony_ci if(outlen) { 26113498266Sopenharmony_ci optr = &out[ocount++]; 26213498266Sopenharmony_ci if(ocount > MAX_SEGMENTS) 26313498266Sopenharmony_ci return PFMT_MANYSEGS; 26413498266Sopenharmony_ci optr->input = 0; 26513498266Sopenharmony_ci optr->flags = FLAGS_SUBSTR; 26613498266Sopenharmony_ci optr->start = start; 26713498266Sopenharmony_ci optr->outlen = outlen; 26813498266Sopenharmony_ci } 26913498266Sopenharmony_ci start = fmt; 27013498266Sopenharmony_ci fmt++; 27113498266Sopenharmony_ci continue; /* while */ 27213498266Sopenharmony_ci } 27313498266Sopenharmony_ci 27413498266Sopenharmony_ci flags = width = precision = 0; 27513498266Sopenharmony_ci 27613498266Sopenharmony_ci if(use_dollar != DOLLAR_NOPE) { 27713498266Sopenharmony_ci param = dollarstring(fmt, &fmt); 27813498266Sopenharmony_ci if(param < 0) { 27913498266Sopenharmony_ci if(use_dollar == DOLLAR_USE) 28013498266Sopenharmony_ci /* illegal combo */ 28113498266Sopenharmony_ci return PFMT_DOLLAR; 28213498266Sopenharmony_ci 28313498266Sopenharmony_ci /* we got no positional, just get the next arg */ 28413498266Sopenharmony_ci param = -1; 28513498266Sopenharmony_ci use_dollar = DOLLAR_NOPE; 28613498266Sopenharmony_ci } 28713498266Sopenharmony_ci else 28813498266Sopenharmony_ci use_dollar = DOLLAR_USE; 28913498266Sopenharmony_ci } 29013498266Sopenharmony_ci else 29113498266Sopenharmony_ci param = -1; 29213498266Sopenharmony_ci 29313498266Sopenharmony_ci /* Handle the flags */ 29413498266Sopenharmony_ci while(loopit) { 29513498266Sopenharmony_ci switch(*fmt++) { 29613498266Sopenharmony_ci case ' ': 29713498266Sopenharmony_ci flags |= FLAGS_SPACE; 29813498266Sopenharmony_ci break; 29913498266Sopenharmony_ci case '+': 30013498266Sopenharmony_ci flags |= FLAGS_SHOWSIGN; 30113498266Sopenharmony_ci break; 30213498266Sopenharmony_ci case '-': 30313498266Sopenharmony_ci flags |= FLAGS_LEFT; 30413498266Sopenharmony_ci flags &= ~FLAGS_PAD_NIL; 30513498266Sopenharmony_ci break; 30613498266Sopenharmony_ci case '#': 30713498266Sopenharmony_ci flags |= FLAGS_ALT; 30813498266Sopenharmony_ci break; 30913498266Sopenharmony_ci case '.': 31013498266Sopenharmony_ci if('*' == *fmt) { 31113498266Sopenharmony_ci /* The precision is picked from a specified parameter */ 31213498266Sopenharmony_ci flags |= FLAGS_PRECPARAM; 31313498266Sopenharmony_ci fmt++; 31413498266Sopenharmony_ci 31513498266Sopenharmony_ci if(use_dollar == DOLLAR_USE) { 31613498266Sopenharmony_ci precision = dollarstring(fmt, &fmt); 31713498266Sopenharmony_ci if(precision < 0) 31813498266Sopenharmony_ci /* illegal combo */ 31913498266Sopenharmony_ci return PFMT_DOLLARPREC; 32013498266Sopenharmony_ci } 32113498266Sopenharmony_ci else 32213498266Sopenharmony_ci /* get it from the next argument */ 32313498266Sopenharmony_ci precision = -1; 32413498266Sopenharmony_ci } 32513498266Sopenharmony_ci else { 32613498266Sopenharmony_ci bool is_neg = FALSE; 32713498266Sopenharmony_ci flags |= FLAGS_PREC; 32813498266Sopenharmony_ci precision = 0; 32913498266Sopenharmony_ci if('-' == *fmt) { 33013498266Sopenharmony_ci is_neg = TRUE; 33113498266Sopenharmony_ci fmt++; 33213498266Sopenharmony_ci } 33313498266Sopenharmony_ci while(ISDIGIT(*fmt)) { 33413498266Sopenharmony_ci if(precision > INT_MAX/10) 33513498266Sopenharmony_ci return PFMT_PREC; 33613498266Sopenharmony_ci precision *= 10; 33713498266Sopenharmony_ci precision += *fmt - '0'; 33813498266Sopenharmony_ci fmt++; 33913498266Sopenharmony_ci } 34013498266Sopenharmony_ci if(is_neg) 34113498266Sopenharmony_ci precision = -precision; 34213498266Sopenharmony_ci } 34313498266Sopenharmony_ci if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) == 34413498266Sopenharmony_ci (FLAGS_PREC | FLAGS_PRECPARAM)) 34513498266Sopenharmony_ci /* it is not permitted to use both kinds of precision for the same 34613498266Sopenharmony_ci argument */ 34713498266Sopenharmony_ci return PFMT_PRECMIX; 34813498266Sopenharmony_ci break; 34913498266Sopenharmony_ci case 'h': 35013498266Sopenharmony_ci flags |= FLAGS_SHORT; 35113498266Sopenharmony_ci break; 35213498266Sopenharmony_ci#if defined(MP_HAVE_INT_EXTENSIONS) 35313498266Sopenharmony_ci case 'I': 35413498266Sopenharmony_ci if((fmt[0] == '3') && (fmt[1] == '2')) { 35513498266Sopenharmony_ci flags |= FLAGS_LONG; 35613498266Sopenharmony_ci fmt += 2; 35713498266Sopenharmony_ci } 35813498266Sopenharmony_ci else if((fmt[0] == '6') && (fmt[1] == '4')) { 35913498266Sopenharmony_ci flags |= FLAGS_LONGLONG; 36013498266Sopenharmony_ci fmt += 2; 36113498266Sopenharmony_ci } 36213498266Sopenharmony_ci else { 36313498266Sopenharmony_ci#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) 36413498266Sopenharmony_ci flags |= FLAGS_LONGLONG; 36513498266Sopenharmony_ci#else 36613498266Sopenharmony_ci flags |= FLAGS_LONG; 36713498266Sopenharmony_ci#endif 36813498266Sopenharmony_ci } 36913498266Sopenharmony_ci break; 37013498266Sopenharmony_ci#endif 37113498266Sopenharmony_ci case 'l': 37213498266Sopenharmony_ci if(flags & FLAGS_LONG) 37313498266Sopenharmony_ci flags |= FLAGS_LONGLONG; 37413498266Sopenharmony_ci else 37513498266Sopenharmony_ci flags |= FLAGS_LONG; 37613498266Sopenharmony_ci break; 37713498266Sopenharmony_ci case 'L': 37813498266Sopenharmony_ci flags |= FLAGS_LONGDOUBLE; 37913498266Sopenharmony_ci break; 38013498266Sopenharmony_ci case 'q': 38113498266Sopenharmony_ci flags |= FLAGS_LONGLONG; 38213498266Sopenharmony_ci break; 38313498266Sopenharmony_ci case 'z': 38413498266Sopenharmony_ci /* the code below generates a warning if -Wunreachable-code is 38513498266Sopenharmony_ci used */ 38613498266Sopenharmony_ci#if (SIZEOF_SIZE_T > SIZEOF_LONG) 38713498266Sopenharmony_ci flags |= FLAGS_LONGLONG; 38813498266Sopenharmony_ci#else 38913498266Sopenharmony_ci flags |= FLAGS_LONG; 39013498266Sopenharmony_ci#endif 39113498266Sopenharmony_ci break; 39213498266Sopenharmony_ci case 'O': 39313498266Sopenharmony_ci#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) 39413498266Sopenharmony_ci flags |= FLAGS_LONGLONG; 39513498266Sopenharmony_ci#else 39613498266Sopenharmony_ci flags |= FLAGS_LONG; 39713498266Sopenharmony_ci#endif 39813498266Sopenharmony_ci break; 39913498266Sopenharmony_ci case '0': 40013498266Sopenharmony_ci if(!(flags & FLAGS_LEFT)) 40113498266Sopenharmony_ci flags |= FLAGS_PAD_NIL; 40213498266Sopenharmony_ci FALLTHROUGH(); 40313498266Sopenharmony_ci case '1': case '2': case '3': case '4': 40413498266Sopenharmony_ci case '5': case '6': case '7': case '8': case '9': 40513498266Sopenharmony_ci flags |= FLAGS_WIDTH; 40613498266Sopenharmony_ci width = 0; 40713498266Sopenharmony_ci fmt--; 40813498266Sopenharmony_ci do { 40913498266Sopenharmony_ci if(width > INT_MAX/10) 41013498266Sopenharmony_ci return PFMT_WIDTH; 41113498266Sopenharmony_ci width *= 10; 41213498266Sopenharmony_ci width += *fmt - '0'; 41313498266Sopenharmony_ci fmt++; 41413498266Sopenharmony_ci } while(ISDIGIT(*fmt)); 41513498266Sopenharmony_ci break; 41613498266Sopenharmony_ci case '*': /* read width from argument list */ 41713498266Sopenharmony_ci flags |= FLAGS_WIDTHPARAM; 41813498266Sopenharmony_ci if(use_dollar == DOLLAR_USE) { 41913498266Sopenharmony_ci width = dollarstring(fmt, &fmt); 42013498266Sopenharmony_ci if(width < 0) 42113498266Sopenharmony_ci /* illegal combo */ 42213498266Sopenharmony_ci return PFMT_DOLLARWIDTH; 42313498266Sopenharmony_ci } 42413498266Sopenharmony_ci else 42513498266Sopenharmony_ci /* pick from the next argument */ 42613498266Sopenharmony_ci width = -1; 42713498266Sopenharmony_ci break; 42813498266Sopenharmony_ci default: 42913498266Sopenharmony_ci loopit = FALSE; 43013498266Sopenharmony_ci fmt--; 43113498266Sopenharmony_ci break; 43213498266Sopenharmony_ci } /* switch */ 43313498266Sopenharmony_ci } /* while */ 43413498266Sopenharmony_ci 43513498266Sopenharmony_ci switch(*fmt) { 43613498266Sopenharmony_ci case 'S': 43713498266Sopenharmony_ci flags |= FLAGS_ALT; 43813498266Sopenharmony_ci FALLTHROUGH(); 43913498266Sopenharmony_ci case 's': 44013498266Sopenharmony_ci type = FORMAT_STRING; 44113498266Sopenharmony_ci break; 44213498266Sopenharmony_ci case 'n': 44313498266Sopenharmony_ci type = FORMAT_INTPTR; 44413498266Sopenharmony_ci break; 44513498266Sopenharmony_ci case 'p': 44613498266Sopenharmony_ci type = FORMAT_PTR; 44713498266Sopenharmony_ci break; 44813498266Sopenharmony_ci case 'd': 44913498266Sopenharmony_ci case 'i': 45013498266Sopenharmony_ci if(flags & FLAGS_LONGLONG) 45113498266Sopenharmony_ci type = FORMAT_LONGLONG; 45213498266Sopenharmony_ci else if(flags & FLAGS_LONG) 45313498266Sopenharmony_ci type = FORMAT_LONG; 45413498266Sopenharmony_ci else 45513498266Sopenharmony_ci type = FORMAT_INT; 45613498266Sopenharmony_ci break; 45713498266Sopenharmony_ci case 'u': 45813498266Sopenharmony_ci if(flags & FLAGS_LONGLONG) 45913498266Sopenharmony_ci type = FORMAT_LONGLONGU; 46013498266Sopenharmony_ci else if(flags & FLAGS_LONG) 46113498266Sopenharmony_ci type = FORMAT_LONGU; 46213498266Sopenharmony_ci else 46313498266Sopenharmony_ci type = FORMAT_INTU; 46413498266Sopenharmony_ci flags |= FLAGS_UNSIGNED; 46513498266Sopenharmony_ci break; 46613498266Sopenharmony_ci case 'o': 46713498266Sopenharmony_ci type = FORMAT_INT; 46813498266Sopenharmony_ci flags |= FLAGS_OCTAL; 46913498266Sopenharmony_ci break; 47013498266Sopenharmony_ci case 'x': 47113498266Sopenharmony_ci type = FORMAT_INTU; 47213498266Sopenharmony_ci flags |= FLAGS_HEX|FLAGS_UNSIGNED; 47313498266Sopenharmony_ci break; 47413498266Sopenharmony_ci case 'X': 47513498266Sopenharmony_ci type = FORMAT_INTU; 47613498266Sopenharmony_ci flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED; 47713498266Sopenharmony_ci break; 47813498266Sopenharmony_ci case 'c': 47913498266Sopenharmony_ci type = FORMAT_INT; 48013498266Sopenharmony_ci flags |= FLAGS_CHAR; 48113498266Sopenharmony_ci break; 48213498266Sopenharmony_ci case 'f': 48313498266Sopenharmony_ci type = FORMAT_DOUBLE; 48413498266Sopenharmony_ci break; 48513498266Sopenharmony_ci case 'e': 48613498266Sopenharmony_ci type = FORMAT_DOUBLE; 48713498266Sopenharmony_ci flags |= FLAGS_FLOATE; 48813498266Sopenharmony_ci break; 48913498266Sopenharmony_ci case 'E': 49013498266Sopenharmony_ci type = FORMAT_DOUBLE; 49113498266Sopenharmony_ci flags |= FLAGS_FLOATE|FLAGS_UPPER; 49213498266Sopenharmony_ci break; 49313498266Sopenharmony_ci case 'g': 49413498266Sopenharmony_ci type = FORMAT_DOUBLE; 49513498266Sopenharmony_ci flags |= FLAGS_FLOATG; 49613498266Sopenharmony_ci break; 49713498266Sopenharmony_ci case 'G': 49813498266Sopenharmony_ci type = FORMAT_DOUBLE; 49913498266Sopenharmony_ci flags |= FLAGS_FLOATG|FLAGS_UPPER; 50013498266Sopenharmony_ci break; 50113498266Sopenharmony_ci default: 50213498266Sopenharmony_ci /* invalid instruction, disregard and continue */ 50313498266Sopenharmony_ci continue; 50413498266Sopenharmony_ci } /* switch */ 50513498266Sopenharmony_ci 50613498266Sopenharmony_ci if(flags & FLAGS_WIDTHPARAM) { 50713498266Sopenharmony_ci if(width < 0) 50813498266Sopenharmony_ci width = param_num++; 50913498266Sopenharmony_ci else { 51013498266Sopenharmony_ci /* if this identifies a parameter already used, this 51113498266Sopenharmony_ci is illegal */ 51213498266Sopenharmony_ci if(usedinput[width/8] & (1 << (width&7))) 51313498266Sopenharmony_ci return PFMT_WIDTHARG; 51413498266Sopenharmony_ci } 51513498266Sopenharmony_ci if(width >= MAX_PARAMETERS) 51613498266Sopenharmony_ci return PFMT_MANYARGS; 51713498266Sopenharmony_ci if(width >= max_param) 51813498266Sopenharmony_ci max_param = width; 51913498266Sopenharmony_ci 52013498266Sopenharmony_ci in[width].type = FORMAT_WIDTH; 52113498266Sopenharmony_ci /* mark as used */ 52213498266Sopenharmony_ci usedinput[width/8] |= (unsigned char)(1 << (width&7)); 52313498266Sopenharmony_ci } 52413498266Sopenharmony_ci 52513498266Sopenharmony_ci if(flags & FLAGS_PRECPARAM) { 52613498266Sopenharmony_ci if(precision < 0) 52713498266Sopenharmony_ci precision = param_num++; 52813498266Sopenharmony_ci else { 52913498266Sopenharmony_ci /* if this identifies a parameter already used, this 53013498266Sopenharmony_ci is illegal */ 53113498266Sopenharmony_ci if(usedinput[precision/8] & (1 << (precision&7))) 53213498266Sopenharmony_ci return PFMT_PRECARG; 53313498266Sopenharmony_ci } 53413498266Sopenharmony_ci if(precision >= MAX_PARAMETERS) 53513498266Sopenharmony_ci return PFMT_MANYARGS; 53613498266Sopenharmony_ci if(precision >= max_param) 53713498266Sopenharmony_ci max_param = precision; 53813498266Sopenharmony_ci 53913498266Sopenharmony_ci in[precision].type = FORMAT_PRECISION; 54013498266Sopenharmony_ci usedinput[precision/8] |= (unsigned char)(1 << (precision&7)); 54113498266Sopenharmony_ci } 54213498266Sopenharmony_ci 54313498266Sopenharmony_ci /* Handle the specifier */ 54413498266Sopenharmony_ci if(param < 0) 54513498266Sopenharmony_ci param = param_num++; 54613498266Sopenharmony_ci if(param >= MAX_PARAMETERS) 54713498266Sopenharmony_ci return PFMT_MANYARGS; 54813498266Sopenharmony_ci if(param >= max_param) 54913498266Sopenharmony_ci max_param = param; 55013498266Sopenharmony_ci 55113498266Sopenharmony_ci iptr = &in[param]; 55213498266Sopenharmony_ci iptr->type = type; 55313498266Sopenharmony_ci 55413498266Sopenharmony_ci /* mark this input as used */ 55513498266Sopenharmony_ci usedinput[param/8] |= (unsigned char)(1 << (param&7)); 55613498266Sopenharmony_ci 55713498266Sopenharmony_ci fmt++; 55813498266Sopenharmony_ci optr = &out[ocount++]; 55913498266Sopenharmony_ci if(ocount > MAX_SEGMENTS) 56013498266Sopenharmony_ci return PFMT_MANYSEGS; 56113498266Sopenharmony_ci optr->input = param; 56213498266Sopenharmony_ci optr->flags = flags; 56313498266Sopenharmony_ci optr->width = width; 56413498266Sopenharmony_ci optr->precision = precision; 56513498266Sopenharmony_ci optr->start = start; 56613498266Sopenharmony_ci optr->outlen = outlen; 56713498266Sopenharmony_ci start = fmt; 56813498266Sopenharmony_ci } 56913498266Sopenharmony_ci else 57013498266Sopenharmony_ci fmt++; 57113498266Sopenharmony_ci } 57213498266Sopenharmony_ci 57313498266Sopenharmony_ci /* is there a trailing piece */ 57413498266Sopenharmony_ci outlen = fmt - start; 57513498266Sopenharmony_ci if(outlen) { 57613498266Sopenharmony_ci optr = &out[ocount++]; 57713498266Sopenharmony_ci if(ocount > MAX_SEGMENTS) 57813498266Sopenharmony_ci return PFMT_MANYSEGS; 57913498266Sopenharmony_ci optr->input = 0; 58013498266Sopenharmony_ci optr->flags = FLAGS_SUBSTR; 58113498266Sopenharmony_ci optr->start = start; 58213498266Sopenharmony_ci optr->outlen = outlen; 58313498266Sopenharmony_ci } 58413498266Sopenharmony_ci 58513498266Sopenharmony_ci /* Read the arg list parameters into our data list */ 58613498266Sopenharmony_ci for(i = 0; i < max_param + 1; i++) { 58713498266Sopenharmony_ci struct va_input *iptr = &in[i]; 58813498266Sopenharmony_ci if(!(usedinput[i/8] & (1 << (i&7)))) 58913498266Sopenharmony_ci /* bad input */ 59013498266Sopenharmony_ci return PFMT_INPUTGAP; 59113498266Sopenharmony_ci 59213498266Sopenharmony_ci /* based on the type, read the correct argument */ 59313498266Sopenharmony_ci switch(iptr->type) { 59413498266Sopenharmony_ci case FORMAT_STRING: 59513498266Sopenharmony_ci iptr->val.str = va_arg(arglist, char *); 59613498266Sopenharmony_ci break; 59713498266Sopenharmony_ci 59813498266Sopenharmony_ci case FORMAT_INTPTR: 59913498266Sopenharmony_ci case FORMAT_PTR: 60013498266Sopenharmony_ci iptr->val.ptr = va_arg(arglist, void *); 60113498266Sopenharmony_ci break; 60213498266Sopenharmony_ci 60313498266Sopenharmony_ci case FORMAT_LONGLONGU: 60413498266Sopenharmony_ci iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t); 60513498266Sopenharmony_ci break; 60613498266Sopenharmony_ci 60713498266Sopenharmony_ci case FORMAT_LONGLONG: 60813498266Sopenharmony_ci iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t); 60913498266Sopenharmony_ci break; 61013498266Sopenharmony_ci 61113498266Sopenharmony_ci case FORMAT_LONGU: 61213498266Sopenharmony_ci iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long); 61313498266Sopenharmony_ci break; 61413498266Sopenharmony_ci 61513498266Sopenharmony_ci case FORMAT_LONG: 61613498266Sopenharmony_ci iptr->val.nums = (mp_intmax_t)va_arg(arglist, long); 61713498266Sopenharmony_ci break; 61813498266Sopenharmony_ci 61913498266Sopenharmony_ci case FORMAT_INTU: 62013498266Sopenharmony_ci iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int); 62113498266Sopenharmony_ci break; 62213498266Sopenharmony_ci 62313498266Sopenharmony_ci case FORMAT_INT: 62413498266Sopenharmony_ci case FORMAT_WIDTH: 62513498266Sopenharmony_ci case FORMAT_PRECISION: 62613498266Sopenharmony_ci iptr->val.nums = (mp_intmax_t)va_arg(arglist, int); 62713498266Sopenharmony_ci break; 62813498266Sopenharmony_ci 62913498266Sopenharmony_ci case FORMAT_DOUBLE: 63013498266Sopenharmony_ci iptr->val.dnum = va_arg(arglist, double); 63113498266Sopenharmony_ci break; 63213498266Sopenharmony_ci 63313498266Sopenharmony_ci default: 63413498266Sopenharmony_ci DEBUGASSERT(NULL); /* unexpected */ 63513498266Sopenharmony_ci break; 63613498266Sopenharmony_ci } 63713498266Sopenharmony_ci } 63813498266Sopenharmony_ci *ipieces = max_param + 1; 63913498266Sopenharmony_ci *opieces = ocount; 64013498266Sopenharmony_ci 64113498266Sopenharmony_ci return PFMT_OK; 64213498266Sopenharmony_ci} 64313498266Sopenharmony_ci 64413498266Sopenharmony_ci/* 64513498266Sopenharmony_ci * formatf() - the general printf function. 64613498266Sopenharmony_ci * 64713498266Sopenharmony_ci * It calls parsefmt() to parse the format string. It populates two arrays; 64813498266Sopenharmony_ci * one that describes the input arguments and one that describes a number of 64913498266Sopenharmony_ci * output segments. 65013498266Sopenharmony_ci * 65113498266Sopenharmony_ci * On success, the input array describes the type of all arguments and their 65213498266Sopenharmony_ci * values. 65313498266Sopenharmony_ci * 65413498266Sopenharmony_ci * The function then iterates over the output sengments and outputs them one 65513498266Sopenharmony_ci * by one until done. Using the appropriate input arguments (if any). 65613498266Sopenharmony_ci * 65713498266Sopenharmony_ci * All output is sent to the 'stream()' callback, one byte at a time. 65813498266Sopenharmony_ci */ 65913498266Sopenharmony_ci 66013498266Sopenharmony_cistatic int formatf( 66113498266Sopenharmony_ci void *userp, /* untouched by format(), just sent to the stream() function in 66213498266Sopenharmony_ci the second argument */ 66313498266Sopenharmony_ci /* function pointer called for each output character */ 66413498266Sopenharmony_ci int (*stream)(unsigned char, void *), 66513498266Sopenharmony_ci const char *format, /* %-formatted string */ 66613498266Sopenharmony_ci va_list ap_save) /* list of parameters */ 66713498266Sopenharmony_ci{ 66813498266Sopenharmony_ci static const char nilstr[] = "(nil)"; 66913498266Sopenharmony_ci const char *digits = lower_digits; /* Base-36 digits for numbers. */ 67013498266Sopenharmony_ci int done = 0; /* number of characters written */ 67113498266Sopenharmony_ci int i; 67213498266Sopenharmony_ci int ocount = 0; /* number of output segments */ 67313498266Sopenharmony_ci int icount = 0; /* number of input arguments */ 67413498266Sopenharmony_ci 67513498266Sopenharmony_ci struct outsegment output[MAX_SEGMENTS]; 67613498266Sopenharmony_ci struct va_input input[MAX_PARAMETERS]; 67713498266Sopenharmony_ci char work[BUFFSIZE]; 67813498266Sopenharmony_ci 67913498266Sopenharmony_ci /* 'workend' points to the final buffer byte position, but with an extra 68013498266Sopenharmony_ci byte as margin to avoid the (false?) warning Coverity gives us 68113498266Sopenharmony_ci otherwise */ 68213498266Sopenharmony_ci char *workend = &work[sizeof(work) - 2]; 68313498266Sopenharmony_ci 68413498266Sopenharmony_ci /* Parse the format string */ 68513498266Sopenharmony_ci if(parsefmt(format, output, input, &ocount, &icount, ap_save)) 68613498266Sopenharmony_ci return 0; 68713498266Sopenharmony_ci 68813498266Sopenharmony_ci for(i = 0; i < ocount; i++) { 68913498266Sopenharmony_ci struct outsegment *optr = &output[i]; 69013498266Sopenharmony_ci struct va_input *iptr; 69113498266Sopenharmony_ci bool is_alt; /* Format spec modifiers. */ 69213498266Sopenharmony_ci int width; /* Width of a field. */ 69313498266Sopenharmony_ci int prec; /* Precision of a field. */ 69413498266Sopenharmony_ci bool is_neg; /* Decimal integer is negative. */ 69513498266Sopenharmony_ci unsigned long base; /* Base of a number to be written. */ 69613498266Sopenharmony_ci mp_uintmax_t num; /* Integral values to be written. */ 69713498266Sopenharmony_ci mp_intmax_t signed_num; /* Used to convert negative in positive. */ 69813498266Sopenharmony_ci char *w; 69913498266Sopenharmony_ci size_t outlen = optr->outlen; 70013498266Sopenharmony_ci int flags = optr->flags; 70113498266Sopenharmony_ci 70213498266Sopenharmony_ci if(outlen) { 70313498266Sopenharmony_ci char *str = optr->start; 70413498266Sopenharmony_ci for(; outlen && *str; outlen--) 70513498266Sopenharmony_ci OUTCHAR(*str++); 70613498266Sopenharmony_ci if(optr->flags & FLAGS_SUBSTR) 70713498266Sopenharmony_ci /* this is just a substring */ 70813498266Sopenharmony_ci continue; 70913498266Sopenharmony_ci } 71013498266Sopenharmony_ci 71113498266Sopenharmony_ci /* pick up the specified width */ 71213498266Sopenharmony_ci if(flags & FLAGS_WIDTHPARAM) { 71313498266Sopenharmony_ci width = (int)input[optr->width].val.nums; 71413498266Sopenharmony_ci if(width < 0) { 71513498266Sopenharmony_ci /* "A negative field width is taken as a '-' flag followed by a 71613498266Sopenharmony_ci positive field width." */ 71713498266Sopenharmony_ci if(width == INT_MIN) 71813498266Sopenharmony_ci width = INT_MAX; 71913498266Sopenharmony_ci else 72013498266Sopenharmony_ci width = -width; 72113498266Sopenharmony_ci flags |= FLAGS_LEFT; 72213498266Sopenharmony_ci flags &= ~FLAGS_PAD_NIL; 72313498266Sopenharmony_ci } 72413498266Sopenharmony_ci } 72513498266Sopenharmony_ci else 72613498266Sopenharmony_ci width = optr->width; 72713498266Sopenharmony_ci 72813498266Sopenharmony_ci /* pick up the specified precision */ 72913498266Sopenharmony_ci if(flags & FLAGS_PRECPARAM) { 73013498266Sopenharmony_ci prec = (int)input[optr->precision].val.nums; 73113498266Sopenharmony_ci if(prec < 0) 73213498266Sopenharmony_ci /* "A negative precision is taken as if the precision were 73313498266Sopenharmony_ci omitted." */ 73413498266Sopenharmony_ci prec = -1; 73513498266Sopenharmony_ci } 73613498266Sopenharmony_ci else if(flags & FLAGS_PREC) 73713498266Sopenharmony_ci prec = optr->precision; 73813498266Sopenharmony_ci else 73913498266Sopenharmony_ci prec = -1; 74013498266Sopenharmony_ci 74113498266Sopenharmony_ci is_alt = (flags & FLAGS_ALT) ? 1 : 0; 74213498266Sopenharmony_ci iptr = &input[optr->input]; 74313498266Sopenharmony_ci 74413498266Sopenharmony_ci switch(iptr->type) { 74513498266Sopenharmony_ci case FORMAT_INTU: 74613498266Sopenharmony_ci case FORMAT_LONGU: 74713498266Sopenharmony_ci case FORMAT_LONGLONGU: 74813498266Sopenharmony_ci flags |= FLAGS_UNSIGNED; 74913498266Sopenharmony_ci FALLTHROUGH(); 75013498266Sopenharmony_ci case FORMAT_INT: 75113498266Sopenharmony_ci case FORMAT_LONG: 75213498266Sopenharmony_ci case FORMAT_LONGLONG: 75313498266Sopenharmony_ci num = iptr->val.numu; 75413498266Sopenharmony_ci if(flags & FLAGS_CHAR) { 75513498266Sopenharmony_ci /* Character. */ 75613498266Sopenharmony_ci if(!(flags & FLAGS_LEFT)) 75713498266Sopenharmony_ci while(--width > 0) 75813498266Sopenharmony_ci OUTCHAR(' '); 75913498266Sopenharmony_ci OUTCHAR((char) num); 76013498266Sopenharmony_ci if(flags & FLAGS_LEFT) 76113498266Sopenharmony_ci while(--width > 0) 76213498266Sopenharmony_ci OUTCHAR(' '); 76313498266Sopenharmony_ci break; 76413498266Sopenharmony_ci } 76513498266Sopenharmony_ci if(flags & FLAGS_OCTAL) { 76613498266Sopenharmony_ci /* Octal unsigned integer */ 76713498266Sopenharmony_ci base = 8; 76813498266Sopenharmony_ci is_neg = FALSE; 76913498266Sopenharmony_ci } 77013498266Sopenharmony_ci else if(flags & FLAGS_HEX) { 77113498266Sopenharmony_ci /* Hexadecimal unsigned integer */ 77213498266Sopenharmony_ci digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits; 77313498266Sopenharmony_ci base = 16; 77413498266Sopenharmony_ci is_neg = FALSE; 77513498266Sopenharmony_ci } 77613498266Sopenharmony_ci else if(flags & FLAGS_UNSIGNED) { 77713498266Sopenharmony_ci /* Decimal unsigned integer */ 77813498266Sopenharmony_ci base = 10; 77913498266Sopenharmony_ci is_neg = FALSE; 78013498266Sopenharmony_ci } 78113498266Sopenharmony_ci else { 78213498266Sopenharmony_ci /* Decimal integer. */ 78313498266Sopenharmony_ci base = 10; 78413498266Sopenharmony_ci 78513498266Sopenharmony_ci is_neg = (iptr->val.nums < (mp_intmax_t)0); 78613498266Sopenharmony_ci if(is_neg) { 78713498266Sopenharmony_ci /* signed_num might fail to hold absolute negative minimum by 1 */ 78813498266Sopenharmony_ci signed_num = iptr->val.nums + (mp_intmax_t)1; 78913498266Sopenharmony_ci signed_num = -signed_num; 79013498266Sopenharmony_ci num = (mp_uintmax_t)signed_num; 79113498266Sopenharmony_ci num += (mp_uintmax_t)1; 79213498266Sopenharmony_ci } 79313498266Sopenharmony_ci } 79413498266Sopenharmony_cinumber: 79513498266Sopenharmony_ci /* Supply a default precision if none was given. */ 79613498266Sopenharmony_ci if(prec == -1) 79713498266Sopenharmony_ci prec = 1; 79813498266Sopenharmony_ci 79913498266Sopenharmony_ci /* Put the number in WORK. */ 80013498266Sopenharmony_ci w = workend; 80113498266Sopenharmony_ci switch(base) { 80213498266Sopenharmony_ci case 10: 80313498266Sopenharmony_ci while(num > 0) { 80413498266Sopenharmony_ci *w-- = (char)('0' + (num % 10)); 80513498266Sopenharmony_ci num /= 10; 80613498266Sopenharmony_ci } 80713498266Sopenharmony_ci break; 80813498266Sopenharmony_ci default: 80913498266Sopenharmony_ci while(num > 0) { 81013498266Sopenharmony_ci *w-- = digits[num % base]; 81113498266Sopenharmony_ci num /= base; 81213498266Sopenharmony_ci } 81313498266Sopenharmony_ci break; 81413498266Sopenharmony_ci } 81513498266Sopenharmony_ci width -= (int)(workend - w); 81613498266Sopenharmony_ci prec -= (int)(workend - w); 81713498266Sopenharmony_ci 81813498266Sopenharmony_ci if(is_alt && base == 8 && prec <= 0) { 81913498266Sopenharmony_ci *w-- = '0'; 82013498266Sopenharmony_ci --width; 82113498266Sopenharmony_ci } 82213498266Sopenharmony_ci 82313498266Sopenharmony_ci if(prec > 0) { 82413498266Sopenharmony_ci width -= prec; 82513498266Sopenharmony_ci while(prec-- > 0 && w >= work) 82613498266Sopenharmony_ci *w-- = '0'; 82713498266Sopenharmony_ci } 82813498266Sopenharmony_ci 82913498266Sopenharmony_ci if(is_alt && base == 16) 83013498266Sopenharmony_ci width -= 2; 83113498266Sopenharmony_ci 83213498266Sopenharmony_ci if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) 83313498266Sopenharmony_ci --width; 83413498266Sopenharmony_ci 83513498266Sopenharmony_ci if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL)) 83613498266Sopenharmony_ci while(width-- > 0) 83713498266Sopenharmony_ci OUTCHAR(' '); 83813498266Sopenharmony_ci 83913498266Sopenharmony_ci if(is_neg) 84013498266Sopenharmony_ci OUTCHAR('-'); 84113498266Sopenharmony_ci else if(flags & FLAGS_SHOWSIGN) 84213498266Sopenharmony_ci OUTCHAR('+'); 84313498266Sopenharmony_ci else if(flags & FLAGS_SPACE) 84413498266Sopenharmony_ci OUTCHAR(' '); 84513498266Sopenharmony_ci 84613498266Sopenharmony_ci if(is_alt && base == 16) { 84713498266Sopenharmony_ci OUTCHAR('0'); 84813498266Sopenharmony_ci if(flags & FLAGS_UPPER) 84913498266Sopenharmony_ci OUTCHAR('X'); 85013498266Sopenharmony_ci else 85113498266Sopenharmony_ci OUTCHAR('x'); 85213498266Sopenharmony_ci } 85313498266Sopenharmony_ci 85413498266Sopenharmony_ci if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL)) 85513498266Sopenharmony_ci while(width-- > 0) 85613498266Sopenharmony_ci OUTCHAR('0'); 85713498266Sopenharmony_ci 85813498266Sopenharmony_ci /* Write the number. */ 85913498266Sopenharmony_ci while(++w <= workend) { 86013498266Sopenharmony_ci OUTCHAR(*w); 86113498266Sopenharmony_ci } 86213498266Sopenharmony_ci 86313498266Sopenharmony_ci if(flags & FLAGS_LEFT) 86413498266Sopenharmony_ci while(width-- > 0) 86513498266Sopenharmony_ci OUTCHAR(' '); 86613498266Sopenharmony_ci break; 86713498266Sopenharmony_ci 86813498266Sopenharmony_ci case FORMAT_STRING: { 86913498266Sopenharmony_ci const char *str; 87013498266Sopenharmony_ci size_t len; 87113498266Sopenharmony_ci 87213498266Sopenharmony_ci str = (char *)iptr->val.str; 87313498266Sopenharmony_ci if(!str) { 87413498266Sopenharmony_ci /* Write null string if there's space. */ 87513498266Sopenharmony_ci if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) { 87613498266Sopenharmony_ci str = nilstr; 87713498266Sopenharmony_ci len = sizeof(nilstr) - 1; 87813498266Sopenharmony_ci /* Disable quotes around (nil) */ 87913498266Sopenharmony_ci flags &= (~FLAGS_ALT); 88013498266Sopenharmony_ci } 88113498266Sopenharmony_ci else { 88213498266Sopenharmony_ci str = ""; 88313498266Sopenharmony_ci len = 0; 88413498266Sopenharmony_ci } 88513498266Sopenharmony_ci } 88613498266Sopenharmony_ci else if(prec != -1) 88713498266Sopenharmony_ci len = (size_t)prec; 88813498266Sopenharmony_ci else if(*str == '\0') 88913498266Sopenharmony_ci len = 0; 89013498266Sopenharmony_ci else 89113498266Sopenharmony_ci len = strlen(str); 89213498266Sopenharmony_ci 89313498266Sopenharmony_ci width -= (len > INT_MAX) ? INT_MAX : (int)len; 89413498266Sopenharmony_ci 89513498266Sopenharmony_ci if(flags & FLAGS_ALT) 89613498266Sopenharmony_ci OUTCHAR('"'); 89713498266Sopenharmony_ci 89813498266Sopenharmony_ci if(!(flags&FLAGS_LEFT)) 89913498266Sopenharmony_ci while(width-- > 0) 90013498266Sopenharmony_ci OUTCHAR(' '); 90113498266Sopenharmony_ci 90213498266Sopenharmony_ci for(; len && *str; len--) 90313498266Sopenharmony_ci OUTCHAR(*str++); 90413498266Sopenharmony_ci if(flags&FLAGS_LEFT) 90513498266Sopenharmony_ci while(width-- > 0) 90613498266Sopenharmony_ci OUTCHAR(' '); 90713498266Sopenharmony_ci 90813498266Sopenharmony_ci if(flags & FLAGS_ALT) 90913498266Sopenharmony_ci OUTCHAR('"'); 91013498266Sopenharmony_ci break; 91113498266Sopenharmony_ci } 91213498266Sopenharmony_ci 91313498266Sopenharmony_ci case FORMAT_PTR: 91413498266Sopenharmony_ci /* Generic pointer. */ 91513498266Sopenharmony_ci if(iptr->val.ptr) { 91613498266Sopenharmony_ci /* If the pointer is not NULL, write it as a %#x spec. */ 91713498266Sopenharmony_ci base = 16; 91813498266Sopenharmony_ci digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits; 91913498266Sopenharmony_ci is_alt = TRUE; 92013498266Sopenharmony_ci num = (size_t) iptr->val.ptr; 92113498266Sopenharmony_ci is_neg = FALSE; 92213498266Sopenharmony_ci goto number; 92313498266Sopenharmony_ci } 92413498266Sopenharmony_ci else { 92513498266Sopenharmony_ci /* Write "(nil)" for a nil pointer. */ 92613498266Sopenharmony_ci const char *point; 92713498266Sopenharmony_ci 92813498266Sopenharmony_ci width -= (int)(sizeof(nilstr) - 1); 92913498266Sopenharmony_ci if(flags & FLAGS_LEFT) 93013498266Sopenharmony_ci while(width-- > 0) 93113498266Sopenharmony_ci OUTCHAR(' '); 93213498266Sopenharmony_ci for(point = nilstr; *point != '\0'; ++point) 93313498266Sopenharmony_ci OUTCHAR(*point); 93413498266Sopenharmony_ci if(!(flags & FLAGS_LEFT)) 93513498266Sopenharmony_ci while(width-- > 0) 93613498266Sopenharmony_ci OUTCHAR(' '); 93713498266Sopenharmony_ci } 93813498266Sopenharmony_ci break; 93913498266Sopenharmony_ci 94013498266Sopenharmony_ci case FORMAT_DOUBLE: { 94113498266Sopenharmony_ci char formatbuf[32]="%"; 94213498266Sopenharmony_ci char *fptr = &formatbuf[1]; 94313498266Sopenharmony_ci size_t left = sizeof(formatbuf)-strlen(formatbuf); 94413498266Sopenharmony_ci int len; 94513498266Sopenharmony_ci 94613498266Sopenharmony_ci if(flags & FLAGS_WIDTH) 94713498266Sopenharmony_ci width = optr->width; 94813498266Sopenharmony_ci 94913498266Sopenharmony_ci if(flags & FLAGS_PREC) 95013498266Sopenharmony_ci prec = optr->precision; 95113498266Sopenharmony_ci 95213498266Sopenharmony_ci if(flags & FLAGS_LEFT) 95313498266Sopenharmony_ci *fptr++ = '-'; 95413498266Sopenharmony_ci if(flags & FLAGS_SHOWSIGN) 95513498266Sopenharmony_ci *fptr++ = '+'; 95613498266Sopenharmony_ci if(flags & FLAGS_SPACE) 95713498266Sopenharmony_ci *fptr++ = ' '; 95813498266Sopenharmony_ci if(flags & FLAGS_ALT) 95913498266Sopenharmony_ci *fptr++ = '#'; 96013498266Sopenharmony_ci 96113498266Sopenharmony_ci *fptr = 0; 96213498266Sopenharmony_ci 96313498266Sopenharmony_ci if(width >= 0) { 96413498266Sopenharmony_ci if(width >= (int)sizeof(work)) 96513498266Sopenharmony_ci width = sizeof(work)-1; 96613498266Sopenharmony_ci /* RECURSIVE USAGE */ 96713498266Sopenharmony_ci len = curl_msnprintf(fptr, left, "%d", width); 96813498266Sopenharmony_ci fptr += len; 96913498266Sopenharmony_ci left -= len; 97013498266Sopenharmony_ci } 97113498266Sopenharmony_ci if(prec >= 0) { 97213498266Sopenharmony_ci /* for each digit in the integer part, we can have one less 97313498266Sopenharmony_ci precision */ 97413498266Sopenharmony_ci size_t maxprec = sizeof(work) - 2; 97513498266Sopenharmony_ci double val = iptr->val.dnum; 97613498266Sopenharmony_ci if(width > 0 && prec <= width) 97713498266Sopenharmony_ci maxprec -= width; 97813498266Sopenharmony_ci while(val >= 10.0) { 97913498266Sopenharmony_ci val /= 10; 98013498266Sopenharmony_ci maxprec--; 98113498266Sopenharmony_ci } 98213498266Sopenharmony_ci 98313498266Sopenharmony_ci if(prec > (int)maxprec) 98413498266Sopenharmony_ci prec = (int)maxprec-1; 98513498266Sopenharmony_ci if(prec < 0) 98613498266Sopenharmony_ci prec = 0; 98713498266Sopenharmony_ci /* RECURSIVE USAGE */ 98813498266Sopenharmony_ci len = curl_msnprintf(fptr, left, ".%d", prec); 98913498266Sopenharmony_ci fptr += len; 99013498266Sopenharmony_ci } 99113498266Sopenharmony_ci if(flags & FLAGS_LONG) 99213498266Sopenharmony_ci *fptr++ = 'l'; 99313498266Sopenharmony_ci 99413498266Sopenharmony_ci if(flags & FLAGS_FLOATE) 99513498266Sopenharmony_ci *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E':'e'); 99613498266Sopenharmony_ci else if(flags & FLAGS_FLOATG) 99713498266Sopenharmony_ci *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g'); 99813498266Sopenharmony_ci else 99913498266Sopenharmony_ci *fptr++ = 'f'; 100013498266Sopenharmony_ci 100113498266Sopenharmony_ci *fptr = 0; /* and a final null-termination */ 100213498266Sopenharmony_ci 100313498266Sopenharmony_ci#ifdef __clang__ 100413498266Sopenharmony_ci#pragma clang diagnostic push 100513498266Sopenharmony_ci#pragma clang diagnostic ignored "-Wformat-nonliteral" 100613498266Sopenharmony_ci#endif 100713498266Sopenharmony_ci /* NOTE NOTE NOTE!! Not all sprintf implementations return number of 100813498266Sopenharmony_ci output characters */ 100913498266Sopenharmony_ci#ifdef HAVE_SNPRINTF 101013498266Sopenharmony_ci (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum); 101113498266Sopenharmony_ci#else 101213498266Sopenharmony_ci (sprintf)(work, formatbuf, iptr->val.dnum); 101313498266Sopenharmony_ci#endif 101413498266Sopenharmony_ci#ifdef __clang__ 101513498266Sopenharmony_ci#pragma clang diagnostic pop 101613498266Sopenharmony_ci#endif 101713498266Sopenharmony_ci DEBUGASSERT(strlen(work) <= sizeof(work)); 101813498266Sopenharmony_ci for(fptr = work; *fptr; fptr++) 101913498266Sopenharmony_ci OUTCHAR(*fptr); 102013498266Sopenharmony_ci break; 102113498266Sopenharmony_ci } 102213498266Sopenharmony_ci 102313498266Sopenharmony_ci case FORMAT_INTPTR: 102413498266Sopenharmony_ci /* Answer the count of characters written. */ 102513498266Sopenharmony_ci#ifdef HAVE_LONG_LONG_TYPE 102613498266Sopenharmony_ci if(flags & FLAGS_LONGLONG) 102713498266Sopenharmony_ci *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done; 102813498266Sopenharmony_ci else 102913498266Sopenharmony_ci#endif 103013498266Sopenharmony_ci if(flags & FLAGS_LONG) 103113498266Sopenharmony_ci *(long *) iptr->val.ptr = (long)done; 103213498266Sopenharmony_ci else if(!(flags & FLAGS_SHORT)) 103313498266Sopenharmony_ci *(int *) iptr->val.ptr = (int)done; 103413498266Sopenharmony_ci else 103513498266Sopenharmony_ci *(short *) iptr->val.ptr = (short)done; 103613498266Sopenharmony_ci break; 103713498266Sopenharmony_ci 103813498266Sopenharmony_ci default: 103913498266Sopenharmony_ci break; 104013498266Sopenharmony_ci } 104113498266Sopenharmony_ci } 104213498266Sopenharmony_ci return done; 104313498266Sopenharmony_ci} 104413498266Sopenharmony_ci 104513498266Sopenharmony_ci/* fputc() look-alike */ 104613498266Sopenharmony_cistatic int addbyter(unsigned char outc, void *f) 104713498266Sopenharmony_ci{ 104813498266Sopenharmony_ci struct nsprintf *infop = f; 104913498266Sopenharmony_ci if(infop->length < infop->max) { 105013498266Sopenharmony_ci /* only do this if we haven't reached max length yet */ 105113498266Sopenharmony_ci *infop->buffer++ = outc; /* store */ 105213498266Sopenharmony_ci infop->length++; /* we are now one byte larger */ 105313498266Sopenharmony_ci return 0; /* fputc() returns like this on success */ 105413498266Sopenharmony_ci } 105513498266Sopenharmony_ci return 1; 105613498266Sopenharmony_ci} 105713498266Sopenharmony_ci 105813498266Sopenharmony_ciint curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, 105913498266Sopenharmony_ci va_list ap_save) 106013498266Sopenharmony_ci{ 106113498266Sopenharmony_ci int retcode; 106213498266Sopenharmony_ci struct nsprintf info; 106313498266Sopenharmony_ci 106413498266Sopenharmony_ci info.buffer = buffer; 106513498266Sopenharmony_ci info.length = 0; 106613498266Sopenharmony_ci info.max = maxlength; 106713498266Sopenharmony_ci 106813498266Sopenharmony_ci retcode = formatf(&info, addbyter, format, ap_save); 106913498266Sopenharmony_ci if(info.max) { 107013498266Sopenharmony_ci /* we terminate this with a zero byte */ 107113498266Sopenharmony_ci if(info.max == info.length) { 107213498266Sopenharmony_ci /* we're at maximum, scrap the last letter */ 107313498266Sopenharmony_ci info.buffer[-1] = 0; 107413498266Sopenharmony_ci DEBUGASSERT(retcode); 107513498266Sopenharmony_ci retcode--; /* don't count the nul byte */ 107613498266Sopenharmony_ci } 107713498266Sopenharmony_ci else 107813498266Sopenharmony_ci info.buffer[0] = 0; 107913498266Sopenharmony_ci } 108013498266Sopenharmony_ci return retcode; 108113498266Sopenharmony_ci} 108213498266Sopenharmony_ci 108313498266Sopenharmony_ciint curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) 108413498266Sopenharmony_ci{ 108513498266Sopenharmony_ci int retcode; 108613498266Sopenharmony_ci va_list ap_save; /* argument pointer */ 108713498266Sopenharmony_ci va_start(ap_save, format); 108813498266Sopenharmony_ci retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save); 108913498266Sopenharmony_ci va_end(ap_save); 109013498266Sopenharmony_ci return retcode; 109113498266Sopenharmony_ci} 109213498266Sopenharmony_ci 109313498266Sopenharmony_ci/* fputc() look-alike */ 109413498266Sopenharmony_cistatic int alloc_addbyter(unsigned char outc, void *f) 109513498266Sopenharmony_ci{ 109613498266Sopenharmony_ci struct asprintf *infop = f; 109713498266Sopenharmony_ci CURLcode result = Curl_dyn_addn(infop->b, &outc, 1); 109813498266Sopenharmony_ci if(result) { 109913498266Sopenharmony_ci infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM; 110013498266Sopenharmony_ci return 1 ; /* fail */ 110113498266Sopenharmony_ci } 110213498266Sopenharmony_ci return 0; 110313498266Sopenharmony_ci} 110413498266Sopenharmony_ci 110513498266Sopenharmony_ci/* appends the formatted string, returns MERR error code */ 110613498266Sopenharmony_ciint Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save) 110713498266Sopenharmony_ci{ 110813498266Sopenharmony_ci struct asprintf info; 110913498266Sopenharmony_ci info.b = dyn; 111013498266Sopenharmony_ci info.merr = MERR_OK; 111113498266Sopenharmony_ci 111213498266Sopenharmony_ci (void)formatf(&info, alloc_addbyter, format, ap_save); 111313498266Sopenharmony_ci if(info.merr) { 111413498266Sopenharmony_ci Curl_dyn_free(info.b); 111513498266Sopenharmony_ci return info.merr; 111613498266Sopenharmony_ci } 111713498266Sopenharmony_ci return 0; 111813498266Sopenharmony_ci} 111913498266Sopenharmony_ci 112013498266Sopenharmony_cichar *curl_mvaprintf(const char *format, va_list ap_save) 112113498266Sopenharmony_ci{ 112213498266Sopenharmony_ci struct asprintf info; 112313498266Sopenharmony_ci struct dynbuf dyn; 112413498266Sopenharmony_ci info.b = &dyn; 112513498266Sopenharmony_ci Curl_dyn_init(info.b, DYN_APRINTF); 112613498266Sopenharmony_ci info.merr = MERR_OK; 112713498266Sopenharmony_ci 112813498266Sopenharmony_ci (void)formatf(&info, alloc_addbyter, format, ap_save); 112913498266Sopenharmony_ci if(info.merr) { 113013498266Sopenharmony_ci Curl_dyn_free(info.b); 113113498266Sopenharmony_ci return NULL; 113213498266Sopenharmony_ci } 113313498266Sopenharmony_ci if(Curl_dyn_len(info.b)) 113413498266Sopenharmony_ci return Curl_dyn_ptr(info.b); 113513498266Sopenharmony_ci return strdup(""); 113613498266Sopenharmony_ci} 113713498266Sopenharmony_ci 113813498266Sopenharmony_cichar *curl_maprintf(const char *format, ...) 113913498266Sopenharmony_ci{ 114013498266Sopenharmony_ci va_list ap_save; 114113498266Sopenharmony_ci char *s; 114213498266Sopenharmony_ci va_start(ap_save, format); 114313498266Sopenharmony_ci s = curl_mvaprintf(format, ap_save); 114413498266Sopenharmony_ci va_end(ap_save); 114513498266Sopenharmony_ci return s; 114613498266Sopenharmony_ci} 114713498266Sopenharmony_ci 114813498266Sopenharmony_cistatic int storebuffer(unsigned char outc, void *f) 114913498266Sopenharmony_ci{ 115013498266Sopenharmony_ci char **buffer = f; 115113498266Sopenharmony_ci **buffer = outc; 115213498266Sopenharmony_ci (*buffer)++; 115313498266Sopenharmony_ci return 0; 115413498266Sopenharmony_ci} 115513498266Sopenharmony_ci 115613498266Sopenharmony_ciint curl_msprintf(char *buffer, const char *format, ...) 115713498266Sopenharmony_ci{ 115813498266Sopenharmony_ci va_list ap_save; /* argument pointer */ 115913498266Sopenharmony_ci int retcode; 116013498266Sopenharmony_ci va_start(ap_save, format); 116113498266Sopenharmony_ci retcode = formatf(&buffer, storebuffer, format, ap_save); 116213498266Sopenharmony_ci va_end(ap_save); 116313498266Sopenharmony_ci *buffer = 0; /* we terminate this with a zero byte */ 116413498266Sopenharmony_ci return retcode; 116513498266Sopenharmony_ci} 116613498266Sopenharmony_ci 116713498266Sopenharmony_cistatic int fputc_wrapper(unsigned char outc, void *f) 116813498266Sopenharmony_ci{ 116913498266Sopenharmony_ci int out = outc; 117013498266Sopenharmony_ci FILE *s = f; 117113498266Sopenharmony_ci int rc = fputc(out, s); 117213498266Sopenharmony_ci if(rc == out) 117313498266Sopenharmony_ci return 0; 117413498266Sopenharmony_ci return 1; 117513498266Sopenharmony_ci} 117613498266Sopenharmony_ci 117713498266Sopenharmony_ciint curl_mprintf(const char *format, ...) 117813498266Sopenharmony_ci{ 117913498266Sopenharmony_ci int retcode; 118013498266Sopenharmony_ci va_list ap_save; /* argument pointer */ 118113498266Sopenharmony_ci va_start(ap_save, format); 118213498266Sopenharmony_ci 118313498266Sopenharmony_ci retcode = formatf(stdout, fputc_wrapper, format, ap_save); 118413498266Sopenharmony_ci va_end(ap_save); 118513498266Sopenharmony_ci return retcode; 118613498266Sopenharmony_ci} 118713498266Sopenharmony_ci 118813498266Sopenharmony_ciint curl_mfprintf(FILE *whereto, const char *format, ...) 118913498266Sopenharmony_ci{ 119013498266Sopenharmony_ci int retcode; 119113498266Sopenharmony_ci va_list ap_save; /* argument pointer */ 119213498266Sopenharmony_ci va_start(ap_save, format); 119313498266Sopenharmony_ci retcode = formatf(whereto, fputc_wrapper, format, ap_save); 119413498266Sopenharmony_ci va_end(ap_save); 119513498266Sopenharmony_ci return retcode; 119613498266Sopenharmony_ci} 119713498266Sopenharmony_ci 119813498266Sopenharmony_ciint curl_mvsprintf(char *buffer, const char *format, va_list ap_save) 119913498266Sopenharmony_ci{ 120013498266Sopenharmony_ci int retcode = formatf(&buffer, storebuffer, format, ap_save); 120113498266Sopenharmony_ci *buffer = 0; /* we terminate this with a zero byte */ 120213498266Sopenharmony_ci return retcode; 120313498266Sopenharmony_ci} 120413498266Sopenharmony_ci 120513498266Sopenharmony_ciint curl_mvprintf(const char *format, va_list ap_save) 120613498266Sopenharmony_ci{ 120713498266Sopenharmony_ci return formatf(stdout, fputc_wrapper, format, ap_save); 120813498266Sopenharmony_ci} 120913498266Sopenharmony_ci 121013498266Sopenharmony_ciint curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) 121113498266Sopenharmony_ci{ 121213498266Sopenharmony_ci return formatf(whereto, fputc_wrapper, format, ap_save); 121313498266Sopenharmony_ci} 1214