snprintf.c 24 KB

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