mprintf.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219
  1. /****************************************************************************
  2. *
  3. * $Id$
  4. *
  5. *************************************************************************
  6. *
  7. * Permission to use, copy, modify, and distribute this software for any
  8. * purpose with or without fee is hereby granted, provided that the above
  9. * copyright notice and this permission notice appear in all copies.
  10. *
  11. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  12. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  13. * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
  14. * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
  15. *
  16. * Purpose:
  17. * A merge of Bjorn Reese's format() function and Daniel's dsprintf()
  18. * 1.0. A full blooded printf() clone with full support for <num>$
  19. * everywhere (parameters, widths and precisions) including variabled
  20. * sized parameters (like doubles, long longs, long doubles and even
  21. * void * in 64-bit architectures).
  22. *
  23. * Current restrictions:
  24. * - Max 128 parameters
  25. * - No 'long double' support.
  26. *
  27. * If you ever want truly portable and good *printf() clones, the project that
  28. * took on from here is named 'Trio' and you find more details on the trio web
  29. * page at http://daniel.haxx.se/trio/
  30. */
  31. #include "setup.h"
  32. #include <sys/types.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <stdarg.h>
  36. #include <ctype.h>
  37. #include <string.h>
  38. #include <curl/mprintf.h>
  39. #ifndef SIZEOF_LONG_DOUBLE
  40. #define SIZEOF_LONG_DOUBLE 0
  41. #endif
  42. #ifndef SIZEOF_SIZE_T
  43. /* default to 4 bytes for size_t unless defined in the config.h */
  44. #define SIZEOF_SIZE_T 4
  45. #endif
  46. #ifdef DPRINTF_DEBUG
  47. #define HAVE_LONGLONG
  48. #define LONG_LONG long long
  49. #define ENABLE_64BIT
  50. #endif
  51. #include "curl_memory.h"
  52. /* The last #include file should be: */
  53. #include "memdebug.h"
  54. #define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
  55. #define MAX_PARAMETERS 128 /* lame static limit */
  56. #undef TRUE
  57. #undef FALSE
  58. #undef BOOL
  59. #ifdef __cplusplus
  60. # define TRUE true
  61. # define FALSE false
  62. # define BOOL bool
  63. #else
  64. # define TRUE ((char)(1 == 1))
  65. # define FALSE ((char)(0 == 1))
  66. # define BOOL char
  67. #endif
  68. /* Lower-case digits. */
  69. static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  70. /* Upper-case digits. */
  71. static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  72. #define OUTCHAR(x) \
  73. do{ \
  74. if(stream((unsigned char)(x), (FILE *)data) != -1) \
  75. done++; \
  76. else \
  77. return done; /* return immediately on failure */ \
  78. } while(0)
  79. /* Data type to read from the arglist */
  80. typedef enum {
  81. FORMAT_UNKNOWN = 0,
  82. FORMAT_STRING,
  83. FORMAT_PTR,
  84. FORMAT_INT,
  85. FORMAT_INTPTR,
  86. FORMAT_LONG,
  87. FORMAT_LONGLONG,
  88. FORMAT_DOUBLE,
  89. FORMAT_LONGDOUBLE,
  90. FORMAT_WIDTH /* For internal use */
  91. } FormatType;
  92. /* convertion and display flags */
  93. enum {
  94. FLAGS_NEW = 0,
  95. FLAGS_SPACE = 1<<0,
  96. FLAGS_SHOWSIGN = 1<<1,
  97. FLAGS_LEFT = 1<<2,
  98. FLAGS_ALT = 1<<3,
  99. FLAGS_SHORT = 1<<4,
  100. FLAGS_LONG = 1<<5,
  101. FLAGS_LONGLONG = 1<<6,
  102. FLAGS_LONGDOUBLE = 1<<7,
  103. FLAGS_PAD_NIL = 1<<8,
  104. FLAGS_UNSIGNED = 1<<9,
  105. FLAGS_OCTAL = 1<<10,
  106. FLAGS_HEX = 1<<11,
  107. FLAGS_UPPER = 1<<12,
  108. FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */
  109. FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
  110. FLAGS_PREC = 1<<15, /* precision was specified */
  111. FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */
  112. FLAGS_CHAR = 1<<17, /* %c story */
  113. FLAGS_FLOATE = 1<<18, /* %e or %E */
  114. FLAGS_FLOATG = 1<<19 /* %g or %G */
  115. };
  116. typedef struct {
  117. FormatType type;
  118. int flags;
  119. long width; /* width OR width parameter number */
  120. long precision; /* precision OR precision parameter number */
  121. union {
  122. char *str;
  123. void *ptr;
  124. long num;
  125. #ifdef ENABLE_64BIT
  126. LONG_LONG lnum;
  127. #endif
  128. double dnum;
  129. } data;
  130. } va_stack_t;
  131. struct nsprintf {
  132. char *buffer;
  133. size_t length;
  134. size_t max;
  135. };
  136. struct asprintf {
  137. char *buffer; /* allocated buffer */
  138. size_t len; /* length of string */
  139. size_t alloc; /* length of alloc */
  140. bool fail; /* TRUE if an alloc has failed and thus the output is not
  141. the complete data */
  142. };
  143. int curl_msprintf(char *buffer, const char *format, ...);
  144. static long dprintf_DollarString(char *input, char **end)
  145. {
  146. int number=0;
  147. while(isdigit((int)*input)) {
  148. number *= 10;
  149. number += *input-'0';
  150. input++;
  151. }
  152. if(number && ('$'==*input++)) {
  153. *end = input;
  154. return number;
  155. }
  156. return 0;
  157. }
  158. static BOOL dprintf_IsQualifierNoDollar(char c)
  159. {
  160. switch (c) {
  161. case '-': case '+': case ' ': case '#': case '.':
  162. case '0': case '1': case '2': case '3': case '4':
  163. case '5': case '6': case '7': case '8': case '9':
  164. case 'h': case 'l': case 'L': case 'z': case 'q':
  165. case '*': case 'O':
  166. return TRUE;
  167. default:
  168. return FALSE;
  169. }
  170. }
  171. #ifdef DPRINTF_DEBUG2
  172. int dprintf_Pass1Report(va_stack_t *vto, int max)
  173. {
  174. int i;
  175. char buffer[128];
  176. int bit;
  177. int flags;
  178. for(i=0; i<max; i++) {
  179. char *type;
  180. switch(vto[i].type) {
  181. case FORMAT_UNKNOWN:
  182. type = "unknown";
  183. break;
  184. case FORMAT_STRING:
  185. type ="string";
  186. break;
  187. case FORMAT_PTR:
  188. type ="pointer";
  189. break;
  190. case FORMAT_INT:
  191. type = "int";
  192. break;
  193. case FORMAT_LONG:
  194. type = "long";
  195. break;
  196. case FORMAT_LONGLONG:
  197. type = "long long";
  198. break;
  199. case FORMAT_DOUBLE:
  200. type = "double";
  201. break;
  202. case FORMAT_LONGDOUBLE:
  203. type = "long double";
  204. break;
  205. }
  206. buffer[0]=0;
  207. for(bit=0; bit<31; bit++) {
  208. flags = vto[i].flags & (1<<bit);
  209. if(flags & FLAGS_SPACE)
  210. strcat(buffer, "space ");
  211. else if(flags & FLAGS_SHOWSIGN)
  212. strcat(buffer, "plus ");
  213. else if(flags & FLAGS_LEFT)
  214. strcat(buffer, "left ");
  215. else if(flags & FLAGS_ALT)
  216. strcat(buffer, "alt ");
  217. else if(flags & FLAGS_SHORT)
  218. strcat(buffer, "short ");
  219. else if(flags & FLAGS_LONG)
  220. strcat(buffer, "long ");
  221. else if(flags & FLAGS_LONGLONG)
  222. strcat(buffer, "longlong ");
  223. else if(flags & FLAGS_LONGDOUBLE)
  224. strcat(buffer, "longdouble ");
  225. else if(flags & FLAGS_PAD_NIL)
  226. strcat(buffer, "padnil ");
  227. else if(flags & FLAGS_UNSIGNED)
  228. strcat(buffer, "unsigned ");
  229. else if(flags & FLAGS_OCTAL)
  230. strcat(buffer, "octal ");
  231. else if(flags & FLAGS_HEX)
  232. strcat(buffer, "hex ");
  233. else if(flags & FLAGS_UPPER)
  234. strcat(buffer, "upper ");
  235. else if(flags & FLAGS_WIDTH)
  236. strcat(buffer, "width ");
  237. else if(flags & FLAGS_WIDTHPARAM)
  238. strcat(buffer, "widthparam ");
  239. else if(flags & FLAGS_PREC)
  240. strcat(buffer, "precision ");
  241. else if(flags & FLAGS_PRECPARAM)
  242. strcat(buffer, "precparam ");
  243. else if(flags & FLAGS_CHAR)
  244. strcat(buffer, "char ");
  245. else if(flags & FLAGS_FLOATE)
  246. strcat(buffer, "floate ");
  247. else if(flags & FLAGS_FLOATG)
  248. strcat(buffer, "floatg ");
  249. }
  250. printf("REPORT: %d. %s [%s]\n", i, type, buffer);
  251. }
  252. }
  253. #endif
  254. /******************************************************************
  255. *
  256. * Pass 1:
  257. * Create an index with the type of each parameter entry and its
  258. * value (may vary in size)
  259. *
  260. ******************************************************************/
  261. static long dprintf_Pass1(char *format, va_stack_t *vto, char **endpos,
  262. va_list arglist)
  263. {
  264. char *fmt = format;
  265. int param_num = 0;
  266. long this_param;
  267. long width;
  268. long precision;
  269. int flags;
  270. long max_param=0;
  271. long i;
  272. while (*fmt) {
  273. if (*fmt++ == '%') {
  274. if (*fmt == '%') {
  275. fmt++;
  276. continue; /* while */
  277. }
  278. flags = FLAGS_NEW;
  279. /* Handle the positional case (N$) */
  280. param_num++;
  281. this_param = dprintf_DollarString(fmt, &fmt);
  282. if (0 == this_param)
  283. /* we got no positional, get the next counter */
  284. this_param = param_num;
  285. if (this_param > max_param)
  286. max_param = this_param;
  287. /*
  288. * The parameter with number 'i' should be used. Next, we need
  289. * to get SIZE and TYPE of the parameter. Add the information
  290. * to our array.
  291. */
  292. width = 0;
  293. precision = 0;
  294. /* Handle the flags */
  295. while (dprintf_IsQualifierNoDollar(*fmt)) {
  296. switch (*fmt++) {
  297. case ' ':
  298. flags |= FLAGS_SPACE;
  299. break;
  300. case '+':
  301. flags |= FLAGS_SHOWSIGN;
  302. break;
  303. case '-':
  304. flags |= FLAGS_LEFT;
  305. flags &= ~FLAGS_PAD_NIL;
  306. break;
  307. case '#':
  308. flags |= FLAGS_ALT;
  309. break;
  310. case '.':
  311. flags |= FLAGS_PREC;
  312. if ('*' == *fmt) {
  313. /* The precision is picked from a specified parameter */
  314. flags |= FLAGS_PRECPARAM;
  315. fmt++;
  316. param_num++;
  317. i = dprintf_DollarString(fmt, &fmt);
  318. if (i)
  319. precision = i;
  320. else
  321. precision = param_num;
  322. if (precision > max_param)
  323. max_param = precision;
  324. }
  325. else {
  326. flags |= FLAGS_PREC;
  327. precision = strtol(fmt, &fmt, 10);
  328. }
  329. break;
  330. case 'h':
  331. flags |= FLAGS_SHORT;
  332. break;
  333. case 'l':
  334. if (flags & FLAGS_LONG)
  335. flags |= FLAGS_LONGLONG;
  336. else
  337. flags |= FLAGS_LONG;
  338. break;
  339. case 'L':
  340. flags |= FLAGS_LONGDOUBLE;
  341. break;
  342. case 'q':
  343. flags |= FLAGS_LONGLONG;
  344. break;
  345. case 'z':
  346. /* the code below generates a warning if -Wunreachable-code is
  347. used */
  348. #if SIZEOF_SIZE_T>4
  349. flags |= FLAGS_LONGLONG;
  350. #else
  351. flags |= FLAGS_LONG;
  352. #endif
  353. break;
  354. case 'O':
  355. #if SIZEOF_CURL_OFF_T > 4
  356. flags |= FLAGS_LONGLONG;
  357. #else
  358. flags |= FLAGS_LONG;
  359. #endif
  360. break;
  361. case '0':
  362. if (!(flags & FLAGS_LEFT))
  363. flags |= FLAGS_PAD_NIL;
  364. /* FALLTHROUGH */
  365. case '1': case '2': case '3': case '4':
  366. case '5': case '6': case '7': case '8': case '9':
  367. flags |= FLAGS_WIDTH;
  368. width = strtol(fmt-1, &fmt, 10);
  369. break;
  370. case '*': /* Special case */
  371. flags |= FLAGS_WIDTHPARAM;
  372. param_num++;
  373. i = dprintf_DollarString(fmt, &fmt);
  374. if(i)
  375. width = i;
  376. else
  377. width = param_num;
  378. if(width > max_param)
  379. max_param=width;
  380. break;
  381. default:
  382. break;
  383. }
  384. } /* switch */
  385. /* Handle the specifier */
  386. i = this_param - 1;
  387. switch (*fmt) {
  388. case 'S':
  389. flags |= FLAGS_ALT;
  390. /* FALLTHROUGH */
  391. case 's':
  392. vto[i].type = FORMAT_STRING;
  393. break;
  394. case 'n':
  395. vto[i].type = FORMAT_INTPTR;
  396. break;
  397. case 'p':
  398. vto[i].type = FORMAT_PTR;
  399. break;
  400. case 'd': case 'i':
  401. vto[i].type = FORMAT_INT;
  402. break;
  403. case 'u':
  404. vto[i].type = FORMAT_INT;
  405. flags |= FLAGS_UNSIGNED;
  406. break;
  407. case 'o':
  408. vto[i].type = FORMAT_INT;
  409. flags |= FLAGS_OCTAL;
  410. break;
  411. case 'x':
  412. vto[i].type = FORMAT_INT;
  413. flags |= FLAGS_HEX;
  414. break;
  415. case 'X':
  416. vto[i].type = FORMAT_INT;
  417. flags |= FLAGS_HEX|FLAGS_UPPER;
  418. break;
  419. case 'c':
  420. vto[i].type = FORMAT_INT;
  421. flags |= FLAGS_CHAR;
  422. break;
  423. case 'f':
  424. vto[i].type = FORMAT_DOUBLE;
  425. break;
  426. case 'e':
  427. vto[i].type = FORMAT_DOUBLE;
  428. flags |= FLAGS_FLOATE;
  429. break;
  430. case 'E':
  431. vto[i].type = FORMAT_DOUBLE;
  432. flags |= FLAGS_FLOATE|FLAGS_UPPER;
  433. break;
  434. case 'g':
  435. vto[i].type = FORMAT_DOUBLE;
  436. flags |= FLAGS_FLOATG;
  437. break;
  438. case 'G':
  439. vto[i].type = FORMAT_DOUBLE;
  440. flags |= FLAGS_FLOATG|FLAGS_UPPER;
  441. break;
  442. default:
  443. vto[i].type = FORMAT_UNKNOWN;
  444. break;
  445. } /* switch */
  446. vto[i].flags = flags;
  447. vto[i].width = width;
  448. vto[i].precision = precision;
  449. if (flags & FLAGS_WIDTHPARAM) {
  450. /* we have the width specified from a parameter, so we make that
  451. parameter's info setup properly */
  452. vto[i].width = width - 1;
  453. i = width - 1;
  454. vto[i].type = FORMAT_WIDTH;
  455. vto[i].flags = FLAGS_NEW;
  456. vto[i].precision = vto[i].width = 0; /* can't use width or precision
  457. of width! */
  458. }
  459. if (flags & FLAGS_PRECPARAM) {
  460. /* we have the precision specified from a parameter, so we make that
  461. parameter's info setup properly */
  462. vto[i].precision = precision - 1;
  463. i = precision - 1;
  464. vto[i].type = FORMAT_WIDTH;
  465. vto[i].flags = FLAGS_NEW;
  466. vto[i].precision = vto[i].width = 0; /* can't use width or precision
  467. of width! */
  468. }
  469. *endpos++ = fmt + 1; /* end of this sequence */
  470. }
  471. }
  472. #ifdef DPRINTF_DEBUG2
  473. dprintf_Pass1Report(vto, max_param);
  474. #endif
  475. /* Read the arg list parameters into our data list */
  476. for (i=0; i<max_param; i++) {
  477. if ((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH))
  478. {
  479. /* Width/precision arguments must be read before the main argument
  480. * they are attached to
  481. */
  482. vto[i + 1].data.num = va_arg(arglist, int);
  483. }
  484. switch (vto[i].type)
  485. {
  486. case FORMAT_STRING:
  487. vto[i].data.str = va_arg(arglist, char *);
  488. break;
  489. case FORMAT_INTPTR:
  490. case FORMAT_UNKNOWN:
  491. case FORMAT_PTR:
  492. vto[i].data.ptr = va_arg(arglist, void *);
  493. break;
  494. case FORMAT_INT:
  495. #ifdef ENABLE_64BIT
  496. if(vto[i].flags & FLAGS_LONGLONG)
  497. vto[i].data.lnum = va_arg(arglist, LONG_LONG);
  498. else
  499. #endif
  500. if(vto[i].flags & FLAGS_LONG)
  501. vto[i].data.num = va_arg(arglist, long);
  502. else
  503. vto[i].data.num = va_arg(arglist, int);
  504. break;
  505. case FORMAT_DOUBLE:
  506. vto[i].data.dnum = va_arg(arglist, double);
  507. break;
  508. case FORMAT_WIDTH:
  509. /* Argument has been read. Silently convert it into an integer
  510. * for later use
  511. */
  512. vto[i].type = FORMAT_INT;
  513. break;
  514. default:
  515. break;
  516. }
  517. }
  518. return max_param;
  519. }
  520. static int dprintf_formatf(
  521. void *data, /* untouched by format(), just sent to the stream() function in
  522. the second argument */
  523. /* function pointer called for each output character */
  524. int (*stream)(int, FILE *),
  525. const char *format, /* %-formatted string */
  526. va_list ap_save) /* list of parameters */
  527. {
  528. /* Base-36 digits for numbers. */
  529. const char *digits = lower_digits;
  530. /* Pointer into the format string. */
  531. char *f;
  532. /* Number of characters written. */
  533. int done = 0;
  534. long param; /* current parameter to read */
  535. long param_num=0; /* parameter counter */
  536. va_stack_t vto[MAX_PARAMETERS];
  537. char *endpos[MAX_PARAMETERS];
  538. char **end;
  539. char work[BUFFSIZE];
  540. va_stack_t *p;
  541. /* Do the actual %-code parsing */
  542. dprintf_Pass1((char *)format, vto, endpos, ap_save);
  543. end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
  544. created for us */
  545. f = (char *)format;
  546. while (*f != '\0') {
  547. /* Format spec modifiers. */
  548. char alt;
  549. /* Width of a field. */
  550. long width;
  551. /* Precision of a field. */
  552. long prec;
  553. /* Decimal integer is negative. */
  554. char is_neg;
  555. /* Base of a number to be written. */
  556. long base;
  557. /* Integral values to be written. */
  558. #ifdef ENABLE_64BIT
  559. unsigned LONG_LONG num;
  560. #else
  561. unsigned long num;
  562. #endif
  563. long signed_num;
  564. if (*f != '%') {
  565. /* This isn't a format spec, so write everything out until the next one
  566. OR end of string is reached. */
  567. do {
  568. OUTCHAR(*f);
  569. } while(*++f && ('%' != *f));
  570. continue;
  571. }
  572. ++f;
  573. /* Check for "%%". Note that although the ANSI standard lists
  574. '%' as a conversion specifier, it says "The complete format
  575. specification shall be `%%'," so we can avoid all the width
  576. and precision processing. */
  577. if (*f == '%') {
  578. ++f;
  579. OUTCHAR('%');
  580. continue;
  581. }
  582. /* If this is a positional parameter, the position must follow imediately
  583. after the %, thus create a %<num>$ sequence */
  584. param=dprintf_DollarString(f, &f);
  585. if(!param)
  586. param = param_num;
  587. else
  588. --param;
  589. param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
  590. third %s will pick the 3rd argument */
  591. p = &vto[param];
  592. /* pick up the specified width */
  593. if(p->flags & FLAGS_WIDTHPARAM)
  594. width = vto[p->width].data.num;
  595. else
  596. width = p->width;
  597. /* pick up the specified precision */
  598. if(p->flags & FLAGS_PRECPARAM)
  599. prec = vto[p->precision].data.num;
  600. else if(p->flags & FLAGS_PREC)
  601. prec = p->precision;
  602. else
  603. prec = -1;
  604. alt = (p->flags & FLAGS_ALT)?TRUE:FALSE;
  605. switch (p->type) {
  606. case FORMAT_INT:
  607. num = p->data.num;
  608. if(p->flags & FLAGS_CHAR) {
  609. /* Character. */
  610. if (!(p->flags & FLAGS_LEFT))
  611. while (--width > 0)
  612. OUTCHAR(' ');
  613. OUTCHAR((char) num);
  614. if (p->flags & FLAGS_LEFT)
  615. while (--width > 0)
  616. OUTCHAR(' ');
  617. break;
  618. }
  619. if(p->flags & FLAGS_UNSIGNED) {
  620. /* Decimal unsigned integer. */
  621. base = 10;
  622. goto unsigned_number;
  623. }
  624. if(p->flags & FLAGS_OCTAL) {
  625. /* Octal unsigned integer. */
  626. base = 8;
  627. goto unsigned_number;
  628. }
  629. if(p->flags & FLAGS_HEX) {
  630. /* Hexadecimal unsigned integer. */
  631. digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
  632. base = 16;
  633. goto unsigned_number;
  634. }
  635. /* Decimal integer. */
  636. base = 10;
  637. #ifdef ENABLE_64BIT
  638. if(p->flags & FLAGS_LONGLONG) {
  639. /* long long */
  640. is_neg = p->data.lnum < 0;
  641. num = is_neg ? (- p->data.lnum) : p->data.lnum;
  642. }
  643. else
  644. #endif
  645. {
  646. signed_num = (long) num;
  647. is_neg = signed_num < 0;
  648. num = is_neg ? (- signed_num) : signed_num;
  649. }
  650. goto number;
  651. unsigned_number:
  652. /* Unsigned number of base BASE. */
  653. is_neg = 0;
  654. number:
  655. /* Number of base BASE. */
  656. {
  657. char *workend = &work[sizeof(work) - 1];
  658. char *w;
  659. /* Supply a default precision if none was given. */
  660. if (prec == -1)
  661. prec = 1;
  662. /* Put the number in WORK. */
  663. w = workend;
  664. while (num > 0) {
  665. *w-- = digits[num % base];
  666. num /= base;
  667. }
  668. width -= workend - w;
  669. prec -= workend - w;
  670. if (alt && base == 8 && prec <= 0) {
  671. *w-- = '0';
  672. --width;
  673. }
  674. if (prec > 0) {
  675. width -= prec;
  676. while (prec-- > 0)
  677. *w-- = '0';
  678. }
  679. if (alt && base == 16)
  680. width -= 2;
  681. if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
  682. --width;
  683. if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
  684. while (width-- > 0)
  685. OUTCHAR(' ');
  686. if (is_neg)
  687. OUTCHAR('-');
  688. else if (p->flags & FLAGS_SHOWSIGN)
  689. OUTCHAR('+');
  690. else if (p->flags & FLAGS_SPACE)
  691. OUTCHAR(' ');
  692. if (alt && base == 16) {
  693. OUTCHAR('0');
  694. if(p->flags & FLAGS_UPPER)
  695. OUTCHAR('X');
  696. else
  697. OUTCHAR('x');
  698. }
  699. if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
  700. while (width-- > 0)
  701. OUTCHAR('0');
  702. /* Write the number. */
  703. while (++w <= workend) {
  704. OUTCHAR(*w);
  705. }
  706. if (p->flags & FLAGS_LEFT)
  707. while (width-- > 0)
  708. OUTCHAR(' ');
  709. }
  710. break;
  711. case FORMAT_STRING:
  712. /* String. */
  713. {
  714. static char null[] = "(nil)";
  715. char *str;
  716. size_t len;
  717. str = (char *) p->data.str;
  718. if ( str == NULL) {
  719. /* Write null[] if there's space. */
  720. if (prec == -1 || prec >= (long) sizeof(null) - 1) {
  721. str = null;
  722. len = sizeof(null) - 1;
  723. /* Disable quotes around (nil) */
  724. p->flags &= (~FLAGS_ALT);
  725. }
  726. else {
  727. str = (char *)"";
  728. len = 0;
  729. }
  730. }
  731. else
  732. len = strlen(str);
  733. if (prec != -1 && (size_t) prec < len)
  734. len = prec;
  735. width -= len;
  736. if (p->flags & FLAGS_ALT)
  737. OUTCHAR('"');
  738. if (!(p->flags&FLAGS_LEFT))
  739. while (width-- > 0)
  740. OUTCHAR(' ');
  741. while (len-- > 0)
  742. OUTCHAR(*str++);
  743. if (p->flags&FLAGS_LEFT)
  744. while (width-- > 0)
  745. OUTCHAR(' ');
  746. if (p->flags & FLAGS_ALT)
  747. OUTCHAR('"');
  748. }
  749. break;
  750. case FORMAT_PTR:
  751. /* Generic pointer. */
  752. {
  753. void *ptr;
  754. ptr = (void *) p->data.ptr;
  755. if (ptr != NULL) {
  756. /* If the pointer is not NULL, write it as a %#x spec. */
  757. base = 16;
  758. digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
  759. alt = 1;
  760. num = (unsigned long) ptr;
  761. is_neg = 0;
  762. goto number;
  763. }
  764. else {
  765. /* Write "(nil)" for a nil pointer. */
  766. static char strnil[] = "(nil)";
  767. char *point;
  768. width -= sizeof(strnil) - 1;
  769. if (p->flags & FLAGS_LEFT)
  770. while (width-- > 0)
  771. OUTCHAR(' ');
  772. for (point = strnil; *point != '\0'; ++point)
  773. OUTCHAR(*point);
  774. if (! (p->flags & FLAGS_LEFT))
  775. while (width-- > 0)
  776. OUTCHAR(' ');
  777. }
  778. }
  779. break;
  780. case FORMAT_DOUBLE:
  781. {
  782. char formatbuf[32]="%";
  783. char *fptr;
  784. size_t left = sizeof(formatbuf)-strlen(formatbuf);
  785. int len;
  786. width = -1;
  787. if (p->flags & FLAGS_WIDTH)
  788. width = p->width;
  789. else if (p->flags & FLAGS_WIDTHPARAM)
  790. width = vto[p->width].data.num;
  791. prec = -1;
  792. if (p->flags & FLAGS_PREC)
  793. prec = p->precision;
  794. else if (p->flags & FLAGS_PRECPARAM)
  795. prec = vto[p->precision].data.num;
  796. if (p->flags & FLAGS_LEFT)
  797. strcat(formatbuf, "-");
  798. if (p->flags & FLAGS_SHOWSIGN)
  799. strcat(formatbuf, "+");
  800. if (p->flags & FLAGS_SPACE)
  801. strcat(formatbuf, " ");
  802. if (p->flags & FLAGS_ALT)
  803. strcat(formatbuf, "#");
  804. fptr=&formatbuf[strlen(formatbuf)];
  805. if(width >= 0) {
  806. /* RECURSIVE USAGE */
  807. len = curl_msnprintf(fptr, left, "%ld", width);
  808. fptr += len;
  809. left -= len;
  810. }
  811. if(prec >= 0) {
  812. /* RECURSIVE USAGE */
  813. len = curl_msnprintf(fptr, left, ".%ld", prec);
  814. fptr += len;
  815. left -= len;
  816. }
  817. (void)left;
  818. if (p->flags & FLAGS_LONG)
  819. *fptr++ = 'l';
  820. if (p->flags & FLAGS_FLOATE)
  821. *fptr++ = p->flags&FLAGS_UPPER ? 'E':'e';
  822. else if (p->flags & FLAGS_FLOATG)
  823. *fptr++ = p->flags & FLAGS_UPPER ? 'G' : 'g';
  824. else
  825. *fptr++ = 'f';
  826. *fptr = 0; /* and a final zero termination */
  827. /* NOTE NOTE NOTE!! Not all sprintf() implementations returns number
  828. of output characters */
  829. (sprintf)(work, formatbuf, p->data.dnum);
  830. for(fptr=work; *fptr; fptr++)
  831. OUTCHAR(*fptr);
  832. }
  833. break;
  834. case FORMAT_INTPTR:
  835. /* Answer the count of characters written. */
  836. #ifdef ENABLE_64BIT
  837. if (p->flags & FLAGS_LONGLONG)
  838. *(LONG_LONG *) p->data.ptr = (LONG_LONG)done;
  839. else
  840. #endif
  841. if (p->flags & FLAGS_LONG)
  842. *(long *) p->data.ptr = (long)done;
  843. else if (!(p->flags & FLAGS_SHORT))
  844. *(int *) p->data.ptr = (int)done;
  845. else
  846. *(short *) p->data.ptr = (short)done;
  847. break;
  848. default:
  849. break;
  850. }
  851. f = *end++; /* goto end of %-code */
  852. }
  853. return done;
  854. }
  855. /* fputc() look-alike */
  856. static int addbyter(int output, FILE *data)
  857. {
  858. struct nsprintf *infop=(struct nsprintf *)data;
  859. unsigned char outc = (unsigned char)output;
  860. if(infop->length < infop->max) {
  861. /* only do this if we haven't reached max length yet */
  862. infop->buffer[0] = outc; /* store */
  863. infop->buffer++; /* increase pointer */
  864. infop->length++; /* we are now one byte larger */
  865. return outc; /* fputc() returns like this on success */
  866. }
  867. return -1;
  868. }
  869. int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
  870. va_list ap_save)
  871. {
  872. int retcode;
  873. struct nsprintf info;
  874. info.buffer = buffer;
  875. info.length = 0;
  876. info.max = maxlength;
  877. retcode = dprintf_formatf(&info, addbyter, format, ap_save);
  878. if(info.max) {
  879. /* we terminate this with a zero byte */
  880. if(info.max == info.length)
  881. /* we're at maximum, scrap the last letter */
  882. info.buffer[-1] = 0;
  883. else
  884. info.buffer[0] = 0;
  885. }
  886. return retcode;
  887. }
  888. int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
  889. {
  890. int retcode;
  891. va_list ap_save; /* argument pointer */
  892. va_start(ap_save, format);
  893. retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
  894. va_end(ap_save);
  895. return retcode;
  896. }
  897. /* fputc() look-alike */
  898. static int alloc_addbyter(int output, FILE *data)
  899. {
  900. struct asprintf *infop=(struct asprintf *)data;
  901. unsigned char outc = (unsigned char)output;
  902. if(!infop->buffer) {
  903. infop->buffer=(char *)malloc(32);
  904. if(!infop->buffer) {
  905. infop->fail = TRUE;
  906. return -1; /* fail */
  907. }
  908. infop->alloc = 32;
  909. infop->len =0;
  910. }
  911. else if(infop->len+1 >= infop->alloc) {
  912. char *newptr;
  913. newptr = (char *)realloc(infop->buffer, infop->alloc*2);
  914. if(!newptr) {
  915. infop->fail = TRUE;
  916. return -1;
  917. }
  918. infop->buffer = newptr;
  919. infop->alloc *= 2;
  920. }
  921. infop->buffer[ infop->len ] = outc;
  922. infop->len++;
  923. return outc; /* fputc() returns like this on success */
  924. }
  925. char *curl_maprintf(const char *format, ...)
  926. {
  927. va_list ap_save; /* argument pointer */
  928. int retcode;
  929. struct asprintf info;
  930. info.buffer = NULL;
  931. info.len = 0;
  932. info.alloc = 0;
  933. info.fail = FALSE;
  934. va_start(ap_save, format);
  935. retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
  936. va_end(ap_save);
  937. if((-1 == retcode) || info.fail) {
  938. if(info.alloc)
  939. free(info.buffer);
  940. return NULL;
  941. }
  942. if(info.alloc) {
  943. info.buffer[info.len] = 0; /* we terminate this with a zero byte */
  944. return info.buffer;
  945. }
  946. else
  947. return strdup("");
  948. }
  949. char *curl_mvaprintf(const char *format, va_list ap_save)
  950. {
  951. int retcode;
  952. struct asprintf info;
  953. info.buffer = NULL;
  954. info.len = 0;
  955. info.alloc = 0;
  956. info.fail = FALSE;
  957. retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
  958. if((-1 == retcode) || info.fail) {
  959. if(info.alloc)
  960. free(info.buffer);
  961. return NULL;
  962. }
  963. if(info.alloc) {
  964. info.buffer[info.len] = 0; /* we terminate this with a zero byte */
  965. return info.buffer;
  966. }
  967. else
  968. return strdup("");
  969. }
  970. static int storebuffer(int output, FILE *data)
  971. {
  972. char **buffer = (char **)data;
  973. unsigned char outc = (unsigned char)output;
  974. **buffer = outc;
  975. (*buffer)++;
  976. return outc; /* act like fputc() ! */
  977. }
  978. int curl_msprintf(char *buffer, const char *format, ...)
  979. {
  980. va_list ap_save; /* argument pointer */
  981. int retcode;
  982. va_start(ap_save, format);
  983. retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
  984. va_end(ap_save);
  985. *buffer=0; /* we terminate this with a zero byte */
  986. return retcode;
  987. }
  988. #if !defined( WIN32) || defined(__UCLIBC__) /* not needed on win32 */
  989. extern int fputc(int, FILE *);
  990. #endif
  991. int curl_mprintf(const char *format, ...)
  992. {
  993. int retcode;
  994. va_list ap_save; /* argument pointer */
  995. va_start(ap_save, format);
  996. retcode = dprintf_formatf(stdout, fputc, format, ap_save);
  997. va_end(ap_save);
  998. return retcode;
  999. }
  1000. int curl_mfprintf(FILE *whereto, const char *format, ...)
  1001. {
  1002. int retcode;
  1003. va_list ap_save; /* argument pointer */
  1004. va_start(ap_save, format);
  1005. retcode = dprintf_formatf(whereto, fputc, format, ap_save);
  1006. va_end(ap_save);
  1007. return retcode;
  1008. }
  1009. int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
  1010. {
  1011. int retcode;
  1012. retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
  1013. *buffer=0; /* we terminate this with a zero byte */
  1014. return retcode;
  1015. }
  1016. int curl_mvprintf(const char *format, va_list ap_save)
  1017. {
  1018. return dprintf_formatf(stdout, fputc, format, ap_save);
  1019. }
  1020. int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
  1021. {
  1022. return dprintf_formatf(whereto, fputc, format, ap_save);
  1023. }
  1024. #ifdef DPRINTF_DEBUG
  1025. int main()
  1026. {
  1027. char buffer[129];
  1028. char *ptr;
  1029. #ifdef ENABLE_64BIT
  1030. long long one=99;
  1031. long long two=100;
  1032. long long test = 0x1000000000LL;
  1033. curl_mprintf("%lld %lld %lld\n", one, two, test);
  1034. #endif
  1035. curl_mprintf("%3d %5d\n", 10, 1998);
  1036. ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001);
  1037. puts(ptr);
  1038. memset(ptr, 55, strlen(ptr)+1);
  1039. free(ptr);
  1040. #if 1
  1041. curl_mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988);
  1042. puts(buffer);
  1043. curl_mfprintf(stderr, "%s %#08x\n", "dummy", 65);
  1044. printf("%s %#08x\n", "dummy", 65);
  1045. {
  1046. double tryout = 3.14156592;
  1047. curl_mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout);
  1048. puts(buffer);
  1049. printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout);
  1050. }
  1051. #endif
  1052. return 0;
  1053. }
  1054. #endif