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