mprintf.c 29 KB

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