/[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

Annotation of /src/tools/snprintf.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 23993 byte(s)
import upstream CVS
1 dpavlin 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