1
0

snprintf.c 18 KB

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