snprintf.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  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. #if SIZEOF_LONG_LONG
  133. #define LLONG long long
  134. #else
  135. #define LLONG long
  136. #endif
  137. #ifndef VA_COPY
  138. #if defined HAVE_VA_COPY || defined 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)) {
  583. if (i != 0) {
  584. double i2;
  585. double ret;
  586. ret = my_modf(x0-l*f, &i2);
  587. (*iptr) = l*f + i2;
  588. return ret;
  589. }
  590. (*iptr) = l;
  591. return x - (*iptr);
  592. }
  593. x *= 0.1;
  594. f *= 10.0;
  595. }
  596. /* yikes! the number is beyond what we can handle. What do we do? */
  597. (*iptr) = 0;
  598. return 0;
  599. }
  600. static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
  601. LDOUBLE fvalue, int min, int max, int flags)
  602. {
  603. int signvalue = 0;
  604. double ufvalue;
  605. char iconvert[311];
  606. char fconvert[311];
  607. int iplace = 0;
  608. int fplace = 0;
  609. int padlen = 0; /* amount to pad */
  610. int zpadlen = 0;
  611. int caps = 0;
  612. int idx;
  613. double intpart;
  614. double fracpart;
  615. double temp;
  616. /*
  617. * AIX manpage says the default is 0, but Solaris says the default
  618. * is 6, and sprintf on AIX defaults to 6
  619. */
  620. if (max < 0)
  621. max = 6;
  622. ufvalue = abs_val (fvalue);
  623. if (fvalue < 0) {
  624. signvalue = '-';
  625. } else {
  626. if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
  627. signvalue = '+';
  628. } else {
  629. if (flags & DP_F_SPACE)
  630. signvalue = ' ';
  631. }
  632. }
  633. #if 0
  634. if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
  635. #endif
  636. #if 0
  637. if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
  638. #endif
  639. /*
  640. * Sorry, we only support 16 digits past the decimal because of our
  641. * conversion method
  642. */
  643. if (max > 16)
  644. max = 16;
  645. /* We "cheat" by converting the fractional part to integer by
  646. * multiplying by a factor of 10
  647. */
  648. temp = ufvalue;
  649. my_modf(temp, &intpart);
  650. fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
  651. if (fracpart >= POW10(max)) {
  652. intpart++;
  653. fracpart -= POW10(max);
  654. }
  655. /* Convert integer part */
  656. do {
  657. temp = intpart*0.1;
  658. my_modf(temp, &intpart);
  659. idx = (int) ((temp -intpart +0.05)* 10.0);
  660. /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
  661. /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
  662. iconvert[iplace++] =
  663. (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
  664. } while (intpart && (iplace < 311));
  665. if (iplace == 311) iplace--;
  666. iconvert[iplace] = 0;
  667. /* Convert fractional part */
  668. if (fracpart)
  669. {
  670. do {
  671. temp = fracpart*0.1;
  672. my_modf(temp, &fracpart);
  673. idx = (int) ((temp -fracpart +0.05)* 10.0);
  674. /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
  675. /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
  676. fconvert[fplace++] =
  677. (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
  678. } while(fracpart && (fplace < 311));
  679. if (fplace == 311) fplace--;
  680. }
  681. fconvert[fplace] = 0;
  682. /* -1 for decimal point, another -1 if we are printing a sign */
  683. padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
  684. zpadlen = max - fplace;
  685. if (zpadlen < 0) zpadlen = 0;
  686. if (padlen < 0)
  687. padlen = 0;
  688. if (flags & DP_F_MINUS)
  689. padlen = -padlen; /* Left Justifty */
  690. if ((flags & DP_F_ZERO) && (padlen > 0)) {
  691. if (signvalue) {
  692. dopr_outch (buffer, currlen, maxlen, signvalue);
  693. --padlen;
  694. signvalue = 0;
  695. }
  696. while (padlen > 0) {
  697. dopr_outch (buffer, currlen, maxlen, '0');
  698. --padlen;
  699. }
  700. }
  701. while (padlen > 0) {
  702. dopr_outch (buffer, currlen, maxlen, ' ');
  703. --padlen;
  704. }
  705. if (signvalue)
  706. dopr_outch (buffer, currlen, maxlen, signvalue);
  707. while (iplace > 0)
  708. dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
  709. #ifdef DEBUG_SNPRINTF
  710. printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
  711. #endif
  712. /*
  713. * Decimal point. This should probably use locale to find the correct
  714. * char to print out.
  715. */
  716. if (max > 0) {
  717. dopr_outch (buffer, currlen, maxlen, '.');
  718. while (zpadlen > 0) {
  719. dopr_outch (buffer, currlen, maxlen, '0');
  720. --zpadlen;
  721. }
  722. while (fplace > 0)
  723. dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
  724. }
  725. while (padlen < 0) {
  726. dopr_outch (buffer, currlen, maxlen, ' ');
  727. ++padlen;
  728. }
  729. }
  730. static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
  731. {
  732. if (*currlen < maxlen) {
  733. buffer[(*currlen)] = c;
  734. }
  735. (*currlen)++;
  736. }
  737. int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
  738. {
  739. return dopr(str, count, fmt, args);
  740. }
  741. #define vsnprintf rsync_vsnprintf
  742. #endif
  743. /* yes this really must be a ||. Don't muck with this (tridge)
  744. *
  745. * The logic for these two is that we need our own definition if the
  746. * OS *either* has no definition of *sprintf, or if it does have one
  747. * that doesn't work properly according to the autoconf test.
  748. */
  749. #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
  750. int rsync_snprintf(char *str,size_t count,const char *fmt,...)
  751. {
  752. size_t ret;
  753. va_list ap;
  754. va_start(ap, fmt);
  755. ret = vsnprintf(str, count, fmt, ap);
  756. va_end(ap);
  757. return ret;
  758. }
  759. #define snprintf rsync_snprintf
  760. #endif
  761. #endif
  762. #ifndef HAVE_VASPRINTF
  763. int vasprintf(char **ptr, const char *format, va_list ap)
  764. {
  765. int ret;
  766. va_list ap2;
  767. VA_COPY(ap2, ap);
  768. ret = vsnprintf(NULL, 0, format, ap2);
  769. if (ret <= 0) return ret;
  770. (*ptr) = (char *)malloc(ret+1);
  771. if (!*ptr) return -1;
  772. VA_COPY(ap2, ap);
  773. ret = vsnprintf(*ptr, ret+1, format, ap2);
  774. return ret;
  775. }
  776. #endif
  777. #ifndef HAVE_ASPRINTF
  778. int asprintf(char **ptr, const char *format, ...)
  779. {
  780. va_list ap;
  781. int ret;
  782. *ptr = NULL;
  783. va_start(ap, format);
  784. ret = vasprintf(ptr, format, ap);
  785. va_end(ap);
  786. return ret;
  787. }
  788. #endif
  789. #ifdef TEST_SNPRINTF
  790. int sprintf(char *str,const char *fmt,...);
  791. int main (void)
  792. {
  793. char buf1[1024];
  794. char buf2[1024];
  795. char *fp_fmt[] = {
  796. "%1.1f",
  797. "%-1.5f",
  798. "%1.5f",
  799. "%123.9f",
  800. "%10.5f",
  801. "% 10.5f",
  802. "%+22.9f",
  803. "%+4.9f",
  804. "%01.3f",
  805. "%4f",
  806. "%3.1f",
  807. "%3.2f",
  808. "%.0f",
  809. "%f",
  810. "-16.16f",
  811. NULL
  812. };
  813. double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
  814. 0.9996, 1.996, 4.136, 5.030201, 0.00205,
  815. /* END LIST */ 0};
  816. char *int_fmt[] = {
  817. "%-1.5d",
  818. "%1.5d",
  819. "%123.9d",
  820. "%5.5d",
  821. "%10.5d",
  822. "% 10.5d",
  823. "%+22.33d",
  824. "%01.3d",
  825. "%4d",
  826. "%d",
  827. NULL
  828. };
  829. long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
  830. char *str_fmt[] = {
  831. "10.5s",
  832. "5.10s",
  833. "10.1s",
  834. "0.10s",
  835. "10.0s",
  836. "1.10s",
  837. "%s",
  838. "%.1s",
  839. "%.10s",
  840. "%10s",
  841. NULL
  842. };
  843. char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
  844. int x, y;
  845. int fail = 0;
  846. int num = 0;
  847. printf ("Testing snprintf format codes against system sprintf...\n");
  848. for (x = 0; fp_fmt[x] ; x++) {
  849. for (y = 0; fp_nums[y] != 0 ; y++) {
  850. int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
  851. int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
  852. sprintf (buf2, fp_fmt[x], fp_nums[y]);
  853. if (strcmp (buf1, buf2)) {
  854. printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
  855. fp_fmt[x], buf1, buf2);
  856. fail++;
  857. }
  858. if (l1 != l2) {
  859. printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
  860. fail++;
  861. }
  862. num++;
  863. }
  864. }
  865. for (x = 0; int_fmt[x] ; x++) {
  866. for (y = 0; int_nums[y] != 0 ; y++) {
  867. int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
  868. int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
  869. sprintf (buf2, int_fmt[x], int_nums[y]);
  870. if (strcmp (buf1, buf2)) {
  871. printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
  872. int_fmt[x], buf1, buf2);
  873. fail++;
  874. }
  875. if (l1 != l2) {
  876. printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
  877. fail++;
  878. }
  879. num++;
  880. }
  881. }
  882. for (x = 0; str_fmt[x] ; x++) {
  883. for (y = 0; str_vals[y] != 0 ; y++) {
  884. int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
  885. int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
  886. sprintf (buf2, str_fmt[x], str_vals[y]);
  887. if (strcmp (buf1, buf2)) {
  888. printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
  889. str_fmt[x], buf1, buf2);
  890. fail++;
  891. }
  892. if (l1 != l2) {
  893. printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
  894. fail++;
  895. }
  896. num++;
  897. }
  898. }
  899. printf ("%d tests failed out of %d.\n", fail, num);
  900. printf("seeing how many digits we support\n");
  901. {
  902. double v0 = 0.12345678901234567890123456789012345678901;
  903. for (x=0; x<100; x++) {
  904. double p = pow(10, x);
  905. double r = v0*p;
  906. snprintf(buf1, sizeof(buf1), "%1.1f", r);
  907. sprintf(buf2, "%1.1f", r);
  908. if (strcmp(buf1, buf2)) {
  909. printf("we seem to support %d digits\n", x-1);
  910. break;
  911. }
  912. }
  913. }
  914. return 0;
  915. }
  916. #endif /* TEST_SNPRINTF */