vsnprintf.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * Please read the file COPYING, README and AUTHORS for more information.
  10. *
  11. * snprintf() and vsnprintf() replacement functions
  12. */
  13. #include "portab.h"
  14. static char UNUSED id[] = "$Id: vsnprintf.c,v 1.5 2003/04/21 10:53:38 alex Exp $";
  15. #include "imp.h"
  16. #include "exp.h"
  17. /*
  18. * snprintf.c: Copyright Patrick Powell 1995
  19. * This code is based on code written by Patrick Powell (papowell@astart.com)
  20. * It may be used for any purpose as long as this notice remains intact
  21. * on all source code distributions
  22. *
  23. * Original: Patrick Powell Tue Apr 11 09:48:21 PDT 1995
  24. * A bombproof version of doprnt (dopr) included.
  25. * Sigh. This sort of thing is always nasty do deal with. Note that
  26. * the version here does not include floating point...
  27. *
  28. * snprintf() is used instead of sprintf() as it does limit checks
  29. * for string length. This covers a nasty loophole.
  30. *
  31. * The other functions are there to prevent NULL pointers from
  32. * causing nast effects.
  33. *
  34. * More Recently:
  35. * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
  36. * This was ugly. It is still ugly. I opted out of floating point
  37. * numbers, but the formatter understands just about everything
  38. * from the normal C string format, at least as far as I can tell from
  39. * the Solaris 2.5 printf(3S) man page.
  40. *
  41. * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
  42. * Ok, added some minimal floating point support, which means this
  43. * probably requires libm on most operating systems. Don't yet
  44. * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
  45. * was pretty badly broken, it just wasn't being exercised in ways
  46. * which showed it, so that's been fixed. Also, formated the code
  47. * to mutt conventions, and removed dead code left over from the
  48. * original. Also, there is now a builtin-test, just compile with:
  49. * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
  50. * and run snprintf for results.
  51. *
  52. * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
  53. * The PGP code was using unsigned hexadecimal formats.
  54. * Unfortunately, unsigned formats simply didn't work.
  55. *
  56. * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
  57. * The original code assumed that both snprintf() and vsnprintf() were
  58. * missing. Some systems only have snprintf() but not vsnprintf(), so
  59. * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
  60. *
  61. * Andrew Tridgell <tridge@samba.org>, October 1998
  62. * fixed handling of %.0f
  63. * added test for HAVE_LONG_DOUBLE
  64. *
  65. * tridge@samba.org, idra@samba.org, April 2001
  66. * got rid of fcvt code (twas buggy and made testing harder)
  67. * added C99 semantics
  68. *
  69. * Alexander Barton, <alex@barton.de>, 2002-05-19
  70. * removed [v]asprintf() and C99 tests: not needed by ngIRCd.
  71. */
  72. #ifdef HAVE_STRING_H
  73. #include <string.h>
  74. #endif
  75. #ifdef HAVE_STRINGS_H
  76. #include <strings.h>
  77. #endif
  78. #ifdef HAVE_CTYPE_H
  79. #include <ctype.h>
  80. #endif
  81. #include <sys/types.h>
  82. #include <stdarg.h>
  83. #ifdef HAVE_STDLIB_H
  84. #include <stdlib.h>
  85. #endif
  86. #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF)
  87. /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
  88. #include <stdio.h>
  89. /* make the compiler happy with an empty file */
  90. void dummy_snprintf PARAMS(( void ));
  91. void dummy_snprintf PARAMS(( void )) { }
  92. #else
  93. #ifdef HAVE_LONG_DOUBLE
  94. #define LDOUBLE long double
  95. #else
  96. #define LDOUBLE double
  97. #endif
  98. #ifdef HAVE_LONG_LONG
  99. #define LLONG long long
  100. #else
  101. #define LLONG long
  102. #endif
  103. static size_t dopr(char *buffer, size_t maxlen, const char *format,
  104. va_list args);
  105. static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
  106. char *value, int flags, int min, int max);
  107. static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
  108. long value, int base, int min, int max, int flags);
  109. static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
  110. LDOUBLE fvalue, int min, int max, int flags);
  111. static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
  112. /*
  113. * dopr(): poor man's version of doprintf
  114. */
  115. /* format read states */
  116. #define DP_S_DEFAULT 0
  117. #define DP_S_FLAGS 1
  118. #define DP_S_MIN 2
  119. #define DP_S_DOT 3
  120. #define DP_S_MAX 4
  121. #define DP_S_MOD 5
  122. #define DP_S_CONV 6
  123. #define DP_S_DONE 7
  124. /* format flags - Bits */
  125. #define DP_F_MINUS (1 << 0)
  126. #define DP_F_PLUS (1 << 1)
  127. #define DP_F_SPACE (1 << 2)
  128. #define DP_F_NUM (1 << 3)
  129. #define DP_F_ZERO (1 << 4)
  130. #define DP_F_UP (1 << 5)
  131. #define DP_F_UNSIGNED (1 << 6)
  132. /* Conversion Flags */
  133. #define DP_C_SHORT 1
  134. #define DP_C_LONG 2
  135. #define DP_C_LDOUBLE 3
  136. #define DP_C_LLONG 4
  137. #define char_to_int(p) ((p)- '0')
  138. #ifndef MAX
  139. #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
  140. #endif
  141. static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
  142. {
  143. char ch;
  144. LLONG value;
  145. LDOUBLE fvalue;
  146. char *strvalue;
  147. int min;
  148. int max;
  149. int state;
  150. int flags;
  151. int cflags;
  152. size_t currlen;
  153. state = DP_S_DEFAULT;
  154. currlen = flags = cflags = min = 0;
  155. max = -1;
  156. ch = *format++;
  157. while (state != DP_S_DONE) {
  158. if (ch == '\0')
  159. state = DP_S_DONE;
  160. switch(state) {
  161. case DP_S_DEFAULT:
  162. if (ch == '%')
  163. state = DP_S_FLAGS;
  164. else
  165. dopr_outch (buffer, &currlen, maxlen, ch);
  166. ch = *format++;
  167. break;
  168. case DP_S_FLAGS:
  169. switch (ch) {
  170. case '-':
  171. flags |= DP_F_MINUS;
  172. ch = *format++;
  173. break;
  174. case '+':
  175. flags |= DP_F_PLUS;
  176. ch = *format++;
  177. break;
  178. case ' ':
  179. flags |= DP_F_SPACE;
  180. ch = *format++;
  181. break;
  182. case '#':
  183. flags |= DP_F_NUM;
  184. ch = *format++;
  185. break;
  186. case '0':
  187. flags |= DP_F_ZERO;
  188. ch = *format++;
  189. break;
  190. default:
  191. state = DP_S_MIN;
  192. break;
  193. }
  194. break;
  195. case DP_S_MIN:
  196. if (isdigit((unsigned char)ch)) {
  197. min = 10*min + char_to_int (ch);
  198. ch = *format++;
  199. } else if (ch == '*') {
  200. min = va_arg (args, int);
  201. ch = *format++;
  202. state = DP_S_DOT;
  203. } else {
  204. state = DP_S_DOT;
  205. }
  206. break;
  207. case DP_S_DOT:
  208. if (ch == '.') {
  209. state = DP_S_MAX;
  210. ch = *format++;
  211. } else {
  212. state = DP_S_MOD;
  213. }
  214. break;
  215. case DP_S_MAX:
  216. if (isdigit((unsigned char)ch)) {
  217. if (max < 0)
  218. max = 0;
  219. max = 10*max + char_to_int (ch);
  220. ch = *format++;
  221. } else if (ch == '*') {
  222. max = va_arg (args, int);
  223. ch = *format++;
  224. state = DP_S_MOD;
  225. } else {
  226. state = DP_S_MOD;
  227. }
  228. break;
  229. case DP_S_MOD:
  230. switch (ch) {
  231. case 'h':
  232. cflags = DP_C_SHORT;
  233. ch = *format++;
  234. break;
  235. case 'l':
  236. cflags = DP_C_LONG;
  237. ch = *format++;
  238. if (ch == 'l') { /* It's a long long */
  239. cflags = DP_C_LLONG;
  240. ch = *format++;
  241. }
  242. break;
  243. case 'L':
  244. cflags = DP_C_LDOUBLE;
  245. ch = *format++;
  246. break;
  247. default:
  248. break;
  249. }
  250. state = DP_S_CONV;
  251. break;
  252. case DP_S_CONV:
  253. switch (ch) {
  254. case 'd':
  255. case 'i':
  256. if (cflags == DP_C_SHORT)
  257. value = va_arg (args, int);
  258. else if (cflags == DP_C_LONG)
  259. value = va_arg (args, long int);
  260. else if (cflags == DP_C_LLONG)
  261. value = va_arg (args, LLONG);
  262. else
  263. value = va_arg (args, int);
  264. fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
  265. break;
  266. case 'o':
  267. flags |= DP_F_UNSIGNED;
  268. if (cflags == DP_C_SHORT)
  269. value = va_arg (args, unsigned int);
  270. else if (cflags == DP_C_LONG)
  271. value = (long)va_arg (args, unsigned long int);
  272. else if (cflags == DP_C_LLONG)
  273. value = (long)va_arg (args, unsigned LLONG);
  274. else
  275. value = (long)va_arg (args, unsigned int);
  276. fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
  277. break;
  278. case 'u':
  279. flags |= DP_F_UNSIGNED;
  280. if (cflags == DP_C_SHORT)
  281. value = va_arg (args, unsigned int);
  282. else if (cflags == DP_C_LONG)
  283. value = (long)va_arg (args, unsigned long int);
  284. else if (cflags == DP_C_LLONG)
  285. value = (LLONG)va_arg (args, unsigned LLONG);
  286. else
  287. value = (long)va_arg (args, unsigned int);
  288. fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
  289. break;
  290. case 'X':
  291. flags |= DP_F_UP;
  292. case 'x':
  293. flags |= DP_F_UNSIGNED;
  294. if (cflags == DP_C_SHORT)
  295. value = va_arg (args, unsigned int);
  296. else if (cflags == DP_C_LONG)
  297. value = (long)va_arg (args, unsigned long int);
  298. else if (cflags == DP_C_LLONG)
  299. value = (LLONG)va_arg (args, unsigned LLONG);
  300. else
  301. value = (long)va_arg (args, unsigned int);
  302. fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
  303. break;
  304. case 'f':
  305. if (cflags == DP_C_LDOUBLE)
  306. fvalue = va_arg (args, LDOUBLE);
  307. else
  308. fvalue = va_arg (args, double);
  309. /* um, floating point? */
  310. fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
  311. break;
  312. case 'E':
  313. flags |= DP_F_UP;
  314. case 'e':
  315. if (cflags == DP_C_LDOUBLE)
  316. fvalue = va_arg (args, LDOUBLE);
  317. else
  318. fvalue = va_arg (args, double);
  319. break;
  320. case 'G':
  321. flags |= DP_F_UP;
  322. case 'g':
  323. if (cflags == DP_C_LDOUBLE)
  324. fvalue = va_arg (args, LDOUBLE);
  325. else
  326. fvalue = va_arg (args, double);
  327. break;
  328. case 'c':
  329. dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
  330. break;
  331. case 's':
  332. strvalue = va_arg (args, char *);
  333. if (max == -1) {
  334. max = strlen(strvalue);
  335. }
  336. if (min > 0 && max >= 0 && min > max) max = min;
  337. fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
  338. break;
  339. case 'p':
  340. strvalue = va_arg (args, void *);
  341. fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
  342. break;
  343. case 'n':
  344. if (cflags == DP_C_SHORT) {
  345. short int *num;
  346. num = va_arg (args, short int *);
  347. *num = currlen;
  348. } else if (cflags == DP_C_LONG) {
  349. long int *num;
  350. num = va_arg (args, long int *);
  351. *num = (long int)currlen;
  352. } else if (cflags == DP_C_LLONG) {
  353. LLONG *num;
  354. num = va_arg (args, LLONG *);
  355. *num = (LLONG)currlen;
  356. } else {
  357. int *num;
  358. num = va_arg (args, int *);
  359. *num = currlen;
  360. }
  361. break;
  362. case '%':
  363. dopr_outch (buffer, &currlen, maxlen, ch);
  364. break;
  365. case 'w':
  366. /* not supported yet, treat as next char */
  367. ch = *format++;
  368. break;
  369. default:
  370. /* Unknown, skip */
  371. break;
  372. }
  373. ch = *format++;
  374. state = DP_S_DEFAULT;
  375. flags = cflags = min = 0;
  376. max = -1;
  377. break;
  378. case DP_S_DONE:
  379. break;
  380. default:
  381. /* hmm? */
  382. break; /* some picky compilers need this */
  383. }
  384. }
  385. if (maxlen != 0) {
  386. if (currlen < maxlen - 1)
  387. buffer[currlen] = '\0';
  388. else if (maxlen > 0)
  389. buffer[maxlen - 1] = '\0';
  390. }
  391. return currlen;
  392. }
  393. static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
  394. char *value, int flags, int min, int max)
  395. {
  396. int padlen, strln; /* amount to pad */
  397. int cnt = 0;
  398. #ifdef DEBUG_SNPRINTF
  399. printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
  400. #endif
  401. if (value == 0) {
  402. value = "<NULL>";
  403. }
  404. for (strln = 0; value[strln]; ++strln); /* strlen */
  405. padlen = min - strln;
  406. if (padlen < 0)
  407. padlen = 0;
  408. if (flags & DP_F_MINUS)
  409. padlen = -padlen; /* Left Justify */
  410. while ((padlen > 0) && (cnt < max)) {
  411. dopr_outch (buffer, currlen, maxlen, ' ');
  412. --padlen;
  413. ++cnt;
  414. }
  415. while (*value && (cnt < max)) {
  416. dopr_outch (buffer, currlen, maxlen, *value++);
  417. ++cnt;
  418. }
  419. while ((padlen < 0) && (cnt < max)) {
  420. dopr_outch (buffer, currlen, maxlen, ' ');
  421. ++padlen;
  422. ++cnt;
  423. }
  424. }
  425. /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
  426. static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
  427. long value, int base, int min, int max, int flags)
  428. {
  429. int signvalue = 0;
  430. unsigned long uvalue;
  431. char convert[20];
  432. int place = 0;
  433. int spadlen = 0; /* amount to space pad */
  434. int zpadlen = 0; /* amount to zero pad */
  435. int caps = 0;
  436. if (max < 0)
  437. max = 0;
  438. uvalue = value;
  439. if(!(flags & DP_F_UNSIGNED)) {
  440. if( value < 0 ) {
  441. signvalue = '-';
  442. uvalue = -value;
  443. } else {
  444. if (flags & DP_F_PLUS) /* Do a sign (+/i) */
  445. signvalue = '+';
  446. else if (flags & DP_F_SPACE)
  447. signvalue = ' ';
  448. }
  449. }
  450. if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
  451. do {
  452. convert[place++] =
  453. (caps? "0123456789ABCDEF":"0123456789abcdef")
  454. [uvalue % (unsigned)base ];
  455. uvalue = (uvalue / (unsigned)base );
  456. } while(uvalue && (place < 20));
  457. if (place == 20) place--;
  458. convert[place] = 0;
  459. zpadlen = max - place;
  460. spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
  461. if (zpadlen < 0) zpadlen = 0;
  462. if (spadlen < 0) spadlen = 0;
  463. if (flags & DP_F_ZERO) {
  464. zpadlen = MAX(zpadlen, spadlen);
  465. spadlen = 0;
  466. }
  467. if (flags & DP_F_MINUS)
  468. spadlen = -spadlen; /* Left Justifty */
  469. #ifdef DEBUG_SNPRINTF
  470. printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
  471. zpadlen, spadlen, min, max, place);
  472. #endif
  473. /* Spaces */
  474. while (spadlen > 0) {
  475. dopr_outch (buffer, currlen, maxlen, ' ');
  476. --spadlen;
  477. }
  478. /* Sign */
  479. if (signvalue)
  480. dopr_outch (buffer, currlen, maxlen, signvalue);
  481. /* Zeros */
  482. if (zpadlen > 0) {
  483. while (zpadlen > 0) {
  484. dopr_outch (buffer, currlen, maxlen, '0');
  485. --zpadlen;
  486. }
  487. }
  488. /* Digits */
  489. while (place > 0)
  490. dopr_outch (buffer, currlen, maxlen, convert[--place]);
  491. /* Left Justified spaces */
  492. while (spadlen < 0) {
  493. dopr_outch (buffer, currlen, maxlen, ' ');
  494. ++spadlen;
  495. }
  496. }
  497. static LDOUBLE abs_val(LDOUBLE value)
  498. {
  499. LDOUBLE result = value;
  500. if (value < 0)
  501. result = -value;
  502. return result;
  503. }
  504. static LDOUBLE POW10(int exp)
  505. {
  506. LDOUBLE result = 1;
  507. while (exp) {
  508. result *= 10;
  509. exp--;
  510. }
  511. return result;
  512. }
  513. static LLONG ROUND(LDOUBLE value)
  514. {
  515. LLONG intpart;
  516. intpart = (LLONG)value;
  517. value = value - intpart;
  518. if (value >= 0.5) intpart++;
  519. return intpart;
  520. }
  521. /* a replacement for modf that doesn't need the math library. Should
  522. be portable, but slow */
  523. static double my_modf(double x0, double *iptr)
  524. {
  525. int i;
  526. long l;
  527. double x = x0;
  528. double f = 1.0;
  529. for (i=0;i<100;i++) {
  530. l = (long)x;
  531. if (l <= (x+1) && l >= (x-1)) break;
  532. x *= 0.1;
  533. f *= 10.0;
  534. }
  535. if (i == 100) {
  536. /* yikes! the number is beyond what we can handle. What do we do? */
  537. (*iptr) = 0;
  538. return 0;
  539. }
  540. if (i != 0) {
  541. double i2;
  542. double ret;
  543. ret = my_modf(x0-l*f, &i2);
  544. (*iptr) = l*f + i2;
  545. return ret;
  546. }
  547. (*iptr) = l;
  548. return x - (*iptr);
  549. }
  550. static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
  551. LDOUBLE fvalue, int min, int max, int flags)
  552. {
  553. int signvalue = 0;
  554. double ufvalue;
  555. char iconvert[311];
  556. char fconvert[311];
  557. int iplace = 0;
  558. int fplace = 0;
  559. int padlen = 0; /* amount to pad */
  560. int zpadlen = 0;
  561. int caps = 0;
  562. int index;
  563. double intpart;
  564. double fracpart;
  565. double temp;
  566. /*
  567. * AIX manpage says the default is 0, but Solaris says the default
  568. * is 6, and sprintf on AIX defaults to 6
  569. */
  570. if (max < 0)
  571. max = 6;
  572. ufvalue = abs_val (fvalue);
  573. if (fvalue < 0) {
  574. signvalue = '-';
  575. } else {
  576. if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
  577. signvalue = '+';
  578. } else {
  579. if (flags & DP_F_SPACE)
  580. signvalue = ' ';
  581. }
  582. }
  583. #if 0
  584. if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
  585. #endif
  586. #if 0
  587. if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
  588. #endif
  589. /*
  590. * Sorry, we only support 16 digits past the decimal because of our
  591. * conversion method
  592. */
  593. if (max > 16)
  594. max = 16;
  595. /* We "cheat" by converting the fractional part to integer by
  596. * multiplying by a factor of 10
  597. */
  598. temp = ufvalue;
  599. my_modf(temp, &intpart);
  600. fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
  601. if (fracpart >= POW10(max)) {
  602. intpart++;
  603. fracpart -= POW10(max);
  604. }
  605. /* Convert integer part */
  606. do {
  607. temp = intpart;
  608. my_modf(intpart*0.1, &intpart);
  609. temp = temp*0.1;
  610. index = (int) ((temp -intpart +0.05)* 10.0);
  611. /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
  612. /* printf ("%llf, %f, %x\n", temp, intpart, index); */
  613. iconvert[iplace++] =
  614. (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
  615. } while (intpart && (iplace < 311));
  616. if (iplace == 311) iplace--;
  617. iconvert[iplace] = 0;
  618. /* Convert fractional part */
  619. if (fracpart)
  620. {
  621. do {
  622. temp = fracpart;
  623. my_modf(fracpart*0.1, &fracpart);
  624. temp = temp*0.1;
  625. index = (int) ((temp -fracpart +0.05)* 10.0);
  626. /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
  627. /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
  628. fconvert[fplace++] =
  629. (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
  630. } while(fracpart && (fplace < 311));
  631. if (fplace == 311) fplace--;
  632. }
  633. fconvert[fplace] = 0;
  634. /* -1 for decimal point, another -1 if we are printing a sign */
  635. padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
  636. zpadlen = max - fplace;
  637. if (zpadlen < 0) zpadlen = 0;
  638. if (padlen < 0)
  639. padlen = 0;
  640. if (flags & DP_F_MINUS)
  641. padlen = -padlen; /* Left Justifty */
  642. if ((flags & DP_F_ZERO) && (padlen > 0)) {
  643. if (signvalue) {
  644. dopr_outch (buffer, currlen, maxlen, signvalue);
  645. --padlen;
  646. signvalue = 0;
  647. }
  648. while (padlen > 0) {
  649. dopr_outch (buffer, currlen, maxlen, '0');
  650. --padlen;
  651. }
  652. }
  653. while (padlen > 0) {
  654. dopr_outch (buffer, currlen, maxlen, ' ');
  655. --padlen;
  656. }
  657. if (signvalue)
  658. dopr_outch (buffer, currlen, maxlen, signvalue);
  659. while (iplace > 0)
  660. dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
  661. #ifdef DEBUG_SNPRINTF
  662. printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
  663. #endif
  664. /*
  665. * Decimal point. This should probably use locale to find the correct
  666. * char to print out.
  667. */
  668. if (max > 0) {
  669. dopr_outch (buffer, currlen, maxlen, '.');
  670. while (fplace > 0)
  671. dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
  672. }
  673. while (zpadlen > 0) {
  674. dopr_outch (buffer, currlen, maxlen, '0');
  675. --zpadlen;
  676. }
  677. while (padlen < 0) {
  678. dopr_outch (buffer, currlen, maxlen, ' ');
  679. ++padlen;
  680. }
  681. }
  682. static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
  683. {
  684. if (*currlen < maxlen) {
  685. buffer[(*currlen)] = c;
  686. }
  687. (*currlen)++;
  688. }
  689. #if !defined(HAVE_VSNPRINTF)
  690. int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
  691. {
  692. return dopr(str, count, fmt, args);
  693. }
  694. #endif
  695. #if !defined(HAVE_SNPRINTF)
  696. int snprintf(char *str,size_t count,const char *fmt,...)
  697. {
  698. size_t ret;
  699. va_list ap;
  700. va_start(ap, fmt);
  701. ret = vsnprintf(str, count, fmt, ap);
  702. va_end(ap);
  703. return ret;
  704. }
  705. #endif
  706. #endif
  707. #ifdef TEST_SNPRINTF
  708. int sprintf(char *str,const char *fmt,...);
  709. int main (void)
  710. {
  711. char buf1[1024];
  712. char buf2[1024];
  713. char *fp_fmt[] = {
  714. "%1.1f",
  715. "%-1.5f",
  716. "%1.5f",
  717. "%123.9f",
  718. "%10.5f",
  719. "% 10.5f",
  720. "%+22.9f",
  721. "%+4.9f",
  722. "%01.3f",
  723. "%4f",
  724. "%3.1f",
  725. "%3.2f",
  726. "%.0f",
  727. "%f",
  728. "-16.16f",
  729. NULL
  730. };
  731. double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
  732. 0.9996, 1.996, 4.136, 0};
  733. char *int_fmt[] = {
  734. "%-1.5d",
  735. "%1.5d",
  736. "%123.9d",
  737. "%5.5d",
  738. "%10.5d",
  739. "% 10.5d",
  740. "%+22.33d",
  741. "%01.3d",
  742. "%4d",
  743. "%d",
  744. NULL
  745. };
  746. long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
  747. char *str_fmt[] = {
  748. "10.5s",
  749. "5.10s",
  750. "10.1s",
  751. "0.10s",
  752. "10.0s",
  753. "1.10s",
  754. "%s",
  755. "%.1s",
  756. "%.10s",
  757. "%10s",
  758. NULL
  759. };
  760. char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
  761. int x, y;
  762. int fail = 0;
  763. int num = 0;
  764. printf ("Testing snprintf format codes against system sprintf...\n");
  765. for (x = 0; fp_fmt[x] ; x++) {
  766. for (y = 0; fp_nums[y] != 0 ; y++) {
  767. int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
  768. int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
  769. sprintf (buf2, fp_fmt[x], fp_nums[y]);
  770. if (strcmp (buf1, buf2)) {
  771. printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
  772. fp_fmt[x], buf1, buf2);
  773. fail++;
  774. }
  775. if (l1 != l2) {
  776. printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
  777. fail++;
  778. }
  779. num++;
  780. }
  781. }
  782. for (x = 0; int_fmt[x] ; x++) {
  783. for (y = 0; int_nums[y] != 0 ; y++) {
  784. int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
  785. int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
  786. sprintf (buf2, int_fmt[x], int_nums[y]);
  787. if (strcmp (buf1, buf2)) {
  788. printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
  789. int_fmt[x], buf1, buf2);
  790. fail++;
  791. }
  792. if (l1 != l2) {
  793. printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
  794. fail++;
  795. }
  796. num++;
  797. }
  798. }
  799. for (x = 0; str_fmt[x] ; x++) {
  800. for (y = 0; str_vals[y] != 0 ; y++) {
  801. int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
  802. int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
  803. sprintf (buf2, str_fmt[x], str_vals[y]);
  804. if (strcmp (buf1, buf2)) {
  805. printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
  806. str_fmt[x], buf1, buf2);
  807. fail++;
  808. }
  809. if (l1 != l2) {
  810. printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
  811. fail++;
  812. }
  813. num++;
  814. }
  815. }
  816. printf ("%d tests failed out of %d.\n", fail, num);
  817. printf("seeing how many digits we support\n");
  818. {
  819. double v0 = 0.12345678901234567890123456789012345678901;
  820. for (x=0; x<100; x++) {
  821. snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
  822. sprintf(buf2, "%1.1f", v0*pow(10, x));
  823. if (strcmp(buf1, buf2)) {
  824. printf("we seem to support %d digits\n", x-1);
  825. break;
  826. }
  827. }
  828. }
  829. return 0;
  830. }
  831. #endif /* SNPRINTF_TEST */
  832. /* -eof- */