/[pearpc]/src/tools/snprintf.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/tools/snprintf.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 6 months ago) by dpavlin
File size: 23993 byte(s)
import upstream CVS
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 */
7
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...
14 *
15 * snprintf() is used instead of sprintf() as it does limit checks
16 * for string length. This covers a nasty loophole.
17 *
18 * The other functions are there to prevent NULL pointers from
19 * causing nast effects.
20 *
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.
27 *
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.
38 *
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.
42 *
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.
47 *
48 * Andrew Tridgell (tridge@samba.org) Oct 1998
49 * fixed handling of %.0f
50 * added test for HAVE_LONG_DOUBLE
51 *
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
55 *
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
65 #include <cctype>
66 #include <cstring>
67 #include <cstdlib>
68 #include <cstdio>
69 #include <cstdarg>
70 #include <sys/types.h>
71
72 #ifdef HAVE_CONFIG_H
73 #include "config.h"
74 #endif
75
76 #include "system/types.h"
77 #include "data.h"
78
79 #ifdef HAVE_CONFIG_H
80 #include "config.h"
81 #endif
82
83 #ifndef MIN
84 #define MIN(a, b) ((a) < (b) ? (a) : (b))
85 #endif
86 #ifndef MAX
87 #define MAX(a, b) ((a) > (b) ? (a) : (b))
88 #endif
89
90 #ifdef HAVE_LONG_DOUBLE
91 #define LDOUBLE long double
92 #else
93 #define LDOUBLE double
94 #endif
95
96 #ifdef HAVE_LONG_LONG
97 #define LLONG long long
98 #else
99 #define LLONG long
100 #endif
101
102 static size_t dopr(char *buffer, size_t maxlen, const char *format,
103 va_list args);
104 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
105 char *value, int flags, int min, int max);
106 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
107 long value, int base, int min, int max, int flags);
108 static void fmtqword(char *buffer, size_t *currlen, size_t maxlen,
109 sint64 value, int base, int min, int max, int flags);
110 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
111 LDOUBLE fvalue, int min, int max, int flags);
112 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
113
114 /*
115 * dopr(): poor man's version of doprintf
116 */
117
118 /* format read states */
119 #define DP_S_DEFAULT 0
120 #define DP_S_FLAGS 1
121 #define DP_S_MIN 2
122 #define DP_S_DOT 3
123 #define DP_S_MAX 4
124 #define DP_S_MOD 5
125 #define DP_S_CONV 6
126 #define DP_S_DONE 7
127
128 /* format flags - Bits */
129 #define DP_F_MINUS (1 << 0)
130 #define DP_F_PLUS (1 << 1)
131 #define DP_F_SPACE (1 << 2)
132 #define DP_F_NUM (1 << 3)
133 #define DP_F_ZERO (1 << 4)
134 #define DP_F_UP (1 << 5)
135 #define DP_F_UNSIGNED (1 << 6)
136
137 /* Conversion Flags */
138 #define DP_C_SHORT 1
139 #define DP_C_LONG 2
140 #define DP_C_LDOUBLE 3
141 #define DP_C_LLONG 4
142 #define DP_C_QWORD 5
143
144 #define char_to_int(p) ((p)- '0')
145 #ifndef MAX
146 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
147 #endif
148
149 static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
150 {
151 char ch;
152 LLONG value;
153 LDOUBLE fvalue;
154 char *strvalue;
155 int min;
156 int max;
157 int state;
158 int flags;
159 int cflags;
160 size_t currlen;
161
162 state = DP_S_DEFAULT;
163 currlen = flags = cflags = min = 0;
164 max = -1;
165 ch = *format++;
166
167 while (state != DP_S_DONE) {
168 if (ch == '\0') state = DP_S_DONE;
169
170 switch(state) {
171 case DP_S_DEFAULT:
172 if (ch == '%') {
173 state = DP_S_FLAGS;
174 } else {
175 dopr_outch(buffer, &currlen, maxlen, ch);
176 }
177 ch = *format++;
178 break;
179 case DP_S_FLAGS:
180 switch (ch) {
181 case '-':
182 flags |= DP_F_MINUS;
183 ch = *format++;
184 break;
185 case '+':
186 flags |= DP_F_PLUS;
187 ch = *format++;
188 break;
189 case ' ':
190 flags |= DP_F_SPACE;
191 ch = *format++;
192 break;
193 case '#':
194 flags |= DP_F_NUM;
195 ch = *format++;
196 break;
197 case '0':
198 flags |= DP_F_ZERO;
199 ch = *format++;
200 break;
201 default:
202 state = DP_S_MIN;
203 break;
204 }
205 break;
206 case DP_S_MIN:
207 if (isdigit((unsigned char)ch)) {
208 min = 10*min + char_to_int (ch);
209 ch = *format++;
210 } else if (ch == '*') {
211 min = va_arg (args, int);
212 ch = *format++;
213 state = DP_S_DOT;
214 } else {
215 state = DP_S_DOT;
216 }
217 break;
218 case DP_S_DOT:
219 if (ch == '.') {
220 state = DP_S_MAX;
221 ch = *format++;
222 } else {
223 state = DP_S_MOD;
224 }
225 break;
226 case DP_S_MAX:
227 if (isdigit((unsigned char)ch)) {
228 if (max < 0) max = 0;
229 max = 10*max + char_to_int (ch);
230 ch = *format++;
231 } else if (ch == '*') {
232 max = va_arg (args, int);
233 ch = *format++;
234 state = DP_S_MOD;
235 } else {
236 state = DP_S_MOD;
237 }
238 break;
239 case DP_S_MOD:
240 switch (ch) {
241 case 'h':
242 cflags = DP_C_SHORT;
243 ch = *format++;
244 break;
245 case 'l':
246 cflags = DP_C_LONG;
247 ch = *format++;
248 if (ch == 'l') { /* It's a long long */
249 cflags = DP_C_LLONG;
250 ch = *format++;
251 }
252 break;
253 case 'L':
254 cflags = DP_C_LDOUBLE;
255 ch = *format++;
256 break;
257 case 'q':
258 cflags = DP_C_QWORD;
259 ch = *format++;
260 break;
261 default:
262 break;
263 }
264 state = DP_S_CONV;
265 break;
266 case DP_S_CONV:
267 switch (ch) {
268 case 'b':
269 flags |= DP_F_UNSIGNED;
270 if (cflags == DP_C_SHORT) {
271 value = va_arg (args, unsigned int);
272 } else if (cflags == DP_C_LONG) {
273 value = (long)va_arg (args, unsigned long int);
274 } else if (cflags == DP_C_LLONG) {
275 value = (LLONG)va_arg (args, unsigned LLONG);
276 } else if (cflags == DP_C_QWORD) {
277 sint64 q = va_arg (args, sint64);
278 fmtqword(buffer, &currlen, maxlen, q, 2, min, max, flags);
279 break;
280 } else {
281 value = (long)va_arg (args, unsigned int);
282 }
283 fmtint (buffer, &currlen, maxlen, value, 2, min, max, flags);
284 break;
285 case 'd':
286 case 'i':
287 if (cflags == DP_C_SHORT) {
288 value = va_arg (args, int);
289 } else if (cflags == DP_C_LONG) {
290 value = va_arg (args, long int);
291 } else if (cflags == DP_C_LLONG) {
292 value = va_arg (args, LLONG);
293 } else if (cflags == DP_C_QWORD) {
294 sint64 q = va_arg (args, sint64);
295 fmtqword(buffer, &currlen, maxlen, q, 10, min, max, flags);
296 break;
297 } else {
298 value = va_arg (args, int);
299 }
300 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
301 break;
302 case 'o':
303 flags |= DP_F_UNSIGNED;
304 if (cflags == DP_C_SHORT) {
305 value = va_arg (args, unsigned int);
306 } else if (cflags == DP_C_LONG) {
307 value = (long)va_arg (args, unsigned long int);
308 } else if (cflags == DP_C_LLONG) {
309 value = (long)va_arg (args, unsigned LLONG);
310 } else if (cflags == DP_C_QWORD) {
311 sint64 q = va_arg (args, sint64);
312 fmtqword(buffer, &currlen, maxlen, q, 8, min, max, flags);
313 break;
314 } else {
315 value = (long)va_arg (args, unsigned int);
316 }
317 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
318 break;
319 case 'u':
320 flags |= DP_F_UNSIGNED;
321 if (cflags == DP_C_SHORT) {
322 value = va_arg (args, unsigned int);
323 } else if (cflags == DP_C_LONG) {
324 value = (long)va_arg (args, unsigned long int);
325 } else if (cflags == DP_C_LLONG) {
326 value = (LLONG)va_arg (args, unsigned LLONG);
327 } else if (cflags == DP_C_QWORD) {
328 sint64 q = va_arg (args, sint64);
329 fmtqword(buffer, &currlen, maxlen, q, 10, min, max, flags);
330 break;
331 } else {
332 value = (long)va_arg (args, unsigned int);
333 }
334 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
335 break;
336 case 'X':
337 flags |= DP_F_UP;
338 case 'x':
339 flags |= DP_F_UNSIGNED;
340 if (cflags == DP_C_SHORT) {
341 value = va_arg (args, unsigned int);
342 } else if (cflags == DP_C_LONG) {
343 value = (long)va_arg (args, unsigned long int);
344 } else if (cflags == DP_C_LLONG) {
345 value = (LLONG)va_arg (args, unsigned LLONG);
346 } else if (cflags == DP_C_QWORD) {
347 sint64 q = va_arg (args, sint64);
348 fmtqword(buffer, &currlen, maxlen, q, 16, min, max, flags);
349 break;
350 } else {
351 value = (long)va_arg (args, unsigned int);
352 }
353 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
354 break;
355 case 'f':
356 if (cflags == DP_C_LDOUBLE)
357 fvalue = va_arg (args, LDOUBLE);
358 else
359 fvalue = va_arg (args, double);
360 /* um, floating point? */
361 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
362 break;
363 case 'E':
364 flags |= DP_F_UP;
365 case 'e':
366 if (cflags == DP_C_LDOUBLE)
367 fvalue = va_arg (args, LDOUBLE);
368 else
369 fvalue = va_arg (args, double);
370 break;
371 case 'G':
372 flags |= DP_F_UP;
373 case 'g':
374 if (cflags == DP_C_LDOUBLE)
375 fvalue = va_arg (args, LDOUBLE);
376 else
377 fvalue = va_arg (args, double);
378 break;
379 case 'c':
380 dopr_outch(buffer, &currlen, maxlen, va_arg (args, int));
381 break;
382 case 's':
383 strvalue = va_arg (args, char *);
384 if (!strvalue) strvalue = "(null)";
385 if (max == -1) {
386 max = strlen(strvalue);
387 }
388 if (min > 0 && max >= 0 && min > max) max = min;
389 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
390 break;
391 case 'p':
392 strvalue = va_arg (args, char *);
393 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
394 break;
395 case 'n':
396 if (cflags == DP_C_SHORT) {
397 short int *num;
398 num = va_arg (args, short int *);
399 *num = currlen;
400 } else if (cflags == DP_C_LONG) {
401 long int *num;
402 num = va_arg (args, long int *);
403 *num = (long int)currlen;
404 } else if (cflags == DP_C_LLONG) {
405 LLONG *num;
406 num = va_arg (args, LLONG *);
407 *num = (LLONG)currlen;
408 } else {
409 int *num;
410 num = va_arg (args, int *);
411 *num = currlen;
412 }
413 break;
414 case '%':
415 dopr_outch(buffer, &currlen, maxlen, ch);
416 break;
417 case 'w':
418 /* not supported yet, treat as next char */
419 ch = *format++;
420 break;
421 case 'y': {
422 /* object */
423 Object *obj = va_arg (args, Object *);
424 if (obj) {
425 currlen += obj->toString(buffer+currlen, maxlen - currlen);
426 } else {
427 strvalue = "(null)";
428 if (max == -1) {
429 max = strlen(strvalue);
430 }
431 if (min > 0 && max >= 0 && min > max) max = min;
432 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
433 }
434 break;
435 }
436 default:
437 /* Unknown, skip */
438 break;
439 }
440 ch = *format++;
441 state = DP_S_DEFAULT;
442 flags = cflags = min = 0;
443 max = -1;
444 break;
445 case DP_S_DONE:
446 break;
447 default:
448 /* hmm? */
449 break; /* some picky compilers need this */
450 }
451 }
452 if (maxlen != 0) {
453 if (currlen < maxlen - 1)
454 buffer[currlen] = '\0';
455 else if (maxlen > 0)
456 buffer[maxlen - 1] = '\0';
457 }
458
459 return currlen;
460 }
461
462 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
463 char *value, int flags, int min, int max)
464 {
465 int padlen, strln; /* amount to pad */
466 int cnt = 0;
467
468 #ifdef DEBUG_SNPRINTF
469 printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
470 #endif
471
472 for (strln = 0; value[strln]; ++strln); /* strlen */
473 padlen = min - strln;
474 if (padlen < 0)
475 padlen = 0;
476 if (flags & DP_F_MINUS)
477 padlen = -padlen; /* Left Justify */
478
479 while ((padlen > 0) && (cnt < max)) {
480 dopr_outch(buffer, currlen, maxlen, ' ');
481 --padlen;
482 ++cnt;
483 }
484 while (*value && (cnt < max)) {
485 dopr_outch(buffer, currlen, maxlen, *value++);
486 ++cnt;
487 }
488 while ((padlen < 0) && (cnt < max)) {
489 dopr_outch(buffer, currlen, maxlen, ' ');
490 ++padlen;
491 ++cnt;
492 }
493 }
494
495 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
496
497 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
498 long value, int base, int min, int max, int flags)
499 {
500 #define MAX_CONVERT_PLACES 40
501 int signvalue = 0;
502 unsigned long uvalue;
503 char convert[MAX_CONVERT_PLACES];
504 int place = 0;
505 int spadlen = 0; /* amount to space pad */
506 int zpadlen = 0; /* amount to zero pad */
507 int caps = 0;
508
509 if (max < 0)
510 max = 0;
511
512 uvalue = value;
513
514 if (!(flags & DP_F_UNSIGNED)) {
515 if (value < 0) {
516 signvalue = '-';
517 uvalue = -value;
518 } else {
519 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
520 signvalue = '+';
521 else if (flags & DP_F_SPACE)
522 signvalue = ' ';
523 }
524 }
525
526 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
527
528 do {
529 convert[place++] =
530 (caps? "0123456789ABCDEF":"0123456789abcdef")[uvalue % (unsigned)base];
531 uvalue = (uvalue / (unsigned)base );
532 } while (uvalue && (place < MAX_CONVERT_PLACES));
533 if (place == MAX_CONVERT_PLACES) place--;
534 convert[place] = 0;
535
536 zpadlen = max - place;
537 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
538 if (zpadlen < 0) zpadlen = 0;
539 if (spadlen < 0) spadlen = 0;
540 if (flags & DP_F_ZERO) {
541 zpadlen = MAX(zpadlen, spadlen);
542 spadlen = 0;
543 }
544 if (flags & DP_F_MINUS)
545 spadlen = -spadlen; /* Left Justifty */
546
547 #ifdef DEBUG_SNPRINTF
548 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
549 zpadlen, spadlen, min, max, place);
550 #endif
551
552 /* Spaces */
553 while (spadlen > 0) {
554 dopr_outch(buffer, currlen, maxlen, ' ');
555 --spadlen;
556 }
557
558 /* Sign */
559 if (signvalue) dopr_outch(buffer, currlen, maxlen, signvalue);
560
561 /* Zeros */
562 if (zpadlen > 0) {
563 while (zpadlen > 0) {
564 dopr_outch(buffer, currlen, maxlen, '0');
565 --zpadlen;
566 }
567 }
568
569 /* Digits */
570 while (place > 0) dopr_outch(buffer, currlen, maxlen, convert[--place]);
571
572 /* Left Justified spaces */
573 while (spadlen < 0) {
574 dopr_outch(buffer, currlen, maxlen, ' ');
575 ++spadlen;
576 }
577 }
578
579 static void fmtqword(char *buffer, size_t *currlen, size_t maxlen,
580 sint64 value, int base, int min, int max, int flags)
581 {
582 #undef MAX_CONVERT_PLACES
583 #define MAX_CONVERT_PLACES 80
584 int signvalue = 0;
585 uint64 uvalue;
586 char convert[MAX_CONVERT_PLACES];
587 int place = 0;
588 int spadlen = 0; /* amount to space pad */
589 int zpadlen = 0; /* amount to zero pad */
590 int caps = 0;
591
592 if (max < 0) max = 0;
593
594 uvalue = value;
595
596 if (!(flags & DP_F_UNSIGNED)) {
597 if (value < 0) {
598 signvalue = '-';
599 uvalue = -uvalue;
600 } else {
601 if (flags & DP_F_PLUS) /* Do a sign (+/i) */
602 signvalue = '+';
603 else if (flags & DP_F_SPACE)
604 signvalue = ' ';
605 }
606 }
607
608 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
609
610 do {
611 uint64 uv = uvalue % (uint64)base;
612 convert[place++] =
613 (caps? "0123456789ABCDEF":"0123456789abcdef")[uv];
614 uvalue = (uvalue / (uint64)base);
615 } while ((uvalue != 0) && (place < MAX_CONVERT_PLACES));
616 if (place == MAX_CONVERT_PLACES) place--;
617 convert[place] = 0;
618
619 zpadlen = max - place;
620 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
621 if (zpadlen < 0) zpadlen = 0;
622 if (spadlen < 0) spadlen = 0;
623 if (flags & DP_F_ZERO) {
624 zpadlen = MAX(zpadlen, spadlen);
625 spadlen = 0;
626 }
627 if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */
628
629 #ifdef DEBUG_SNPRINTF
630 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
631 zpadlen, spadlen, min, max, place);
632 #endif
633
634 /* Spaces */
635 while (spadlen > 0) {
636 dopr_outch(buffer, currlen, maxlen, ' ');
637 --spadlen;
638 }
639
640 /* Sign */
641 if (signvalue) dopr_outch(buffer, currlen, maxlen, signvalue);
642
643 /* Zeros */
644 if (zpadlen > 0) {
645 while (zpadlen > 0) {
646 dopr_outch(buffer, currlen, maxlen, '0');
647 --zpadlen;
648 }
649 }
650
651 /* Digits */
652 while (place > 0) dopr_outch(buffer, currlen, maxlen, convert[--place]);
653
654 /* Left Justified spaces */
655 while (spadlen < 0) {
656 dopr_outch(buffer, currlen, maxlen, ' ');
657 ++spadlen;
658 }
659 }
660
661 static LDOUBLE abs_val(LDOUBLE value)
662 {
663 return (value < 0) ? -value : value;
664 }
665
666 static LDOUBLE POW10(int exp)
667 {
668 LDOUBLE result = 1;
669
670 while (exp) {
671 result *= 10;
672 exp--;
673 }
674
675 return result;
676 }
677
678 static LLONG ROUND(LDOUBLE value)
679 {
680 LLONG intpart;
681
682 intpart = (LLONG)value;
683 value = value - intpart;
684 if (value >= 0.5) intpart++;
685
686 return intpart;
687 }
688
689 /* a replacement for modf that doesn't need the math library. Should
690 be portable, but slow */
691 static double my_modf(double x0, double *iptr)
692 {
693 int i;
694 long l;
695 double x = x0;
696 double f = 1.0;
697
698 for (i=0;i<100;i++) {
699 l = (long)x;
700 if (l <= (x+1) && l >= (x-1)) break;
701 x *= 0.1;
702 f *= 10.0;
703 }
704
705 if (i == 100) {
706 /* yikes! the number is beyond what we can handle. What do we do? */
707 (*iptr) = 0;
708 return 0;
709 }
710
711 if (i != 0) {
712 double i2;
713 double ret;
714
715 ret = my_modf(x0-l*f, &i2);
716 (*iptr) = l*f + i2;
717 return ret;
718 }
719
720 (*iptr) = l;
721 return x - (*iptr);
722 }
723
724
725 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
726 LDOUBLE fvalue, int min, int max, int flags)
727 {
728 int signvalue = 0;
729 double ufvalue;
730 char iconvert[311];
731 char fconvert[311];
732 int iplace = 0;
733 int fplace = 0;
734 int padlen = 0; /* amount to pad */
735 int zpadlen = 0;
736 int caps = 0;
737 int index;
738 double intpart;
739 double fracpart;
740 double temp;
741
742 /*
743 * AIX manpage says the default is 0, but Solaris says the default
744 * is 6, and sprintf on AIX defaults to 6
745 */
746 if (max < 0)
747 max = 6;
748
749 ufvalue = abs_val (fvalue);
750
751 if (fvalue < 0) {
752 signvalue = '-';
753 } else {
754 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
755 signvalue = '+';
756 } else {
757 if (flags & DP_F_SPACE)
758 signvalue = ' ';
759 }
760 }
761
762 #if 0
763 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
764 #endif
765
766 #if 0
767 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
768 #endif
769
770 /*
771 * Sorry, we only support 16 digits past the decimal because of our
772 * conversion method
773 */
774 if (max > 16)
775 max = 16;
776
777 /* We "cheat" by converting the fractional part to integer by
778 * multiplying by a factor of 10
779 */
780
781 temp = ufvalue;
782 my_modf(temp, &intpart);
783
784 fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
785
786 if (fracpart >= POW10(max)) {
787 intpart++;
788 fracpart -= POW10(max);
789 }
790
791
792 /* Convert integer part */
793 do {
794 temp = intpart;
795 my_modf(intpart*0.1, &intpart);
796 temp = temp*0.1;
797 index = (int) ((temp -intpart +0.05)* 10.0);
798 /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
799 /* printf ("%llf, %f, %x\n", temp, intpart, index); */
800 iconvert[iplace++] =
801 (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
802 } while (intpart && (iplace < 311));
803 if (iplace == 311) iplace--;
804 iconvert[iplace] = 0;
805
806 /* Convert fractional part */
807 if (fracpart)
808 {
809 do {
810 temp = fracpart;
811 my_modf(fracpart*0.1, &fracpart);
812 temp = temp*0.1;
813 index = (int) ((temp -fracpart +0.05)* 10.0);
814 /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
815 /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
816 fconvert[fplace++] =
817 (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
818 } while(fracpart && (fplace < 311));
819 if (fplace == 311) fplace--;
820 }
821 fconvert[fplace] = 0;
822
823 /* -1 for decimal point, another -1 if we are printing a sign */
824 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
825 zpadlen = max - fplace;
826 if (zpadlen < 0) zpadlen = 0;
827 if (padlen < 0)
828 padlen = 0;
829 if (flags & DP_F_MINUS)
830 padlen = -padlen; /* Left Justifty */
831
832 if ((flags & DP_F_ZERO) && (padlen > 0)) {
833 if (signvalue) {
834 dopr_outch(buffer, currlen, maxlen, signvalue);
835 --padlen;
836 signvalue = 0;
837 }
838 while (padlen > 0) {
839 dopr_outch(buffer, currlen, maxlen, '0');
840 --padlen;
841 }
842 }
843 while (padlen > 0) {
844 dopr_outch(buffer, currlen, maxlen, ' ');
845 --padlen;
846 }
847 if (signvalue)
848 dopr_outch(buffer, currlen, maxlen, signvalue);
849
850 while (iplace > 0)
851 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
852
853 #ifdef DEBUG_SNPRINTF
854 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
855 #endif
856
857 /*
858 * Decimal point. This should probably use locale to find the correct
859 * char to print out.
860 */
861 if (max > 0) {
862 dopr_outch(buffer, currlen, maxlen, '.');
863
864 while (fplace > 0)
865 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
866 }
867
868 while (zpadlen > 0) {
869 dopr_outch(buffer, currlen, maxlen, '0');
870 --zpadlen;
871 }
872
873 while (padlen < 0) {
874 dopr_outch(buffer, currlen, maxlen, ' ');
875 ++padlen;
876 }
877 }
878
879 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
880 {
881 if (*currlen < maxlen) {
882 buffer[(*currlen)] = c;
883 }
884 (*currlen)++;
885 }
886
887 int ht_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
888 {
889 if ((int)count < 0) count = 0;
890 int res = dopr(str, count, fmt, args);
891 if (count) count--;
892 return str ? MIN(res, (int)count) : count;
893 }
894
895 int ht_snprintf(char *str, size_t count, const char *fmt,...)
896 {
897 size_t ret;
898 va_list ap;
899
900 va_start(ap, fmt);
901 ret = ht_vsnprintf(str, count, fmt, ap);
902 va_end(ap);
903 return ret;
904 }
905
906 int ht_vasprintf(char **ptr, const char *format, va_list ap)
907 {
908 int ret;
909
910 ret = dopr(NULL, 0, format, ap);
911 if (ret <= 0) {
912 *ptr = NULL;
913 return 0;
914 }
915
916 (*ptr) = (char *)malloc(ret+1);
917 if (!*ptr) return 0;
918 ret = ht_vsnprintf(*ptr, ret+1, format, ap);
919
920 return ret;
921 }
922
923
924 int ht_asprintf(char **ptr, const char *format, ...)
925 {
926 va_list ap;
927 int ret;
928
929 va_start(ap, format);
930 ret = ht_vasprintf(ptr, format, ap);
931 va_end(ap);
932
933 return ret;
934 }
935
936 int ht_vfprintf(FILE *file, const char *fmt, va_list args)
937 {
938 #if 0
939 char *buf;
940 int ret = ht_vasprintf(&buf, fmt, args);
941 fputs(buf, file);
942 free(buf);
943 #else
944 char buf[1024];
945 int ret = ht_vsnprintf(buf, sizeof buf, fmt, args);
946 fputs(buf, file);
947 #endif
948 return ret;
949 }
950
951 int ht_fprintf(FILE *file, const char *fmt, ...)
952 {
953 va_list ap;
954 int ret;
955
956 va_start(ap, fmt);
957 ret = ht_vfprintf(file, fmt, ap);
958 va_end(ap);
959
960 return ret;
961 }
962
963
964 int ht_vprintf(const char *fmt, va_list args)
965 {
966 return ht_vfprintf(stdout, fmt, args);
967 }
968
969 int ht_printf(const char *fmt, ...)
970 {
971 va_list ap;
972 int ret;
973
974 va_start(ap, fmt);
975 ret = ht_vprintf(fmt, ap);
976 va_end(ap);
977
978 return ret;
979 }
980
981

  ViewVC Help
Powered by ViewVC 1.1.26