mprintf.c 32 KB

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