snprintf.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  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. * added 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. * Darren Tucker (dtucker@zip.com.au) 2005
  92. * Fix bug allowing read overruns of the source string with "%.*s"
  93. * Usually harmless unless the read runs outside the process' allocation
  94. * (eg if your malloc does guard pages) in which case it will segfault.
  95. * From OpenSSH. Also added test for same.
  96. *
  97. * Simo Sorce (idra@samba.org) Jan 2006
  98. *
  99. * Add support for position independent parameters
  100. * fix fmtstr now it conforms to sprintf wrt min.max
  101. *
  102. **************************************************************/
  103. #ifndef NO_CONFIG_H
  104. /* 08/13/2007 EG changed path to config.h to match NRPE distro */
  105. #include "../include/config.h"
  106. #else
  107. #define NULL 0
  108. #endif
  109. #ifdef TEST_SNPRINTF /* need math library headers for testing */
  110. /* In test mode, we pretend that this system doesn't have any snprintf
  111. * functions, regardless of what config.h says. */
  112. # undef HAVE_SNPRINTF
  113. # undef HAVE_VSNPRINTF
  114. # undef HAVE_C99_VSNPRINTF
  115. # undef HAVE_ASPRINTF
  116. # undef HAVE_VASPRINTF
  117. # include <math.h>
  118. #endif /* TEST_SNPRINTF */
  119. #ifdef HAVE_STRING_H
  120. #include <string.h>
  121. #endif
  122. #ifdef HAVE_STRINGS_H
  123. #include <strings.h>
  124. #endif
  125. #ifdef HAVE_CTYPE_H
  126. #include <ctype.h>
  127. #endif
  128. #include <sys/types.h>
  129. #include <stdarg.h>
  130. #ifdef HAVE_STDLIB_H
  131. #include <stdlib.h>
  132. #endif
  133. #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
  134. /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
  135. #include <stdio.h>
  136. /* make the compiler happy with an empty file */
  137. void dummy_snprintf(void);
  138. void dummy_snprintf(void) {}
  139. #endif /* HAVE_SNPRINTF, etc */
  140. #ifdef HAVE_LONG_DOUBLE
  141. #define LDOUBLE long double
  142. #else
  143. #define LDOUBLE double
  144. #endif
  145. #ifdef HAVE_LONG_LONG
  146. #define LLONG long long
  147. #else
  148. #define LLONG long
  149. #endif
  150. #ifndef VA_COPY
  151. #ifdef HAVE_VA_COPY
  152. #define VA_COPY(dest, src) va_copy(dest, src)
  153. #else
  154. #ifdef HAVE___VA_COPY
  155. #define VA_COPY(dest, src) __va_copy(dest, src)
  156. #else
  157. #define VA_COPY(dest, src) (dest) = (src)
  158. #endif
  159. #endif
  160. /*
  161. * dopr(): poor man's version of doprintf
  162. */
  163. /* format read states */
  164. #define DP_S_DEFAULT 0
  165. #define DP_S_FLAGS 1
  166. #define DP_S_MIN 2
  167. #define DP_S_DOT 3
  168. #define DP_S_MAX 4
  169. #define DP_S_MOD 5
  170. #define DP_S_CONV 6
  171. #define DP_S_DONE 7
  172. /* format flags - Bits */
  173. #define DP_F_MINUS (1 << 0)
  174. #define DP_F_PLUS (1 << 1)
  175. #define DP_F_SPACE (1 << 2)
  176. #define DP_F_NUM (1 << 3)
  177. #define DP_F_ZERO (1 << 4)
  178. #define DP_F_UP (1 << 5)
  179. #define DP_F_UNSIGNED (1 << 6)
  180. /* Conversion Flags */
  181. #define DP_C_CHAR 1
  182. #define DP_C_SHORT 2
  183. #define DP_C_LONG 3
  184. #define DP_C_LDOUBLE 4
  185. #define DP_C_LLONG 5
  186. /* Chunk types */
  187. #define CNK_FMT_STR 0
  188. #define CNK_INT 1
  189. #define CNK_OCTAL 2
  190. #define CNK_UINT 3
  191. #define CNK_HEX 4
  192. #define CNK_FLOAT 5
  193. #define CNK_CHAR 6
  194. #define CNK_STRING 7
  195. #define CNK_PTR 8
  196. #define CNK_NUM 9
  197. #define CNK_PRCNT 10
  198. #define char_to_int(p) ((p)- '0')
  199. #ifndef MAX
  200. #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
  201. #endif
  202. /* yes this really must be a ||. Don't muck with this (tridge) */
  203. #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
  204. struct pr_chunk {
  205. int type; /* chunk type */
  206. int num; /* parameter number */
  207. int min;
  208. int max;
  209. int flags;
  210. int cflags;
  211. int start;
  212. int len;
  213. LLONG value;
  214. LDOUBLE fvalue;
  215. char *strvalue;
  216. void *pnum;
  217. struct pr_chunk *min_star;
  218. struct pr_chunk *max_star;
  219. struct pr_chunk *next;
  220. };
  221. struct pr_chunk_x {
  222. struct pr_chunk **chunks;
  223. int num;
  224. };
  225. static size_t dopr(char *buffer, size_t maxlen, const char *format,
  226. va_list args_in);
  227. static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
  228. char *value, int flags, int min, int max);
  229. static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
  230. long value, int base, int min, int max, int flags);
  231. static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
  232. LDOUBLE fvalue, int min, int max, int flags);
  233. static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
  234. static struct pr_chunk *new_chunk(void);
  235. static int add_cnk_list_entry(struct pr_chunk_x **list,
  236. int max_num, struct pr_chunk *chunk);
  237. static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
  238. {
  239. char ch;
  240. int state;
  241. int pflag;
  242. int pnum;
  243. int pfirst;
  244. size_t currlen;
  245. va_list args;
  246. const char *base;
  247. struct pr_chunk *chunks = NULL;
  248. struct pr_chunk *cnk = NULL;
  249. struct pr_chunk_x *clist = NULL;
  250. int max_pos;
  251. size_t ret = (size_t)-1;
  252. VA_COPY(args, args_in);
  253. state = DP_S_DEFAULT;
  254. pfirst = 1;
  255. pflag = 0;
  256. pnum = 0;
  257. max_pos = 0;
  258. base = format;
  259. ch = *format++;
  260. /* retrieve the string structure as chunks */
  261. while (state != DP_S_DONE) {
  262. if (ch == '\0')
  263. state = DP_S_DONE;
  264. switch(state) {
  265. case DP_S_DEFAULT:
  266. if (cnk) {
  267. cnk->next = new_chunk();
  268. cnk = cnk->next;
  269. } else {
  270. cnk = new_chunk();
  271. }
  272. if (!cnk) goto done;
  273. if (!chunks) chunks = cnk;
  274. if (ch == '%') {
  275. state = DP_S_FLAGS;
  276. ch = *format++;
  277. } else {
  278. cnk->type = CNK_FMT_STR;
  279. cnk->start = format - base -1;
  280. while ((ch != '\0') && (ch != '%')) ch = *format++;
  281. cnk->len = format - base - cnk->start -1;
  282. }
  283. break;
  284. case DP_S_FLAGS:
  285. switch (ch) {
  286. case '-':
  287. cnk->flags |= DP_F_MINUS;
  288. ch = *format++;
  289. break;
  290. case '+':
  291. cnk->flags |= DP_F_PLUS;
  292. ch = *format++;
  293. break;
  294. case ' ':
  295. cnk->flags |= DP_F_SPACE;
  296. ch = *format++;
  297. break;
  298. case '#':
  299. cnk->flags |= DP_F_NUM;
  300. ch = *format++;
  301. break;
  302. case '0':
  303. cnk->flags |= DP_F_ZERO;
  304. ch = *format++;
  305. break;
  306. case 'I':
  307. /* internationalization not supported yet */
  308. ch = *format++;
  309. break;
  310. default:
  311. state = DP_S_MIN;
  312. break;
  313. }
  314. break;
  315. case DP_S_MIN:
  316. if (isdigit((unsigned char)ch)) {
  317. cnk->min = 10 * cnk->min + char_to_int (ch);
  318. ch = *format++;
  319. } else if (ch == '$') {
  320. if (!pfirst && !pflag) {
  321. /* parameters must be all positioned or none */
  322. goto done;
  323. }
  324. if (pfirst) {
  325. pfirst = 0;
  326. pflag = 1;
  327. }
  328. if (cnk->min == 0) /* what ?? */
  329. goto done;
  330. cnk->num = cnk->min;
  331. cnk->min = 0;
  332. ch = *format++;
  333. } else if (ch == '*') {
  334. if (pfirst) pfirst = 0;
  335. cnk->min_star = new_chunk();
  336. if (!cnk->min_star) /* out of memory :-( */
  337. goto done;
  338. cnk->min_star->type = CNK_INT;
  339. if (pflag) {
  340. int num;
  341. ch = *format++;
  342. if (!isdigit((unsigned char)ch)) {
  343. /* parameters must be all positioned or none */
  344. goto done;
  345. }
  346. for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
  347. num = 10 * num + char_to_int(ch);
  348. }
  349. cnk->min_star->num = num;
  350. if (ch != '$') /* what ?? */
  351. goto done;
  352. } else {
  353. cnk->min_star->num = ++pnum;
  354. }
  355. max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
  356. if (max_pos == 0) /* out of memory :-( */
  357. goto done;
  358. ch = *format++;
  359. state = DP_S_DOT;
  360. } else {
  361. if (pfirst) pfirst = 0;
  362. state = DP_S_DOT;
  363. }
  364. break;
  365. case DP_S_DOT:
  366. if (ch == '.') {
  367. state = DP_S_MAX;
  368. ch = *format++;
  369. } else {
  370. state = DP_S_MOD;
  371. }
  372. break;
  373. case DP_S_MAX:
  374. if (isdigit((unsigned char)ch)) {
  375. if (cnk->max < 0)
  376. cnk->max = 0;
  377. cnk->max = 10 * cnk->max + char_to_int (ch);
  378. ch = *format++;
  379. } else if (ch == '$') {
  380. if (!pfirst && !pflag) {
  381. /* parameters must be all positioned or none */
  382. goto done;
  383. }
  384. if (cnk->max <= 0) /* what ?? */
  385. goto done;
  386. cnk->num = cnk->max;
  387. cnk->max = -1;
  388. ch = *format++;
  389. } else if (ch == '*') {
  390. cnk->max_star = new_chunk();
  391. if (!cnk->max_star) /* out of memory :-( */
  392. goto done;
  393. cnk->max_star->type = CNK_INT;
  394. if (pflag) {
  395. int num;
  396. ch = *format++;
  397. if (!isdigit((unsigned char)ch)) {
  398. /* parameters must be all positioned or none */
  399. goto done;
  400. }
  401. for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
  402. num = 10 * num + char_to_int(ch);
  403. }
  404. cnk->max_star->num = num;
  405. if (ch != '$') /* what ?? */
  406. goto done;
  407. } else {
  408. cnk->max_star->num = ++pnum;
  409. }
  410. max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
  411. if (max_pos == 0) /* out of memory :-( */
  412. goto done;
  413. ch = *format++;
  414. state = DP_S_MOD;
  415. } else {
  416. state = DP_S_MOD;
  417. }
  418. break;
  419. case DP_S_MOD:
  420. switch (ch) {
  421. case 'h':
  422. cnk->cflags = DP_C_SHORT;
  423. ch = *format++;
  424. if (ch == 'h') {
  425. cnk->cflags = DP_C_CHAR;
  426. ch = *format++;
  427. }
  428. break;
  429. case 'l':
  430. cnk->cflags = DP_C_LONG;
  431. ch = *format++;
  432. if (ch == 'l') { /* It's a long long */
  433. cnk->cflags = DP_C_LLONG;
  434. ch = *format++;
  435. }
  436. break;
  437. case 'L':
  438. cnk->cflags = DP_C_LDOUBLE;
  439. ch = *format++;
  440. break;
  441. default:
  442. break;
  443. }
  444. state = DP_S_CONV;
  445. break;
  446. case DP_S_CONV:
  447. if (cnk->num == 0) cnk->num = ++pnum;
  448. max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
  449. if (max_pos == 0) /* out of memory :-( */
  450. goto done;
  451. switch (ch) {
  452. case 'd':
  453. case 'i':
  454. cnk->type = CNK_INT;
  455. break;
  456. case 'o':
  457. cnk->type = CNK_OCTAL;
  458. cnk->flags |= DP_F_UNSIGNED;
  459. break;
  460. case 'u':
  461. cnk->type = CNK_UINT;
  462. cnk->flags |= DP_F_UNSIGNED;
  463. break;
  464. case 'X':
  465. cnk->flags |= DP_F_UP;
  466. case 'x':
  467. cnk->type = CNK_HEX;
  468. cnk->flags |= DP_F_UNSIGNED;
  469. break;
  470. case 'A':
  471. /* hex float not supported yet */
  472. case 'E':
  473. case 'G':
  474. case 'F':
  475. cnk->flags |= DP_F_UP;
  476. case 'a':
  477. /* hex float not supported yet */
  478. case 'e':
  479. case 'f':
  480. case 'g':
  481. cnk->type = CNK_FLOAT;
  482. break;
  483. case 'c':
  484. cnk->type = CNK_CHAR;
  485. break;
  486. case 's':
  487. cnk->type = CNK_STRING;
  488. break;
  489. case 'p':
  490. cnk->type = CNK_PTR;
  491. break;
  492. case 'n':
  493. cnk->type = CNK_NUM;
  494. break;
  495. case '%':
  496. cnk->type = CNK_PRCNT;
  497. break;
  498. default:
  499. /* Unknown, bail out*/
  500. goto done;
  501. }
  502. ch = *format++;
  503. state = DP_S_DEFAULT;
  504. break;
  505. case DP_S_DONE:
  506. break;
  507. default:
  508. /* hmm? */
  509. break; /* some picky compilers need this */
  510. }
  511. }
  512. /* retieve the format arguments */
  513. for (pnum = 0; pnum < max_pos; pnum++) {
  514. int i;
  515. if (clist[pnum].num == 0) {
  516. /* ignoring a parameter should not be permitted
  517. * all parameters must be matched at least once
  518. * BUT seem some system ignore this rule ...
  519. * at least my glibc based system does --SSS
  520. */
  521. #ifdef DEBUG_SNPRINTF
  522. printf("parameter at position %d not used\n", pnum+1);
  523. #endif
  524. /* eat the parameter */
  525. va_arg (args, int);
  526. continue;
  527. }
  528. for (i = 1; i < clist[pnum].num; i++) {
  529. if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
  530. /* nooo noo no!
  531. * all the references to a parameter
  532. * must be of the same type
  533. */
  534. goto done;
  535. }
  536. }
  537. cnk = clist[pnum].chunks[0];
  538. switch (cnk->type) {
  539. case CNK_INT:
  540. if (cnk->cflags == DP_C_SHORT)
  541. cnk->value = va_arg (args, int);
  542. else if (cnk->cflags == DP_C_LONG)
  543. cnk->value = va_arg (args, long int);
  544. else if (cnk->cflags == DP_C_LLONG)
  545. cnk->value = va_arg (args, LLONG);
  546. else
  547. cnk->value = va_arg (args, int);
  548. for (i = 1; i < clist[pnum].num; i++) {
  549. clist[pnum].chunks[i]->value = cnk->value;
  550. }
  551. break;
  552. case CNK_OCTAL:
  553. case CNK_UINT:
  554. case CNK_HEX:
  555. if (cnk->cflags == DP_C_SHORT)
  556. cnk->value = va_arg (args, unsigned int);
  557. else if (cnk->cflags == DP_C_LONG)
  558. cnk->value = (long)va_arg (args, unsigned long int);
  559. else if (cnk->cflags == DP_C_LLONG)
  560. cnk->value = (LLONG)va_arg (args, unsigned LLONG);
  561. else
  562. cnk->value = (long)va_arg (args, unsigned int);
  563. for (i = 1; i < clist[pnum].num; i++) {
  564. clist[pnum].chunks[i]->value = cnk->value;
  565. }
  566. break;
  567. case CNK_FLOAT:
  568. if (cnk->cflags == DP_C_LDOUBLE)
  569. cnk->fvalue = va_arg (args, LDOUBLE);
  570. else
  571. cnk->fvalue = va_arg (args, double);
  572. for (i = 1; i < clist[pnum].num; i++) {
  573. clist[pnum].chunks[i]->fvalue = cnk->fvalue;
  574. }
  575. break;
  576. case CNK_CHAR:
  577. cnk->value = va_arg (args, int);
  578. for (i = 1; i < clist[pnum].num; i++) {
  579. clist[pnum].chunks[i]->value = cnk->value;
  580. }
  581. break;
  582. case CNK_STRING:
  583. cnk->strvalue = va_arg (args, char *);
  584. if (!cnk->strvalue) cnk->strvalue = "(NULL)";
  585. for (i = 1; i < clist[pnum].num; i++) {
  586. clist[pnum].chunks[i]->strvalue = cnk->strvalue;
  587. }
  588. break;
  589. case CNK_PTR:
  590. cnk->strvalue = va_arg (args, void *);
  591. for (i = 1; i < clist[pnum].num; i++) {
  592. clist[pnum].chunks[i]->strvalue = cnk->strvalue;
  593. }
  594. break;
  595. case CNK_NUM:
  596. if (cnk->cflags == DP_C_CHAR)
  597. cnk->pnum = va_arg (args, char *);
  598. else if (cnk->cflags == DP_C_SHORT)
  599. cnk->pnum = va_arg (args, short int *);
  600. else if (cnk->cflags == DP_C_LONG)
  601. cnk->pnum = va_arg (args, long int *);
  602. else if (cnk->cflags == DP_C_LLONG)
  603. cnk->pnum = va_arg (args, LLONG *);
  604. else
  605. cnk->pnum = va_arg (args, int *);
  606. for (i = 1; i < clist[pnum].num; i++) {
  607. clist[pnum].chunks[i]->pnum = cnk->pnum;
  608. }
  609. break;
  610. case CNK_PRCNT:
  611. break;
  612. default:
  613. /* what ?? */
  614. goto done;
  615. }
  616. }
  617. /* print out the actual string from chunks */
  618. currlen = 0;
  619. cnk = chunks;
  620. while (cnk) {
  621. int len, min, max;
  622. if (cnk->min_star) min = cnk->min_star->value;
  623. else min = cnk->min;
  624. if (cnk->max_star) max = cnk->max_star->value;
  625. else max = cnk->max;
  626. switch (cnk->type) {
  627. case CNK_FMT_STR:
  628. if (maxlen != 0 && maxlen > currlen) {
  629. if (maxlen > (currlen + cnk->len)) len = cnk->len;
  630. else len = maxlen - currlen;
  631. memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
  632. }
  633. currlen += cnk->len;
  634. break;
  635. case CNK_INT:
  636. case CNK_UINT:
  637. fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
  638. break;
  639. case CNK_OCTAL:
  640. fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
  641. break;
  642. case CNK_HEX:
  643. fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
  644. break;
  645. case CNK_FLOAT:
  646. fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
  647. break;
  648. case CNK_CHAR:
  649. dopr_outch (buffer, &currlen, maxlen, cnk->value);
  650. break;
  651. case CNK_STRING:
  652. if (max == -1) {
  653. max = strlen(cnk->strvalue);
  654. }
  655. fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
  656. break;
  657. case CNK_PTR:
  658. fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
  659. break;
  660. case CNK_NUM:
  661. if (cnk->cflags == DP_C_CHAR)
  662. *((char *)(cnk->pnum)) = (char)currlen;
  663. else if (cnk->cflags == DP_C_SHORT)
  664. *((short int *)(cnk->pnum)) = (short int)currlen;
  665. else if (cnk->cflags == DP_C_LONG)
  666. *((long int *)(cnk->pnum)) = (long int)currlen;
  667. else if (cnk->cflags == DP_C_LLONG)
  668. *((LLONG *)(cnk->pnum)) = (LLONG)currlen;
  669. else
  670. *((int *)(cnk->pnum)) = (int)currlen;
  671. break;
  672. case CNK_PRCNT:
  673. dopr_outch (buffer, &currlen, maxlen, '%');
  674. break;
  675. default:
  676. /* what ?? */
  677. goto done;
  678. }
  679. cnk = cnk->next;
  680. }
  681. if (maxlen != 0) {
  682. if (currlen < maxlen - 1)
  683. buffer[currlen] = '\0';
  684. else if (maxlen > 0)
  685. buffer[maxlen - 1] = '\0';
  686. }
  687. ret = currlen;
  688. done:
  689. while (chunks) {
  690. cnk = chunks->next;
  691. free(chunks);
  692. chunks = cnk;
  693. }
  694. if (clist) {
  695. for (pnum = 0; pnum < max_pos; pnum++) {
  696. if (clist[pnum].chunks) free(clist[pnum].chunks);
  697. }
  698. free(clist);
  699. }
  700. return ret;
  701. }
  702. static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
  703. char *value, int flags, int min, int max)
  704. {
  705. int padlen, strln; /* amount to pad */
  706. int cnt = 0;
  707. #ifdef DEBUG_SNPRINTF
  708. printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
  709. #endif
  710. if (value == 0) {
  711. value = "<NULL>";
  712. }
  713. for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
  714. padlen = min - strln;
  715. if (padlen < 0)
  716. padlen = 0;
  717. if (flags & DP_F_MINUS)
  718. padlen = -padlen; /* Left Justify */
  719. while (padlen > 0) {
  720. dopr_outch (buffer, currlen, maxlen, ' ');
  721. --padlen;
  722. }
  723. while (*value && (cnt < max)) {
  724. dopr_outch (buffer, currlen, maxlen, *value++);
  725. ++cnt;
  726. }
  727. while (padlen < 0) {
  728. dopr_outch (buffer, currlen, maxlen, ' ');
  729. ++padlen;
  730. }
  731. }
  732. /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
  733. static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
  734. long value, int base, int min, int max, int flags)
  735. {
  736. int signvalue = 0;
  737. unsigned long uvalue;
  738. char convert[20];
  739. int place = 0;
  740. int spadlen = 0; /* amount to space pad */
  741. int zpadlen = 0; /* amount to zero pad */
  742. int caps = 0;
  743. if (max < 0)
  744. max = 0;
  745. uvalue = value;
  746. if(!(flags & DP_F_UNSIGNED)) {
  747. if( value < 0 ) {
  748. signvalue = '-';
  749. uvalue = -value;
  750. } else {
  751. if (flags & DP_F_PLUS) /* Do a sign (+/i) */
  752. signvalue = '+';
  753. else if (flags & DP_F_SPACE)
  754. signvalue = ' ';
  755. }
  756. }
  757. if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
  758. do {
  759. convert[place++] =
  760. (caps? "0123456789ABCDEF":"0123456789abcdef")
  761. [uvalue % (unsigned)base ];
  762. uvalue = (uvalue / (unsigned)base );
  763. } while(uvalue && (place < 20));
  764. if (place == 20) place--;
  765. convert[place] = 0;
  766. zpadlen = max - place;
  767. spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
  768. if (zpadlen < 0) zpadlen = 0;
  769. if (spadlen < 0) spadlen = 0;
  770. if (flags & DP_F_ZERO) {
  771. zpadlen = MAX(zpadlen, spadlen);
  772. spadlen = 0;
  773. }
  774. if (flags & DP_F_MINUS)
  775. spadlen = -spadlen; /* Left Justify */
  776. #ifdef DEBUG_SNPRINTF
  777. printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
  778. zpadlen, spadlen, min, max, place);
  779. #endif
  780. /* Spaces */
  781. while (spadlen > 0) {
  782. dopr_outch (buffer, currlen, maxlen, ' ');
  783. --spadlen;
  784. }
  785. /* Sign */
  786. if (signvalue)
  787. dopr_outch (buffer, currlen, maxlen, signvalue);
  788. /* Zeros */
  789. if (zpadlen > 0) {
  790. while (zpadlen > 0) {
  791. dopr_outch (buffer, currlen, maxlen, '0');
  792. --zpadlen;
  793. }
  794. }
  795. /* Digits */
  796. while (place > 0)
  797. dopr_outch (buffer, currlen, maxlen, convert[--place]);
  798. /* Left Justified spaces */
  799. while (spadlen < 0) {
  800. dopr_outch (buffer, currlen, maxlen, ' ');
  801. ++spadlen;
  802. }
  803. }
  804. static LDOUBLE abs_val(LDOUBLE value)
  805. {
  806. LDOUBLE result = value;
  807. if (value < 0)
  808. result = -value;
  809. return result;
  810. }
  811. static LDOUBLE POW10(int exp)
  812. {
  813. LDOUBLE result = 1;
  814. while (exp) {
  815. result *= 10;
  816. exp--;
  817. }
  818. return result;
  819. }
  820. static LLONG ROUND(LDOUBLE value)
  821. {
  822. LLONG intpart;
  823. intpart = (LLONG)value;
  824. value = value - intpart;
  825. if (value >= 0.5) intpart++;
  826. return intpart;
  827. }
  828. /* a replacement for modf that doesn't need the math library. Should
  829. be portable, but slow */
  830. static double my_modf(double x0, double *iptr)
  831. {
  832. int i;
  833. long l;
  834. double x = x0;
  835. double f = 1.0;
  836. for (i=0;i<100;i++) {
  837. l = (long)x;
  838. if (l <= (x+1) && l >= (x-1)) break;
  839. x *= 0.1;
  840. f *= 10.0;
  841. }
  842. if (i == 100) {
  843. /* yikes! the number is beyond what we can handle. What do we do? */
  844. (*iptr) = 0;
  845. return 0;
  846. }
  847. if (i != 0) {
  848. double i2;
  849. double ret;
  850. ret = my_modf(x0-l*f, &i2);
  851. (*iptr) = l*f + i2;
  852. return ret;
  853. }
  854. (*iptr) = l;
  855. return x - (*iptr);
  856. }
  857. static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
  858. LDOUBLE fvalue, int min, int max, int flags)
  859. {
  860. int signvalue = 0;
  861. double ufvalue;
  862. char iconvert[311];
  863. char fconvert[311];
  864. int iplace = 0;
  865. int fplace = 0;
  866. int padlen = 0; /* amount to pad */
  867. int zpadlen = 0;
  868. int caps = 0;
  869. int idx;
  870. double intpart;
  871. double fracpart;
  872. double temp;
  873. /*
  874. * AIX manpage says the default is 0, but Solaris says the default
  875. * is 6, and sprintf on AIX defaults to 6
  876. */
  877. if (max < 0)
  878. max = 6;
  879. ufvalue = abs_val (fvalue);
  880. if (fvalue < 0) {
  881. signvalue = '-';
  882. } else {
  883. if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
  884. signvalue = '+';
  885. } else {
  886. if (flags & DP_F_SPACE)
  887. signvalue = ' ';
  888. }
  889. }
  890. #if 0
  891. if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
  892. #endif
  893. #if 0
  894. if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
  895. #endif
  896. /*
  897. * Sorry, we only support 9 digits past the decimal because of our
  898. * conversion method
  899. */
  900. if (max > 9)
  901. max = 9;
  902. /* We "cheat" by converting the fractional part to integer by
  903. * multiplying by a factor of 10
  904. */
  905. temp = ufvalue;
  906. my_modf(temp, &intpart);
  907. fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
  908. if (fracpart >= POW10(max)) {
  909. intpart++;
  910. fracpart -= POW10(max);
  911. }
  912. /* Convert integer part */
  913. do {
  914. temp = intpart*0.1;
  915. my_modf(temp, &intpart);
  916. idx = (int) ((temp -intpart +0.05)* 10.0);
  917. /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
  918. /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
  919. iconvert[iplace++] =
  920. (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
  921. } while (intpart && (iplace < 311));
  922. if (iplace == 311) iplace--;
  923. iconvert[iplace] = 0;
  924. /* Convert fractional part */
  925. if (fracpart)
  926. {
  927. do {
  928. temp = fracpart*0.1;
  929. my_modf(temp, &fracpart);
  930. idx = (int) ((temp -fracpart +0.05)* 10.0);
  931. /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
  932. /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
  933. fconvert[fplace++] =
  934. (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
  935. } while(fracpart && (fplace < 311));
  936. if (fplace == 311) fplace--;
  937. }
  938. fconvert[fplace] = 0;
  939. /* -1 for decimal point, another -1 if we are printing a sign */
  940. padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
  941. zpadlen = max - fplace;
  942. if (zpadlen < 0) zpadlen = 0;
  943. if (padlen < 0)
  944. padlen = 0;
  945. if (flags & DP_F_MINUS)
  946. padlen = -padlen; /* Left Justify */
  947. if ((flags & DP_F_ZERO) && (padlen > 0)) {
  948. if (signvalue) {
  949. dopr_outch (buffer, currlen, maxlen, signvalue);
  950. --padlen;
  951. signvalue = 0;
  952. }
  953. while (padlen > 0) {
  954. dopr_outch (buffer, currlen, maxlen, '0');
  955. --padlen;
  956. }
  957. }
  958. while (padlen > 0) {
  959. dopr_outch (buffer, currlen, maxlen, ' ');
  960. --padlen;
  961. }
  962. if (signvalue)
  963. dopr_outch (buffer, currlen, maxlen, signvalue);
  964. while (iplace > 0)
  965. dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
  966. #ifdef DEBUG_SNPRINTF
  967. printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
  968. #endif
  969. /*
  970. * Decimal point. This should probably use locale to find the correct
  971. * char to print out.
  972. */
  973. if (max > 0) {
  974. dopr_outch (buffer, currlen, maxlen, '.');
  975. while (zpadlen > 0) {
  976. dopr_outch (buffer, currlen, maxlen, '0');
  977. --zpadlen;
  978. }
  979. while (fplace > 0)
  980. dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
  981. }
  982. while (padlen < 0) {
  983. dopr_outch (buffer, currlen, maxlen, ' ');
  984. ++padlen;
  985. }
  986. }
  987. static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
  988. {
  989. if (*currlen < maxlen) {
  990. buffer[(*currlen)] = c;
  991. }
  992. (*currlen)++;
  993. }
  994. static struct pr_chunk *new_chunk(void) {
  995. struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
  996. if ( !new_c )
  997. return NULL;
  998. new_c->type = 0;
  999. new_c->num = 0;
  1000. new_c->min = 0;
  1001. new_c->min_star = NULL;
  1002. new_c->max = -1;
  1003. new_c->max_star = NULL;
  1004. new_c->flags = 0;
  1005. new_c->cflags = 0;
  1006. new_c->start = 0;
  1007. new_c->len = 0;
  1008. new_c->value = 0;
  1009. new_c->fvalue = 0;
  1010. new_c->strvalue = NULL;
  1011. new_c->pnum = NULL;
  1012. new_c->next = NULL;
  1013. return new_c;
  1014. }
  1015. static int add_cnk_list_entry(struct pr_chunk_x **list,
  1016. int max_num, struct pr_chunk *chunk) {
  1017. struct pr_chunk_x *l;
  1018. struct pr_chunk **c;
  1019. int max;
  1020. int cnum;
  1021. int i, pos;
  1022. if (chunk->num > max_num) {
  1023. max = chunk->num;
  1024. if (*list == NULL) {
  1025. l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
  1026. pos = 0;
  1027. } else {
  1028. l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
  1029. pos = max_num;
  1030. }
  1031. if (l == NULL) {
  1032. for (i = 0; i < max; i++) {
  1033. if ((*list)[i].chunks) free((*list)[i].chunks);
  1034. }
  1035. return 0;
  1036. }
  1037. for (i = pos; i < max; i++) {
  1038. l[i].chunks = NULL;
  1039. l[i].num = 0;
  1040. }
  1041. } else {
  1042. l = *list;
  1043. max = max_num;
  1044. }
  1045. i = chunk->num - 1;
  1046. cnum = l[i].num + 1;
  1047. if (l[i].chunks == NULL) {
  1048. c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum);
  1049. } else {
  1050. c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
  1051. }
  1052. if (c == NULL) {
  1053. for (i = 0; i < max; i++) {
  1054. if (l[i].chunks) free(l[i].chunks);
  1055. }
  1056. return 0;
  1057. }
  1058. c[l[i].num] = chunk;
  1059. l[i].chunks = c;
  1060. l[i].num = cnum;
  1061. *list = l;
  1062. return max;
  1063. }
  1064. int smb_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
  1065. {
  1066. return dopr(str, count, fmt, args);
  1067. }
  1068. #define vsnprintf smb_vsnprintf
  1069. #endif
  1070. /* yes this really must be a ||. Don't muck with this (tridge)
  1071. *
  1072. * The logic for these two is that we need our own definition if the
  1073. * OS *either* has no definition of *sprintf, or if it does have one
  1074. * that doesn't work properly according to the autoconf test.
  1075. */
  1076. #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
  1077. int smb_snprintf(char *str,size_t count,const char *fmt,...)
  1078. {
  1079. size_t ret;
  1080. va_list ap;
  1081. va_start(ap, fmt);
  1082. ret = vsnprintf(str, count, fmt, ap);
  1083. va_end(ap);
  1084. return ret;
  1085. }
  1086. #define snprintf smb_snprintf
  1087. #endif
  1088. #endif
  1089. #ifndef HAVE_VASPRINTF
  1090. int vasprintf(char **ptr, const char *format, va_list ap)
  1091. {
  1092. int ret;
  1093. va_list ap2;
  1094. VA_COPY(ap2, ap);
  1095. ret = vsnprintf(NULL, 0, format, ap2);
  1096. if (ret <= 0) return ret;
  1097. (*ptr) = (char *)malloc(ret+1);
  1098. if (!*ptr) return -1;
  1099. VA_COPY(ap2, ap);
  1100. ret = vsnprintf(*ptr, ret+1, format, ap2);
  1101. return ret;
  1102. }
  1103. #endif
  1104. #ifndef HAVE_ASPRINTF
  1105. int asprintf(char **ptr, const char *format, ...)
  1106. {
  1107. va_list ap;
  1108. int ret;
  1109. *ptr = NULL;
  1110. va_start(ap, format);
  1111. ret = vasprintf(ptr, format, ap);
  1112. va_end(ap);
  1113. return ret;
  1114. }
  1115. #endif
  1116. #ifdef TEST_SNPRINTF
  1117. int sprintf(char *str,const char *fmt,...);
  1118. int main (void)
  1119. {
  1120. char buf1[1024];
  1121. char buf2[1024];
  1122. char *buf3;
  1123. char *fp_fmt[] = {
  1124. "%1.1f",
  1125. "%-1.5f",
  1126. "%1.5f",
  1127. "%123.9f",
  1128. "%10.5f",
  1129. "% 10.5f",
  1130. "%+22.9f",
  1131. "%+4.9f",
  1132. "%01.3f",
  1133. "%4f",
  1134. "%3.1f",
  1135. "%3.2f",
  1136. "%.0f",
  1137. "%f",
  1138. "%-8.8f",
  1139. "%-9.9f",
  1140. NULL
  1141. };
  1142. double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
  1143. 0.9996, 1.996, 4.136, 5.030201, 0.00205,
  1144. /* END LIST */ 0};
  1145. char *int_fmt[] = {
  1146. "%-1.5d",
  1147. "%1.5d",
  1148. "%123.9d",
  1149. "%5.5d",
  1150. "%10.5d",
  1151. "% 10.5d",
  1152. "%+22.33d",
  1153. "%01.3d",
  1154. "%4d",
  1155. "%d",
  1156. NULL
  1157. };
  1158. long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 1234567890};
  1159. char *str_fmt[] = {
  1160. "%10.5s",
  1161. "%-10.5s",
  1162. "%5.10s",
  1163. "%-5.10s",
  1164. "%10.1s",
  1165. "%0.10s",
  1166. "%10.0s",
  1167. "%1.10s",
  1168. "%s",
  1169. "%.1s",
  1170. "%.10s",
  1171. "%10s",
  1172. NULL
  1173. };
  1174. char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
  1175. int x, y;
  1176. int fail = 0;
  1177. int num = 0;
  1178. int l1, l2;
  1179. printf ("Testing snprintf format codes against system sprintf...\n");
  1180. for (x = 0; fp_fmt[x] ; x++) {
  1181. for (y = 0; fp_nums[y] != 0 ; y++) {
  1182. buf1[0] = buf2[0] = '\0';
  1183. l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
  1184. l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
  1185. sprintf (buf2, fp_fmt[x], fp_nums[y]);
  1186. buf1[1023] = buf1[1023] = '\0';
  1187. if (strcmp (buf1, buf2) || (l1 != l2)) {
  1188. printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
  1189. fp_fmt[x], l1, buf1, l2, buf2);
  1190. fail++;
  1191. }
  1192. num++;
  1193. }
  1194. }
  1195. for (x = 0; int_fmt[x] ; x++) {
  1196. for (y = 0; int_nums[y] != 0 ; y++) {
  1197. buf1[0] = buf2[0] = '\0';
  1198. l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
  1199. l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
  1200. sprintf (buf2, int_fmt[x], int_nums[y]);
  1201. buf1[1023] = buf1[1023] = '\0';
  1202. if (strcmp (buf1, buf2) || (l1 != l2)) {
  1203. printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
  1204. int_fmt[x], l1, buf1, l2, buf2);
  1205. fail++;
  1206. }
  1207. num++;
  1208. }
  1209. }
  1210. for (x = 0; str_fmt[x] ; x++) {
  1211. for (y = 0; str_vals[y] != 0 ; y++) {
  1212. buf1[0] = buf2[0] = '\0';
  1213. l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
  1214. l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
  1215. sprintf (buf2, str_fmt[x], str_vals[y]);
  1216. buf1[1023] = buf1[1023] = '\0';
  1217. if (strcmp (buf1, buf2) || (l1 != l2)) {
  1218. printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
  1219. str_fmt[x], l1, buf1, l2, buf2);
  1220. fail++;
  1221. }
  1222. num++;
  1223. }
  1224. }
  1225. #define BUFSZ 2048
  1226. buf1[0] = buf2[0] = '\0';
  1227. if ((buf3 = malloc(BUFSZ)) == NULL) {
  1228. fail++;
  1229. } else {
  1230. num++;
  1231. memset(buf3, 'a', BUFSZ);
  1232. snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
  1233. buf1[1023] = '\0';
  1234. if (strcmp(buf1, "a") != 0) {
  1235. printf("length limit buf1 '%s' expected 'a'\n", buf1);
  1236. fail++;
  1237. }
  1238. }
  1239. buf1[0] = buf2[0] = '\0';
  1240. l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
  1241. l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
  1242. buf1[1023] = buf1[1023] = '\0';
  1243. if (strcmp(buf1, buf2) || (l1 != l2)) {
  1244. printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
  1245. "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
  1246. fail++;
  1247. }
  1248. buf1[0] = buf2[0] = '\0';
  1249. l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
  1250. l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
  1251. buf1[1023] = buf1[1023] = '\0';
  1252. if (strcmp(buf1, buf2)) {
  1253. printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
  1254. "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
  1255. fail++;
  1256. }
  1257. #if 0
  1258. buf1[0] = buf2[0] = '\0';
  1259. l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
  1260. l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
  1261. buf1[1023] = buf1[1023] = '\0';
  1262. if (strcmp(buf1, buf2)) {
  1263. printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
  1264. "%lld", l1, buf1, l2, buf2);
  1265. fail++;
  1266. }
  1267. buf1[0] = buf2[0] = '\0';
  1268. l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
  1269. l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
  1270. buf1[1023] = buf1[1023] = '\0';
  1271. if (strcmp(buf1, buf2)) {
  1272. printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
  1273. "%Lf", l1, buf1, l2, buf2);
  1274. fail++;
  1275. }
  1276. #endif
  1277. printf ("%d tests failed out of %d.\n", fail, num);
  1278. printf("seeing how many digits we support\n");
  1279. {
  1280. double v0 = 0.12345678901234567890123456789012345678901;
  1281. for (x=0; x<100; x++) {
  1282. double p = pow(10, x);
  1283. double r = v0*p;
  1284. snprintf(buf1, sizeof(buf1), "%1.1f", r);
  1285. sprintf(buf2, "%1.1f", r);
  1286. if (strcmp(buf1, buf2)) {
  1287. printf("we seem to support %d digits\n", x-1);
  1288. break;
  1289. }
  1290. }
  1291. }
  1292. return 0;
  1293. }
  1294. #endif /* TEST_SNPRINTF */