Switch to using -I to find includes, rather than relative paths.
[gemrb.git] / gemrb / plugins / Core / snprintf.cpp
blob525f3b167f67a2da9ab2be3ebaecb74970656c77
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 #ifdef HAVE_CONFIG_H
82 #include "config.h"
83 #endif
85 #ifndef MIN
86 #define MIN(a, b) ((a) < (b) ? (a) : (b))
87 #endif
88 #ifndef MAX
89 #define MAX(a, b) ((a) > (b) ? (a) : (b))
90 #endif
92 #ifdef HAVE_LONG_DOUBLE
93 #define LDOUBLE long double
94 #else
95 #define LDOUBLE double
96 #endif
98 #ifdef HAVE_LONG_LONG
99 #define LLONG long long
100 #else
101 #define LLONG long
102 #endif
104 static size_t dopr(char *buffer, size_t maxlen, const char *format,
105 va_list args);
106 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
107 char *value, int flags, int min, int max);
108 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
109 long value, int base, int min, int max, int flags);
110 static void fmtqword(char *buffer, size_t *currlen, size_t maxlen,
111 sint64 value, int base, int min, int max, int flags);
112 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
113 LDOUBLE fvalue, int min, int max, int flags);
114 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
117 * dopr(): poor man's version of doprintf
120 /* format read states */
121 #define DP_S_DEFAULT 0
122 #define DP_S_FLAGS 1
123 #define DP_S_MIN 2
124 #define DP_S_DOT 3
125 #define DP_S_MAX 4
126 #define DP_S_MOD 5
127 #define DP_S_CONV 6
128 #define DP_S_DONE 7
130 /* format flags - Bits */
131 #define DP_F_MINUS (1 << 0)
132 #define DP_F_PLUS (1 << 1)
133 #define DP_F_SPACE (1 << 2)
134 #define DP_F_NUM (1 << 3)
135 #define DP_F_ZERO (1 << 4)
136 #define DP_F_UP (1 << 5)
137 #define DP_F_UNSIGNED (1 << 6)
139 /* Conversion Flags */
140 #define DP_C_SHORT 1
141 #define DP_C_LONG 2
142 #define DP_C_LDOUBLE 3
143 #define DP_C_LLONG 4
144 #define DP_C_QWORD 5
146 #define char_to_int(p) ((p)- '0')
147 #ifndef MAX
148 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
149 #endif
151 static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
153 char ch;
154 LLONG value;
155 LDOUBLE fvalue;
156 char *strvalue;
157 int min;
158 int max;
159 int state;
160 int flags;
161 int cflags;
162 size_t currlen;
164 state = DP_S_DEFAULT;
165 currlen = flags = cflags = min = 0;
166 max = -1;
167 ch = *format++;
169 while (state != DP_S_DONE) {
170 if (ch == '\0') state = DP_S_DONE;
172 switch(state) {
173 case DP_S_DEFAULT:
174 if (ch == '%') {
175 state = DP_S_FLAGS;
176 } else {
177 dopr_outch(buffer, &currlen, maxlen, ch);
179 ch = *format++;
180 break;
181 case DP_S_FLAGS:
182 switch (ch) {
183 case '-':
184 flags |= DP_F_MINUS;
185 ch = *format++;
186 break;
187 case '+':
188 flags |= DP_F_PLUS;
189 ch = *format++;
190 break;
191 case ' ':
192 flags |= DP_F_SPACE;
193 ch = *format++;
194 break;
195 case '#':
196 flags |= DP_F_NUM;
197 ch = *format++;
198 break;
199 case '0':
200 flags |= DP_F_ZERO;
201 ch = *format++;
202 break;
203 default:
204 state = DP_S_MIN;
205 break;
207 break;
208 case DP_S_MIN:
209 if (isdigit((unsigned char)ch)) {
210 min = 10*min + char_to_int (ch);
211 ch = *format++;
212 } else if (ch == '*') {
213 min = va_arg (args, int);
214 ch = *format++;
215 state = DP_S_DOT;
216 } else {
217 state = DP_S_DOT;
219 break;
220 case DP_S_DOT:
221 if (ch == '.') {
222 state = DP_S_MAX;
223 ch = *format++;
224 } else {
225 state = DP_S_MOD;
227 break;
228 case DP_S_MAX:
229 if (isdigit((unsigned char)ch)) {
230 if (max < 0) max = 0;
231 max = 10*max + char_to_int (ch);
232 ch = *format++;
233 } else if (ch == '*') {
234 max = va_arg (args, int);
235 ch = *format++;
236 state = DP_S_MOD;
237 } else {
238 state = DP_S_MOD;
240 break;
241 case DP_S_MOD:
242 switch (ch) {
243 case 'h':
244 cflags = DP_C_SHORT;
245 ch = *format++;
246 break;
247 case 'l':
248 cflags = DP_C_LONG;
249 ch = *format++;
250 if (ch == 'l') { /* It's a long long */
251 cflags = DP_C_LLONG;
252 ch = *format++;
254 break;
255 case 'L':
256 cflags = DP_C_LDOUBLE;
257 ch = *format++;
258 break;
259 case 'q':
260 cflags = DP_C_QWORD;
261 ch = *format++;
262 break;
263 default:
264 break;
266 state = DP_S_CONV;
267 break;
268 case DP_S_CONV:
269 switch (ch) {
270 case 'b':
271 flags |= DP_F_UNSIGNED;
272 if (cflags == DP_C_SHORT) {
273 value = va_arg (args, unsigned int);
274 } else if (cflags == DP_C_LONG) {
275 value = (long)va_arg (args, unsigned long int);
276 } else if (cflags == DP_C_LLONG) {
277 value = (LLONG)va_arg (args, unsigned LLONG);
278 } else if (cflags == DP_C_QWORD) {
279 sint64 *q = va_arg (args, sint64 *);
280 fmtqword(buffer, &currlen, maxlen, *q, 2, min, max, flags);
281 break;
282 } else {
283 value = (long)va_arg (args, unsigned int);
285 fmtint (buffer, &currlen, maxlen, value, 2, min, max, flags);
286 break;
287 case 'd':
288 case 'i':
289 if (cflags == DP_C_SHORT) {
290 value = va_arg (args, int);
291 } else if (cflags == DP_C_LONG) {
292 value = va_arg (args, long int);
293 } else if (cflags == DP_C_LLONG) {
294 value = va_arg (args, LLONG);
295 } else if (cflags == DP_C_QWORD) {
296 sint64 *q = va_arg (args, sint64 *);
297 fmtqword(buffer, &currlen, maxlen, *q, 10, min, max, flags);
298 break;
299 } else {
300 value = va_arg (args, int);
302 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
303 break;
304 case 'o':
305 flags |= DP_F_UNSIGNED;
306 if (cflags == DP_C_SHORT) {
307 value = va_arg (args, unsigned int);
308 } else if (cflags == DP_C_LONG) {
309 value = (long)va_arg (args, unsigned long int);
310 } else if (cflags == DP_C_LLONG) {
311 value = (long)va_arg (args, unsigned LLONG);
312 } else if (cflags == DP_C_QWORD) {
313 sint64 *q = va_arg (args, sint64 *);
314 fmtqword(buffer, &currlen, maxlen, *q, 8, min, max, flags);
315 break;
316 } else {
317 value = (long)va_arg (args, unsigned int);
319 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
320 break;
321 case 'u':
322 flags |= DP_F_UNSIGNED;
323 if (cflags == DP_C_SHORT) {
324 value = va_arg (args, unsigned int);
325 } else if (cflags == DP_C_LONG) {
326 value = (long)va_arg (args, unsigned long int);
327 } else if (cflags == DP_C_LLONG) {
328 value = (LLONG)va_arg (args, unsigned LLONG);
329 } else if (cflags == DP_C_QWORD) {
330 sint64 *q = va_arg (args, sint64 *);
331 fmtqword(buffer, &currlen, maxlen, *q, 10, min, max, flags);
332 break;
333 } else {
334 value = (long)va_arg (args, unsigned int);
336 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
337 break;
338 case 'X':
339 flags |= DP_F_UP;
340 case 'x':
341 flags |= DP_F_UNSIGNED;
342 if (cflags == DP_C_SHORT) {
343 value = va_arg (args, unsigned int);
344 } else if (cflags == DP_C_LONG) {
345 value = (long)va_arg (args, unsigned long int);
346 } else if (cflags == DP_C_LLONG) {
347 value = (LLONG)va_arg (args, unsigned LLONG);
348 } else if (cflags == DP_C_QWORD) {
349 sint64 *q = va_arg (args, sint64 *);
350 fmtqword(buffer, &currlen, maxlen, *q, 16, min, max, flags);
351 break;
352 } else {
353 value = (long)va_arg (args, unsigned int);
355 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
356 break;
357 case 'f':
358 if (cflags == DP_C_LDOUBLE)
359 fvalue = va_arg (args, LDOUBLE);
360 else
361 fvalue = va_arg (args, double);
362 /* um, floating point? */
363 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
364 break;
365 case 'E':
366 flags |= DP_F_UP;
367 case 'e':
368 if (cflags == DP_C_LDOUBLE)
369 fvalue = va_arg (args, LDOUBLE);
370 else
371 fvalue = va_arg (args, double);
372 break;
373 case 'G':
374 flags |= DP_F_UP;
375 case 'g':
376 if (cflags == DP_C_LDOUBLE)
377 fvalue = va_arg (args, LDOUBLE);
378 else
379 fvalue = va_arg (args, double);
380 break;
381 case 'c':
382 dopr_outch(buffer, &currlen, maxlen, va_arg (args, int));
383 break;
384 case 's':
385 strvalue = va_arg (args, char *);
386 if (!strvalue) strvalue = "(null)";
387 if (max == -1) {
388 max = strlen(strvalue);
390 if (min > 0 && max >= 0 && min > max) max = min;
391 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
392 break;
393 case 'p':
394 strvalue = va_arg (args, char *);
395 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
396 break;
397 case 'n':
398 if (cflags == DP_C_SHORT) {
399 short int *num;
400 num = va_arg (args, short int *);
401 *num = currlen;
402 } else if (cflags == DP_C_LONG) {
403 long int *num;
404 num = va_arg (args, long int *);
405 *num = (long int)currlen;
406 } else if (cflags == DP_C_LLONG) {
407 LLONG *num;
408 num = va_arg (args, LLONG *);
409 *num = (LLONG)currlen;
410 } else {
411 int *num;
412 num = va_arg (args, int *);
413 *num = currlen;
415 break;
416 case '%':
417 dopr_outch(buffer, &currlen, maxlen, ch);
418 break;
419 case 'w':
420 /* not supported yet, treat as next char */
421 ch = *format++;
422 break;
423 case 'y': {
424 /* object */
425 Object *obj = va_arg (args, Object *);
426 if (obj) {
427 currlen += obj->toString(buffer+currlen, maxlen - currlen);
428 } else {
429 strvalue = "(null)";
430 if (max == -1) {
431 max = strlen(strvalue);
433 if (min > 0 && max >= 0 && min > max) max = min;
434 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
436 break;
438 default:
439 /* Unknown, skip */
440 break;
442 ch = *format++;
443 state = DP_S_DEFAULT;
444 flags = cflags = min = 0;
445 max = -1;
446 break;
447 case DP_S_DONE:
448 break;
449 default:
450 /* hmm? */
451 break; /* some picky compilers need this */
454 if (maxlen != 0) {
455 if (currlen < maxlen - 1)
456 buffer[currlen] = '\0';
457 else if (maxlen > 0)
458 buffer[maxlen - 1] = '\0';
461 return currlen;
464 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
465 char *value, int flags, int min, int max)
467 int padlen, strln; /* amount to pad */
468 int cnt = 0;
470 #ifdef DEBUG_SNPRINTF
471 printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
472 #endif
474 for (strln = 0; value[strln]; ++strln); /* strlen */
475 padlen = min - strln;
476 if (padlen < 0)
477 padlen = 0;
478 if (flags & DP_F_MINUS)
479 padlen = -padlen; /* Left Justify */
481 while ((padlen > 0) && (cnt < max)) {
482 dopr_outch(buffer, currlen, maxlen, ' ');
483 --padlen;
484 ++cnt;
486 while (*value && (cnt < max)) {
487 dopr_outch(buffer, currlen, maxlen, *value++);
488 ++cnt;
490 while ((padlen < 0) && (cnt < max)) {
491 dopr_outch(buffer, currlen, maxlen, ' ');
492 ++padlen;
493 ++cnt;
497 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
499 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
500 long value, int base, int min, int max, int flags)
502 #define MAX_CONVERT_PLACES 40
503 int signvalue = 0;
504 unsigned long uvalue;
505 char convert[MAX_CONVERT_PLACES];
506 int place = 0;
507 int spadlen = 0; /* amount to space pad */
508 int zpadlen = 0; /* amount to zero pad */
509 int caps = 0;
511 if (max < 0)
512 max = 0;
514 uvalue = value;
516 if (!(flags & DP_F_UNSIGNED)) {
517 if (value < 0) {
518 signvalue = '-';
519 uvalue = -value;
520 } else {
521 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
522 signvalue = '+';
523 else if (flags & DP_F_SPACE)
524 signvalue = ' ';
528 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
530 do {
531 convert[place++] =
532 (caps? "0123456789ABCDEF":"0123456789abcdef")[uvalue % (unsigned)base];
533 uvalue = (uvalue / (unsigned)base );
534 } while (uvalue && (place < MAX_CONVERT_PLACES));
535 if (place == MAX_CONVERT_PLACES) place--;
536 convert[place] = 0;
538 zpadlen = max - place;
539 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
540 if (zpadlen < 0) zpadlen = 0;
541 if (spadlen < 0) spadlen = 0;
542 if (flags & DP_F_ZERO) {
543 zpadlen = MAX(zpadlen, spadlen);
544 spadlen = 0;
546 if (flags & DP_F_MINUS)
547 spadlen = -spadlen; /* Left Justifty */
549 #ifdef DEBUG_SNPRINTF
550 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
551 zpadlen, spadlen, min, max, place);
552 #endif
554 /* Spaces */
555 while (spadlen > 0) {
556 dopr_outch(buffer, currlen, maxlen, ' ');
557 --spadlen;
560 /* Sign */
561 if (signvalue) dopr_outch(buffer, currlen, maxlen, signvalue);
563 /* Zeros */
564 if (zpadlen > 0) {
565 while (zpadlen > 0) {
566 dopr_outch(buffer, currlen, maxlen, '0');
567 --zpadlen;
571 /* Digits */
572 while (place > 0) dopr_outch(buffer, currlen, maxlen, convert[--place]);
574 /* Left Justified spaces */
575 while (spadlen < 0) {
576 dopr_outch(buffer, currlen, maxlen, ' ');
577 ++spadlen;
581 static void fmtqword(char *buffer, size_t *currlen, size_t maxlen,
582 sint64 value, int base, int min, int max, int flags)
584 #undef MAX_CONVERT_PLACES
585 #define MAX_CONVERT_PLACES 80
586 int signvalue = 0;
587 uint64 uvalue;
588 char convert[MAX_CONVERT_PLACES];
589 int place = 0;
590 int spadlen = 0; /* amount to space pad */
591 int zpadlen = 0; /* amount to zero pad */
592 int caps = 0;
594 if (max < 0) max = 0;
596 uvalue = value;
598 if (!(flags & DP_F_UNSIGNED)) {
599 if (value < 0) {
600 signvalue = '-';
601 uvalue = -uvalue;
602 } else {
603 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
604 signvalue = '+';
605 else if (flags & DP_F_SPACE)
606 signvalue = ' ';
610 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
612 do {
613 uint64 uv = uvalue % (uint64)base;
614 convert[place++] =
615 (caps? "0123456789ABCDEF":"0123456789abcdef")[uv];
616 uvalue = (uvalue / (uint64)base);
617 } while ((uvalue != 0) && (place < MAX_CONVERT_PLACES));
618 if (place == MAX_CONVERT_PLACES) place--;
619 convert[place] = 0;
621 zpadlen = max - place;
622 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
623 if (zpadlen < 0) zpadlen = 0;
624 if (spadlen < 0) spadlen = 0;
625 if (flags & DP_F_ZERO) {
626 zpadlen = MAX(zpadlen, spadlen);
627 spadlen = 0;
629 if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */
631 #ifdef DEBUG_SNPRINTF
632 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
633 zpadlen, spadlen, min, max, place);
634 #endif
636 /* Spaces */
637 while (spadlen > 0) {
638 dopr_outch(buffer, currlen, maxlen, ' ');
639 --spadlen;
642 /* Sign */
643 if (signvalue) dopr_outch(buffer, currlen, maxlen, signvalue);
645 /* Zeros */
646 if (zpadlen > 0) {
647 while (zpadlen > 0) {
648 dopr_outch(buffer, currlen, maxlen, '0');
649 --zpadlen;
653 /* Digits */
654 while (place > 0) dopr_outch(buffer, currlen, maxlen, convert[--place]);
656 /* Left Justified spaces */
657 while (spadlen < 0) {
658 dopr_outch(buffer, currlen, maxlen, ' ');
659 ++spadlen;
663 static LDOUBLE abs_val(LDOUBLE value)
665 return (value < 0) ? -value : value;
668 static LDOUBLE POW10(int exp)
670 LDOUBLE result = 1;
672 while (exp) {
673 result *= 10;
674 exp--;
677 return result;
680 static LLONG ROUND(LDOUBLE value)
682 LLONG intpart;
684 intpart = (LLONG)value;
685 value = value - intpart;
686 if (value >= 0.5) intpart++;
688 return intpart;
691 /* a replacement for modf that doesn't need the math library. Should
692 be portable, but slow */
693 static double my_modf(double x0, double *iptr)
695 int i;
696 long l;
697 double x = x0;
698 double f = 1.0;
700 for (i=0;i<100;i++) {
701 l = (long)x;
702 if (l <= (x+1) && l >= (x-1)) break;
703 x *= 0.1;
704 f *= 10.0;
707 if (i == 100) {
708 /* yikes! the number is beyond what we can handle. What do we do? */
709 (*iptr) = 0;
710 return 0;
713 if (i != 0) {
714 double i2;
715 double ret;
717 ret = my_modf(x0-l*f, &i2);
718 (*iptr) = l*f + i2;
719 return ret;
722 (*iptr) = l;
723 return x - (*iptr);
727 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
728 LDOUBLE fvalue, int min, int max, int flags)
730 int signvalue = 0;
731 double ufvalue;
732 char iconvert[311];
733 char fconvert[311];
734 int iplace = 0;
735 int fplace = 0;
736 int padlen = 0; /* amount to pad */
737 int zpadlen = 0;
738 int caps = 0;
739 int index;
740 double intpart;
741 double fracpart;
742 double temp;
745 * AIX manpage says the default is 0, but Solaris says the default
746 * is 6, and sprintf on AIX defaults to 6
748 if (max < 0)
749 max = 6;
751 ufvalue = abs_val (fvalue);
753 if (fvalue < 0) {
754 signvalue = '-';
755 } else {
756 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
757 signvalue = '+';
758 } else {
759 if (flags & DP_F_SPACE)
760 signvalue = ' ';
764 #if 0
765 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
766 #endif
768 #if 0
769 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
770 #endif
773 * Sorry, we only support 16 digits past the decimal because of our
774 * conversion method
776 if (max > 16)
777 max = 16;
779 /* We "cheat" by converting the fractional part to integer by
780 * multiplying by a factor of 10
783 temp = ufvalue;
784 my_modf(temp, &intpart);
786 fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
788 if (fracpart >= POW10(max)) {
789 intpart++;
790 fracpart -= POW10(max);
794 /* Convert integer part */
795 do {
796 temp = intpart;
797 my_modf(intpart*0.1, &intpart);
798 temp = temp*0.1;
799 index = (int) ((temp -intpart +0.05)* 10.0);
800 /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
801 /* printf ("%llf, %f, %x\n", temp, intpart, index); */
802 iconvert[iplace++] =
803 (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
804 } while (intpart && (iplace < 311));
805 if (iplace == 311) iplace--;
806 iconvert[iplace] = 0;
808 /* Convert fractional part */
809 if (fracpart)
811 do {
812 temp = fracpart;
813 my_modf(fracpart*0.1, &fracpart);
814 temp = temp*0.1;
815 index = (int) ((temp -fracpart +0.05)* 10.0);
816 /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
817 /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
818 fconvert[fplace++] =
819 (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
820 } while(fracpart && (fplace < 311));
821 if (fplace == 311) fplace--;
823 fconvert[fplace] = 0;
825 /* -1 for decimal point, another -1 if we are printing a sign */
826 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
827 zpadlen = max - fplace;
828 if (zpadlen < 0) zpadlen = 0;
829 if (padlen < 0)
830 padlen = 0;
831 if (flags & DP_F_MINUS)
832 padlen = -padlen; /* Left Justifty */
834 if ((flags & DP_F_ZERO) && (padlen > 0)) {
835 if (signvalue) {
836 dopr_outch(buffer, currlen, maxlen, signvalue);
837 --padlen;
838 signvalue = 0;
840 while (padlen > 0) {
841 dopr_outch(buffer, currlen, maxlen, '0');
842 --padlen;
845 while (padlen > 0) {
846 dopr_outch(buffer, currlen, maxlen, ' ');
847 --padlen;
849 if (signvalue)
850 dopr_outch(buffer, currlen, maxlen, signvalue);
852 while (iplace > 0)
853 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
855 #ifdef DEBUG_SNPRINTF
856 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
857 #endif
860 * Decimal point. This should probably use locale to find the correct
861 * char to print out.
863 if (max > 0) {
864 dopr_outch(buffer, currlen, maxlen, '.');
866 while (fplace > 0)
867 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
870 while (zpadlen > 0) {
871 dopr_outch(buffer, currlen, maxlen, '0');
872 --zpadlen;
875 while (padlen < 0) {
876 dopr_outch(buffer, currlen, maxlen, ' ');
877 ++padlen;
881 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
883 if (*currlen < maxlen) {
884 buffer[(*currlen)] = c;
886 (*currlen)++;
889 int ht_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
891 if ((int)count < 0) count = 0;
892 int res = dopr(str, count, fmt, args);
893 if (count) count--;
894 return str ? MIN(res, (int)count) : count;
897 int ht_snprintf(char *str, size_t count, const char *fmt,...)
899 size_t ret;
900 va_list ap;
902 va_start(ap, fmt);
903 ret = ht_vsnprintf(str, count, fmt, ap);
904 va_end(ap);
905 return ret;
908 int ht_vasprintf(char **ptr, const char *format, va_list ap)
910 int ret;
912 ret = dopr(NULL, 0, format, ap);
913 if (ret <= 0) {
914 *ptr = NULL;
915 return 0;
918 (*ptr) = (char *)malloc(ret+1);
919 if (!*ptr) return 0;
920 ret = ht_vsnprintf(*ptr, ret+1, format, ap);
922 return ret;
926 int ht_asprintf(char **ptr, const char *format, ...)
928 va_list ap;
929 int ret;
931 va_start(ap, format);
932 ret = ht_vasprintf(ptr, format, ap);
933 va_end(ap);
935 return ret;
938 int ht_vfprintf(FILE *file, const char *fmt, va_list args)
940 #if 0
941 char *buf;
942 int ret = ht_vasprintf(&buf, fmt, args);
943 fputs(buf, file);
944 free(buf);
945 #else
946 char buf[1024];
947 int ret = ht_vsnprintf(buf, sizeof buf, fmt, args);
948 fputs(buf, file);
949 #endif
950 return ret;
953 int ht_fprintf(FILE *file, const char *fmt, ...)
955 va_list ap;
956 int ret;
958 va_start(ap, fmt);
959 ret = ht_vfprintf(file, fmt, ap);
960 va_end(ap);
962 return ret;
966 int ht_vprintf(const char *fmt, va_list args)
968 return ht_vfprintf(stdout, fmt, args);
971 int ht_printf(const char *fmt, ...)
973 va_list ap;
974 int ret;
976 va_start(ap, fmt);
977 ret = ht_vprintf(fmt, ap);
978 va_end(ap);
980 return ret;
984 #endif //HAVE_SNPRINTF