vsnprintf.c 21 KB

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