factored out the EFFv2 saving into EFFImporter
[gemrb.git] / gemrb / core / System / snprintf.cpp
blobacd785dbbaed059339b10cac0797f36f6afd7d87
1 /*
2 * Copyright Patrick Powell 1995
3 * This code is based on code written by Patrick Powell (papowell@astart.com)
4 * It may be used for any purpose as long as this notice remains intact
5 * on all source code distributions
6 */
8 /**************************************************************
9 * Original:
10 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
11 * A bombproof version of doprnt (dopr) included.
12 * Sigh. This sort of thing is always nasty do deal with. Note that
13 * the version here does not include floating point...
15 * snprintf() is used instead of sprintf() as it does limit checks
16 * for string length. This covers a nasty loophole.
18 * The other functions are there to prevent NULL pointers from
19 * causing nast effects.
21 * More Recently:
22 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
23 * This was ugly. It is still ugly. I opted out of floating point
24 * numbers, but the formatter understands just about everything
25 * from the normal C string format, at least as far as I can tell from
26 * the Solaris 2.5 printf(3S) man page.
28 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
29 * Ok, added some minimal floating point support, which means this
30 * probably requires libm on most operating systems. Don't yet
31 * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
32 * was pretty badly broken, it just wasn't being exercised in ways
33 * which showed it, so that's been fixed. Also, formated the code
34 * to mutt conventions, and removed dead code left over from the
35 * original. Also, there is now a builtin-test, just compile with:
36 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
37 * and run snprintf for results.
39 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
40 * The PGP code was using unsigned hexadecimal formats.
41 * Unfortunately, unsigned formats simply didn't work.
43 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
44 * The original code assumed that both snprintf() and vsnprintf() were
45 * missing. Some systems only have snprintf() but not vsnprintf(), so
46 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
48 * Andrew Tridgell (tridge@samba.org) Oct 1998
49 * fixed handling of %.0f
50 * added test for HAVE_LONG_DOUBLE
52 * tridge@samba.org, idra@samba.org, April 2001
53 * got rid of fcvt code (twas buggy and made testing harder)
54 * added C99 semantics
56 * HT authors
57 * * ht_snprintf/ht_vsnprintf return number of characters actually
58 * written instead of the number of characters that would
59 * have been written.
60 * * added '%y' to allow object output using Object's toString() method.
61 * * added '%q[dioux]' for formatting qwords.
62 * * added '%b' for formatting in binary notation.
63 **************************************************************/
64 #include "win32def.h"
65 #ifndef HAVE_SNPRINTF
67 #include <cctype>
68 #include <cstring>
69 #include <cstdlib>
70 #include <cstdio>
71 #include <cstdarg>
72 #include <sys/types.h>
74 #ifdef HAVE_CONFIG_H
75 #include "config.h"
76 #endif
78 #include "system/types.h"
79 #include "data.h"
81 #ifndef MIN
82 #define MIN(a, b) ((a) < (b) ? (a) : (b))
83 #endif
84 #ifndef MAX
85 #define MAX(a, b) ((a) > (b) ? (a) : (b))
86 #endif
88 #ifdef HAVE_LONG_DOUBLE
89 #define LDOUBLE long double
90 #else
91 #define LDOUBLE double
92 #endif
94 #ifdef HAVE_LONG_LONG
95 #define LLONG long long
96 #else
97 #define LLONG long
98 #endif
100 static size_t dopr(char *buffer, size_t maxlen, const char *format,
101 va_list args);
102 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
103 char *value, int flags, int min, int max);
104 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
105 long value, int base, int min, int max, int flags);
106 static void fmtqword(char *buffer, size_t *currlen, size_t maxlen,
107 sint64 value, int base, int min, int max, int flags);
108 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
109 LDOUBLE fvalue, int min, int max, int flags);
110 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
113 * dopr(): poor man's version of doprintf
116 /* format read states */
117 #define DP_S_DEFAULT 0
118 #define DP_S_FLAGS 1
119 #define DP_S_MIN 2
120 #define DP_S_DOT 3
121 #define DP_S_MAX 4
122 #define DP_S_MOD 5
123 #define DP_S_CONV 6
124 #define DP_S_DONE 7
126 /* format flags - Bits */
127 #define DP_F_MINUS (1 << 0)
128 #define DP_F_PLUS (1 << 1)
129 #define DP_F_SPACE (1 << 2)
130 #define DP_F_NUM (1 << 3)
131 #define DP_F_ZERO (1 << 4)
132 #define DP_F_UP (1 << 5)
133 #define DP_F_UNSIGNED (1 << 6)
135 /* Conversion Flags */
136 #define DP_C_SHORT 1
137 #define DP_C_LONG 2
138 #define DP_C_LDOUBLE 3
139 #define DP_C_LLONG 4
140 #define DP_C_QWORD 5
142 #define char_to_int(p) ((p)- '0')
143 #ifndef MAX
144 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
145 #endif
147 static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
149 char ch;
150 LLONG value;
151 LDOUBLE fvalue;
152 char *strvalue;
153 int min;
154 int max;
155 int state;
156 int flags;
157 int cflags;
158 size_t currlen;
160 state = DP_S_DEFAULT;
161 currlen = flags = cflags = min = 0;
162 max = -1;
163 ch = *format++;
165 while (state != DP_S_DONE) {
166 if (ch == '\0') state = DP_S_DONE;
168 switch(state) {
169 case DP_S_DEFAULT:
170 if (ch == '%') {
171 state = DP_S_FLAGS;
172 } else {
173 dopr_outch(buffer, &currlen, maxlen, ch);
175 ch = *format++;
176 break;
177 case DP_S_FLAGS:
178 switch (ch) {
179 case '-':
180 flags |= DP_F_MINUS;
181 ch = *format++;
182 break;
183 case '+':
184 flags |= DP_F_PLUS;
185 ch = *format++;
186 break;
187 case ' ':
188 flags |= DP_F_SPACE;
189 ch = *format++;
190 break;
191 case '#':
192 flags |= DP_F_NUM;
193 ch = *format++;
194 break;
195 case '0':
196 flags |= DP_F_ZERO;
197 ch = *format++;
198 break;
199 default:
200 state = DP_S_MIN;
201 break;
203 break;
204 case DP_S_MIN:
205 if (isdigit((unsigned char)ch)) {
206 min = 10*min + char_to_int (ch);
207 ch = *format++;
208 } else if (ch == '*') {
209 min = va_arg (args, int);
210 ch = *format++;
211 state = DP_S_DOT;
212 } else {
213 state = DP_S_DOT;
215 break;
216 case DP_S_DOT:
217 if (ch == '.') {
218 state = DP_S_MAX;
219 ch = *format++;
220 } else {
221 state = DP_S_MOD;
223 break;
224 case DP_S_MAX:
225 if (isdigit((unsigned char)ch)) {
226 if (max < 0) max = 0;
227 max = 10*max + char_to_int (ch);
228 ch = *format++;
229 } else if (ch == '*') {
230 max = va_arg (args, int);
231 ch = *format++;
232 state = DP_S_MOD;
233 } else {
234 state = DP_S_MOD;
236 break;
237 case DP_S_MOD:
238 switch (ch) {
239 case 'h':
240 cflags = DP_C_SHORT;
241 ch = *format++;
242 break;
243 case 'l':
244 cflags = DP_C_LONG;
245 ch = *format++;
246 if (ch == 'l') { /* It's a long long */
247 cflags = DP_C_LLONG;
248 ch = *format++;
250 break;
251 case 'L':
252 cflags = DP_C_LDOUBLE;
253 ch = *format++;
254 break;
255 case 'q':
256 cflags = DP_C_QWORD;
257 ch = *format++;
258 break;
259 default:
260 break;
262 state = DP_S_CONV;
263 break;
264 case DP_S_CONV:
265 switch (ch) {
266 case 'b':
267 flags |= DP_F_UNSIGNED;
268 if (cflags == DP_C_SHORT) {
269 value = va_arg (args, unsigned int);
270 } else if (cflags == DP_C_LONG) {
271 value = (long)va_arg (args, unsigned long int);
272 } else if (cflags == DP_C_LLONG) {
273 value = (LLONG)va_arg (args, unsigned LLONG);
274 } else if (cflags == DP_C_QWORD) {
275 sint64 *q = va_arg (args, sint64 *);
276 fmtqword(buffer, &currlen, maxlen, *q, 2, min, max, flags);
277 break;
278 } else {
279 value = (long)va_arg (args, unsigned int);
281 fmtint (buffer, &currlen, maxlen, value, 2, min, max, flags);
282 break;
283 case 'd':
284 case 'i':
285 if (cflags == DP_C_SHORT) {
286 value = va_arg (args, int);
287 } else if (cflags == DP_C_LONG) {
288 value = va_arg (args, long int);
289 } else if (cflags == DP_C_LLONG) {
290 value = va_arg (args, LLONG);
291 } else if (cflags == DP_C_QWORD) {
292 sint64 *q = va_arg (args, sint64 *);
293 fmtqword(buffer, &currlen, maxlen, *q, 10, min, max, flags);
294 break;
295 } else {
296 value = va_arg (args, int);
298 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
299 break;
300 case 'o':
301 flags |= DP_F_UNSIGNED;
302 if (cflags == DP_C_SHORT) {
303 value = va_arg (args, unsigned int);
304 } else if (cflags == DP_C_LONG) {
305 value = (long)va_arg (args, unsigned long int);
306 } else if (cflags == DP_C_LLONG) {
307 value = (long)va_arg (args, unsigned LLONG);
308 } else if (cflags == DP_C_QWORD) {
309 sint64 *q = va_arg (args, sint64 *);
310 fmtqword(buffer, &currlen, maxlen, *q, 8, min, max, flags);
311 break;
312 } else {
313 value = (long)va_arg (args, unsigned int);
315 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
316 break;
317 case 'u':
318 flags |= DP_F_UNSIGNED;
319 if (cflags == DP_C_SHORT) {
320 value = va_arg (args, unsigned int);
321 } else if (cflags == DP_C_LONG) {
322 value = (long)va_arg (args, unsigned long int);
323 } else if (cflags == DP_C_LLONG) {
324 value = (LLONG)va_arg (args, unsigned LLONG);
325 } else if (cflags == DP_C_QWORD) {
326 sint64 *q = va_arg (args, sint64 *);
327 fmtqword(buffer, &currlen, maxlen, *q, 10, min, max, flags);
328 break;
329 } else {
330 value = (long)va_arg (args, unsigned int);
332 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
333 break;
334 case 'X':
335 flags |= DP_F_UP;
336 case 'x':
337 flags |= DP_F_UNSIGNED;
338 if (cflags == DP_C_SHORT) {
339 value = va_arg (args, unsigned int);
340 } else if (cflags == DP_C_LONG) {
341 value = (long)va_arg (args, unsigned long int);
342 } else if (cflags == DP_C_LLONG) {
343 value = (LLONG)va_arg (args, unsigned LLONG);
344 } else if (cflags == DP_C_QWORD) {
345 sint64 *q = va_arg (args, sint64 *);
346 fmtqword(buffer, &currlen, maxlen, *q, 16, min, max, flags);
347 break;
348 } else {
349 value = (long)va_arg (args, unsigned int);
351 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
352 break;
353 case 'f':
354 if (cflags == DP_C_LDOUBLE)
355 fvalue = va_arg (args, LDOUBLE);
356 else
357 fvalue = va_arg (args, double);
358 /* um, floating point? */
359 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
360 break;
361 case 'E':
362 flags |= DP_F_UP;
363 case 'e':
364 if (cflags == DP_C_LDOUBLE)
365 fvalue = va_arg (args, LDOUBLE);
366 else
367 fvalue = va_arg (args, double);
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 break;
377 case 'c':
378 dopr_outch(buffer, &currlen, maxlen, va_arg (args, int));
379 break;
380 case 's':
381 strvalue = va_arg (args, char *);
382 if (!strvalue) strvalue = "(null)";
383 if (max == -1) {
384 max = strlen(strvalue);
386 if (min > 0 && max >= 0 && min > max) max = min;
387 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
388 break;
389 case 'p':
390 strvalue = va_arg (args, char *);
391 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
392 break;
393 case 'n':
394 if (cflags == DP_C_SHORT) {
395 short int *num;
396 num = va_arg (args, short int *);
397 *num = currlen;
398 } else if (cflags == DP_C_LONG) {
399 long int *num;
400 num = va_arg (args, long int *);
401 *num = (long int)currlen;
402 } else if (cflags == DP_C_LLONG) {
403 LLONG *num;
404 num = va_arg (args, LLONG *);
405 *num = (LLONG)currlen;
406 } else {
407 int *num;
408 num = va_arg (args, int *);
409 *num = currlen;
411 break;
412 case '%':
413 dopr_outch(buffer, &currlen, maxlen, ch);
414 break;
415 case 'w':
416 /* not supported yet, treat as next char */
417 ch = *format++;
418 break;
419 case 'y': {
420 /* object */
421 Object *obj = va_arg (args, Object *);
422 if (obj) {
423 currlen += obj->toString(buffer+currlen, maxlen - currlen);
424 } else {
425 strvalue = "(null)";
426 if (max == -1) {
427 max = strlen(strvalue);
429 if (min > 0 && max >= 0 && min > max) max = min;
430 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
432 break;
434 default:
435 /* Unknown, skip */
436 break;
438 ch = *format++;
439 state = DP_S_DEFAULT;
440 flags = cflags = min = 0;
441 max = -1;
442 break;
443 case DP_S_DONE:
444 break;
445 default:
446 /* hmm? */
447 break; /* some picky compilers need this */
450 if (maxlen != 0) {
451 if (currlen < maxlen - 1)
452 buffer[currlen] = '\0';
453 else if (maxlen > 0)
454 buffer[maxlen - 1] = '\0';
457 return currlen;
460 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
461 char *value, int flags, int min, int max)
463 int padlen, strln; /* amount to pad */
464 int cnt = 0;
466 #ifdef DEBUG_SNPRINTF
467 printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
468 #endif
470 for (strln = 0; value[strln]; ++strln); /* strlen */
471 padlen = min - strln;
472 if (padlen < 0)
473 padlen = 0;
474 if (flags & DP_F_MINUS)
475 padlen = -padlen; /* Left Justify */
477 while ((padlen > 0) && (cnt < max)) {
478 dopr_outch(buffer, currlen, maxlen, ' ');
479 --padlen;
480 ++cnt;
482 while (*value && (cnt < max)) {
483 dopr_outch(buffer, currlen, maxlen, *value++);
484 ++cnt;
486 while ((padlen < 0) && (cnt < max)) {
487 dopr_outch(buffer, currlen, maxlen, ' ');
488 ++padlen;
489 ++cnt;
493 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
495 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
496 long value, int base, int min, int max, int flags)
498 #define MAX_CONVERT_PLACES 40
499 int signvalue = 0;
500 unsigned long uvalue;
501 char convert[MAX_CONVERT_PLACES];
502 int place = 0;
503 int spadlen = 0; /* amount to space pad */
504 int zpadlen = 0; /* amount to zero pad */
505 int caps = 0;
507 if (max < 0)
508 max = 0;
510 uvalue = value;
512 if (!(flags & DP_F_UNSIGNED)) {
513 if (value < 0) {
514 signvalue = '-';
515 uvalue = -value;
516 } else {
517 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
518 signvalue = '+';
519 else if (flags & DP_F_SPACE)
520 signvalue = ' ';
524 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
526 do {
527 convert[place++] =
528 (caps? "0123456789ABCDEF":"0123456789abcdef")[uvalue % (unsigned)base];
529 uvalue = (uvalue / (unsigned)base );
530 } while (uvalue && (place < MAX_CONVERT_PLACES));
531 if (place == MAX_CONVERT_PLACES) place--;
532 convert[place] = 0;
534 zpadlen = max - place;
535 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
536 if (zpadlen < 0) zpadlen = 0;
537 if (spadlen < 0) spadlen = 0;
538 if (flags & DP_F_ZERO) {
539 zpadlen = MAX(zpadlen, spadlen);
540 spadlen = 0;
542 if (flags & DP_F_MINUS)
543 spadlen = -spadlen; /* Left Justifty */
545 #ifdef DEBUG_SNPRINTF
546 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
547 zpadlen, spadlen, min, max, place);
548 #endif
550 /* Spaces */
551 while (spadlen > 0) {
552 dopr_outch(buffer, currlen, maxlen, ' ');
553 --spadlen;
556 /* Sign */
557 if (signvalue) dopr_outch(buffer, currlen, maxlen, signvalue);
559 /* Zeros */
560 if (zpadlen > 0) {
561 while (zpadlen > 0) {
562 dopr_outch(buffer, currlen, maxlen, '0');
563 --zpadlen;
567 /* Digits */
568 while (place > 0) dopr_outch(buffer, currlen, maxlen, convert[--place]);
570 /* Left Justified spaces */
571 while (spadlen < 0) {
572 dopr_outch(buffer, currlen, maxlen, ' ');
573 ++spadlen;
577 static void fmtqword(char *buffer, size_t *currlen, size_t maxlen,
578 sint64 value, int base, int min, int max, int flags)
580 #undef MAX_CONVERT_PLACES
581 #define MAX_CONVERT_PLACES 80
582 int signvalue = 0;
583 uint64 uvalue;
584 char convert[MAX_CONVERT_PLACES];
585 int place = 0;
586 int spadlen = 0; /* amount to space pad */
587 int zpadlen = 0; /* amount to zero pad */
588 int caps = 0;
590 if (max < 0) max = 0;
592 uvalue = value;
594 if (!(flags & DP_F_UNSIGNED)) {
595 if (value < 0) {
596 signvalue = '-';
597 uvalue = -uvalue;
598 } else {
599 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
600 signvalue = '+';
601 else if (flags & DP_F_SPACE)
602 signvalue = ' ';
606 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
608 do {
609 uint64 uv = uvalue % (uint64)base;
610 convert[place++] =
611 (caps? "0123456789ABCDEF":"0123456789abcdef")[uv];
612 uvalue = (uvalue / (uint64)base);
613 } while ((uvalue != 0) && (place < MAX_CONVERT_PLACES));
614 if (place == MAX_CONVERT_PLACES) place--;
615 convert[place] = 0;
617 zpadlen = max - place;
618 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
619 if (zpadlen < 0) zpadlen = 0;
620 if (spadlen < 0) spadlen = 0;
621 if (flags & DP_F_ZERO) {
622 zpadlen = MAX(zpadlen, spadlen);
623 spadlen = 0;
625 if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */
627 #ifdef DEBUG_SNPRINTF
628 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
629 zpadlen, spadlen, min, max, place);
630 #endif
632 /* Spaces */
633 while (spadlen > 0) {
634 dopr_outch(buffer, currlen, maxlen, ' ');
635 --spadlen;
638 /* Sign */
639 if (signvalue) dopr_outch(buffer, currlen, maxlen, signvalue);
641 /* Zeros */
642 if (zpadlen > 0) {
643 while (zpadlen > 0) {
644 dopr_outch(buffer, currlen, maxlen, '0');
645 --zpadlen;
649 /* Digits */
650 while (place > 0) dopr_outch(buffer, currlen, maxlen, convert[--place]);
652 /* Left Justified spaces */
653 while (spadlen < 0) {
654 dopr_outch(buffer, currlen, maxlen, ' ');
655 ++spadlen;
659 static LDOUBLE abs_val(LDOUBLE value)
661 return (value < 0) ? -value : value;
664 static LDOUBLE POW10(int exp)
666 LDOUBLE result = 1;
668 while (exp) {
669 result *= 10;
670 exp--;
673 return result;
676 static LLONG ROUND(LDOUBLE value)
678 LLONG intpart;
680 intpart = (LLONG)value;
681 value = value - intpart;
682 if (value >= 0.5) intpart++;
684 return intpart;
687 /* a replacement for modf that doesn't need the math library. Should
688 be portable, but slow */
689 static double my_modf(double x0, double *iptr)
691 int i;
692 long l;
693 double x = x0;
694 double f = 1.0;
696 for (i=0;i<100;i++) {
697 l = (long)x;
698 if (l <= (x+1) && l >= (x-1)) break;
699 x *= 0.1;
700 f *= 10.0;
703 if (i == 100) {
704 /* yikes! the number is beyond what we can handle. What do we do? */
705 (*iptr) = 0;
706 return 0;
709 if (i != 0) {
710 double i2;
711 double ret;
713 ret = my_modf(x0-l*f, &i2);
714 (*iptr) = l*f + i2;
715 return ret;
718 (*iptr) = l;
719 return x - (*iptr);
723 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
724 LDOUBLE fvalue, int min, int max, int flags)
726 int signvalue = 0;
727 double ufvalue;
728 char iconvert[311];
729 char fconvert[311];
730 int iplace = 0;
731 int fplace = 0;
732 int padlen = 0; /* amount to pad */
733 int zpadlen = 0;
734 int caps = 0;
735 int index;
736 double intpart;
737 double fracpart;
738 double temp;
741 * AIX manpage says the default is 0, but Solaris says the default
742 * is 6, and sprintf on AIX defaults to 6
744 if (max < 0)
745 max = 6;
747 ufvalue = abs_val (fvalue);
749 if (fvalue < 0) {
750 signvalue = '-';
751 } else {
752 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
753 signvalue = '+';
754 } else {
755 if (flags & DP_F_SPACE)
756 signvalue = ' ';
760 #if 0
761 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
762 #endif
764 #if 0
765 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
766 #endif
769 * Sorry, we only support 16 digits past the decimal because of our
770 * conversion method
772 if (max > 16)
773 max = 16;
775 /* We "cheat" by converting the fractional part to integer by
776 * multiplying by a factor of 10
779 temp = ufvalue;
780 my_modf(temp, &intpart);
782 fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
784 if (fracpart >= POW10(max)) {
785 intpart++;
786 fracpart -= POW10(max);
790 /* Convert integer part */
791 do {
792 temp = intpart;
793 my_modf(intpart*0.1, &intpart);
794 temp = temp*0.1;
795 index = (int) ((temp -intpart +0.05)* 10.0);
796 /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
797 /* printf ("%llf, %f, %x\n", temp, intpart, index); */
798 iconvert[iplace++] =
799 (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
800 } while (intpart && (iplace < 311));
801 if (iplace == 311) iplace--;
802 iconvert[iplace] = 0;
804 /* Convert fractional part */
805 if (fracpart)
807 do {
808 temp = fracpart;
809 my_modf(fracpart*0.1, &fracpart);
810 temp = temp*0.1;
811 index = (int) ((temp -fracpart +0.05)* 10.0);
812 /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
813 /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
814 fconvert[fplace++] =
815 (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
816 } while(fracpart && (fplace < 311));
817 if (fplace == 311) fplace--;
819 fconvert[fplace] = 0;
821 /* -1 for decimal point, another -1 if we are printing a sign */
822 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
823 zpadlen = max - fplace;
824 if (zpadlen < 0) zpadlen = 0;
825 if (padlen < 0)
826 padlen = 0;
827 if (flags & DP_F_MINUS)
828 padlen = -padlen; /* Left Justifty */
830 if ((flags & DP_F_ZERO) && (padlen > 0)) {
831 if (signvalue) {
832 dopr_outch(buffer, currlen, maxlen, signvalue);
833 --padlen;
834 signvalue = 0;
836 while (padlen > 0) {
837 dopr_outch(buffer, currlen, maxlen, '0');
838 --padlen;
841 while (padlen > 0) {
842 dopr_outch(buffer, currlen, maxlen, ' ');
843 --padlen;
845 if (signvalue)
846 dopr_outch(buffer, currlen, maxlen, signvalue);
848 while (iplace > 0)
849 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
851 #ifdef DEBUG_SNPRINTF
852 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
853 #endif
856 * Decimal point. This should probably use locale to find the correct
857 * char to print out.
859 if (max > 0) {
860 dopr_outch(buffer, currlen, maxlen, '.');
862 while (fplace > 0)
863 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
866 while (zpadlen > 0) {
867 dopr_outch(buffer, currlen, maxlen, '0');
868 --zpadlen;
871 while (padlen < 0) {
872 dopr_outch(buffer, currlen, maxlen, ' ');
873 ++padlen;
877 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
879 if (*currlen < maxlen) {
880 buffer[(*currlen)] = c;
882 (*currlen)++;
885 int ht_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
887 if ((int)count < 0) count = 0;
888 int res = dopr(str, count, fmt, args);
889 if (count) count--;
890 return str ? MIN(res, (int)count) : count;
893 int ht_snprintf(char *str, size_t count, const char *fmt,...)
895 size_t ret;
896 va_list ap;
898 va_start(ap, fmt);
899 ret = ht_vsnprintf(str, count, fmt, ap);
900 va_end(ap);
901 return ret;
904 int ht_vasprintf(char **ptr, const char *format, va_list ap)
906 int ret;
908 ret = dopr(NULL, 0, format, ap);
909 if (ret <= 0) {
910 *ptr = NULL;
911 return 0;
914 (*ptr) = (char *)malloc(ret+1);
915 if (!*ptr) return 0;
916 ret = ht_vsnprintf(*ptr, ret+1, format, ap);
918 return ret;
922 int ht_asprintf(char **ptr, const char *format, ...)
924 va_list ap;
925 int ret;
927 va_start(ap, format);
928 ret = ht_vasprintf(ptr, format, ap);
929 va_end(ap);
931 return ret;
934 int ht_vfprintf(FILE *file, const char *fmt, va_list args)
936 #if 0
937 char *buf;
938 int ret = ht_vasprintf(&buf, fmt, args);
939 fputs(buf, file);
940 free(buf);
941 #else
942 char buf[1024];
943 int ret = ht_vsnprintf(buf, sizeof buf, fmt, args);
944 fputs(buf, file);
945 #endif
946 return ret;
949 int ht_fprintf(FILE *file, const char *fmt, ...)
951 va_list ap;
952 int ret;
954 va_start(ap, fmt);
955 ret = ht_vfprintf(file, fmt, ap);
956 va_end(ap);
958 return ret;
962 int ht_vprintf(const char *fmt, va_list args)
964 return ht_vfprintf(stdout, fmt, args);
967 int ht_printf(const char *fmt, ...)
969 va_list ap;
970 int ret;
972 va_start(ap, fmt);
973 ret = ht_vprintf(fmt, ap);
974 va_end(ap);
976 return ret;
980 #endif //HAVE_SNPRINTF