import of openssh-5.8p1
[openssh.git] / openbsd-compat / bsd-snprintf.c
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  * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
57  * actually print args for %g and %e
58  * 
59  * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
60  * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
61  * see any include file that is guaranteed to be here, so I'm defining it
62  * locally.  Fixes AIX and Solaris builds.
63  * 
64  * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
65  * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
66  * functions
67  * 
68  * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
69  * Fix usage of va_list passed as an arg.  Use __va_copy before using it
70  * when it exists.
71  * 
72  * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
73  * Fix incorrect zpadlen handling in fmtfp.
74  * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
75  * few mods to make it easier to compile the tests.
76  * addedd the "Ollie" test to the floating point ones.
77  *
78  * Martin Pool (mbp@samba.org) April 2003
79  *    Remove NO_CONFIG_H so that the test case can be built within a source
80  *    tree with less trouble.
81  *    Remove unnecessary SAFE_FREE() definition.
82  *
83  * Martin Pool (mbp@samba.org) May 2003
84  *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
85  *
86  *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
87  *    if the C library has some snprintf functions already.
88  *
89  * Damien Miller (djm@mindrot.org) Jan 2007
90  *    Fix integer overflows in return value.
91  *    Make formatting quite a bit faster by inlining dopr_outch()
92  *
93  **************************************************************/
94
95 #include "includes.h"
96
97 #if defined(BROKEN_SNPRINTF)            /* For those with broken snprintf() */
98 # undef HAVE_SNPRINTF
99 # undef HAVE_VSNPRINTF
100 #endif
101
102 #ifndef VA_COPY
103 # ifdef HAVE_VA_COPY
104 #  define VA_COPY(dest, src) va_copy(dest, src)
105 # else
106 #  ifdef HAVE___VA_COPY
107 #   define VA_COPY(dest, src) __va_copy(dest, src)
108 #  else
109 #   define VA_COPY(dest, src) (dest) = (src)
110 #  endif
111 # endif
112 #endif
113
114 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
115
116 #include <ctype.h>
117 #include <stdarg.h>
118 #include <stdlib.h>
119 #include <string.h>
120 #include <limits.h>
121 #include <errno.h>
122
123 #ifdef HAVE_LONG_DOUBLE
124 # define LDOUBLE long double
125 #else
126 # define LDOUBLE double
127 #endif
128
129 #ifdef HAVE_LONG_LONG
130 # define LLONG long long
131 #else
132 # define LLONG long
133 #endif
134
135 /*
136  * dopr(): poor man's version of doprintf
137  */
138
139 /* format read states */
140 #define DP_S_DEFAULT 0
141 #define DP_S_FLAGS   1
142 #define DP_S_MIN     2
143 #define DP_S_DOT     3
144 #define DP_S_MAX     4
145 #define DP_S_MOD     5
146 #define DP_S_CONV    6
147 #define DP_S_DONE    7
148
149 /* format flags - Bits */
150 #define DP_F_MINUS      (1 << 0)
151 #define DP_F_PLUS       (1 << 1)
152 #define DP_F_SPACE      (1 << 2)
153 #define DP_F_NUM        (1 << 3)
154 #define DP_F_ZERO       (1 << 4)
155 #define DP_F_UP         (1 << 5)
156 #define DP_F_UNSIGNED   (1 << 6)
157
158 /* Conversion Flags */
159 #define DP_C_SHORT   1
160 #define DP_C_LONG    2
161 #define DP_C_LDOUBLE 3
162 #define DP_C_LLONG   4
163
164 #define char_to_int(p) ((p)- '0')
165 #ifndef MAX
166 # define MAX(p,q) (((p) >= (q)) ? (p) : (q))
167 #endif
168
169 #define DOPR_OUTCH(buf, pos, buflen, thechar) \
170         do { \
171                 if (pos + 1 >= INT_MAX) { \
172                         errno = ERANGE; \
173                         return -1; \
174                 } \
175                 if (pos < buflen) \
176                         buf[pos] = thechar; \
177                 (pos)++; \
178         } while (0)
179
180 static int dopr(char *buffer, size_t maxlen, const char *format, 
181     va_list args_in);
182 static int fmtstr(char *buffer, size_t *currlen, size_t maxlen,
183     char *value, int flags, int min, int max);
184 static int fmtint(char *buffer, size_t *currlen, size_t maxlen,
185     LLONG value, int base, int min, int max, int flags);
186 static int fmtfp(char *buffer, size_t *currlen, size_t maxlen,
187     LDOUBLE fvalue, int min, int max, int flags);
188
189 static int
190 dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
191 {
192         char ch;
193         LLONG value;
194         LDOUBLE fvalue;
195         char *strvalue;
196         int min;
197         int max;
198         int state;
199         int flags;
200         int cflags;
201         size_t currlen;
202         va_list args;
203
204         VA_COPY(args, args_in);
205         
206         state = DP_S_DEFAULT;
207         currlen = flags = cflags = min = 0;
208         max = -1;
209         ch = *format++;
210         
211         while (state != DP_S_DONE) {
212                 if (ch == '\0') 
213                         state = DP_S_DONE;
214
215                 switch(state) {
216                 case DP_S_DEFAULT:
217                         if (ch == '%') 
218                                 state = DP_S_FLAGS;
219                         else
220                                 DOPR_OUTCH(buffer, currlen, maxlen, ch);
221                         ch = *format++;
222                         break;
223                 case DP_S_FLAGS:
224                         switch (ch) {
225                         case '-':
226                                 flags |= DP_F_MINUS;
227                                 ch = *format++;
228                                 break;
229                         case '+':
230                                 flags |= DP_F_PLUS;
231                                 ch = *format++;
232                                 break;
233                         case ' ':
234                                 flags |= DP_F_SPACE;
235                                 ch = *format++;
236                                 break;
237                         case '#':
238                                 flags |= DP_F_NUM;
239                                 ch = *format++;
240                                 break;
241                         case '0':
242                                 flags |= DP_F_ZERO;
243                                 ch = *format++;
244                                 break;
245                         default:
246                                 state = DP_S_MIN;
247                                 break;
248                         }
249                         break;
250                 case DP_S_MIN:
251                         if (isdigit((unsigned char)ch)) {
252                                 min = 10*min + char_to_int (ch);
253                                 ch = *format++;
254                         } else if (ch == '*') {
255                                 min = va_arg (args, int);
256                                 ch = *format++;
257                                 state = DP_S_DOT;
258                         } else {
259                                 state = DP_S_DOT;
260                         }
261                         break;
262                 case DP_S_DOT:
263                         if (ch == '.') {
264                                 state = DP_S_MAX;
265                                 ch = *format++;
266                         } else { 
267                                 state = DP_S_MOD;
268                         }
269                         break;
270                 case DP_S_MAX:
271                         if (isdigit((unsigned char)ch)) {
272                                 if (max < 0)
273                                         max = 0;
274                                 max = 10*max + char_to_int (ch);
275                                 ch = *format++;
276                         } else if (ch == '*') {
277                                 max = va_arg (args, int);
278                                 ch = *format++;
279                                 state = DP_S_MOD;
280                         } else {
281                                 state = DP_S_MOD;
282                         }
283                         break;
284                 case DP_S_MOD:
285                         switch (ch) {
286                         case 'h':
287                                 cflags = DP_C_SHORT;
288                                 ch = *format++;
289                                 break;
290                         case 'l':
291                                 cflags = DP_C_LONG;
292                                 ch = *format++;
293                                 if (ch == 'l') {        /* It's a long long */
294                                         cflags = DP_C_LLONG;
295                                         ch = *format++;
296                                 }
297                                 break;
298                         case 'L':
299                                 cflags = DP_C_LDOUBLE;
300                                 ch = *format++;
301                                 break;
302                         default:
303                                 break;
304                         }
305                         state = DP_S_CONV;
306                         break;
307                 case DP_S_CONV:
308                         switch (ch) {
309                         case 'd':
310                         case 'i':
311                                 if (cflags == DP_C_SHORT) 
312                                         value = va_arg (args, int);
313                                 else if (cflags == DP_C_LONG)
314                                         value = va_arg (args, long int);
315                                 else if (cflags == DP_C_LLONG)
316                                         value = va_arg (args, LLONG);
317                                 else
318                                         value = va_arg (args, int);
319                                 if (fmtint(buffer, &currlen, maxlen,
320                                     value, 10, min, max, flags) == -1)
321                                         return -1;
322                                 break;
323                         case 'o':
324                                 flags |= DP_F_UNSIGNED;
325                                 if (cflags == DP_C_SHORT)
326                                         value = va_arg (args, unsigned int);
327                                 else if (cflags == DP_C_LONG)
328                                         value = (long)va_arg (args, unsigned long int);
329                                 else if (cflags == DP_C_LLONG)
330                                         value = (long)va_arg (args, unsigned LLONG);
331                                 else
332                                         value = (long)va_arg (args, unsigned int);
333                                 if (fmtint(buffer, &currlen, maxlen, value,
334                                     8, min, max, flags) == -1)
335                                         return -1;
336                                 break;
337                         case 'u':
338                                 flags |= DP_F_UNSIGNED;
339                                 if (cflags == DP_C_SHORT)
340                                         value = va_arg (args, unsigned int);
341                                 else if (cflags == DP_C_LONG)
342                                         value = (long)va_arg (args, unsigned long int);
343                                 else if (cflags == DP_C_LLONG)
344                                         value = (LLONG)va_arg (args, unsigned LLONG);
345                                 else
346                                         value = (long)va_arg (args, unsigned int);
347                                 if (fmtint(buffer, &currlen, maxlen, value,
348                                     10, min, max, flags) == -1)
349                                         return -1;
350                                 break;
351                         case 'X':
352                                 flags |= DP_F_UP;
353                         case 'x':
354                                 flags |= DP_F_UNSIGNED;
355                                 if (cflags == DP_C_SHORT)
356                                         value = va_arg (args, unsigned int);
357                                 else if (cflags == DP_C_LONG)
358                                         value = (long)va_arg (args, unsigned long int);
359                                 else if (cflags == DP_C_LLONG)
360                                         value = (LLONG)va_arg (args, unsigned LLONG);
361                                 else
362                                         value = (long)va_arg (args, unsigned int);
363                                 if (fmtint(buffer, &currlen, maxlen, value,
364                                     16, min, max, flags) == -1)
365                                         return -1;
366                                 break;
367                         case 'f':
368                                 if (cflags == DP_C_LDOUBLE)
369                                         fvalue = va_arg (args, LDOUBLE);
370                                 else
371                                         fvalue = va_arg (args, double);
372                                 if (fmtfp(buffer, &currlen, maxlen, fvalue,
373                                     min, max, flags) == -1)
374                                         return -1;
375                                 break;
376                         case 'E':
377                                 flags |= DP_F_UP;
378                         case 'e':
379                                 if (cflags == DP_C_LDOUBLE)
380                                         fvalue = va_arg (args, LDOUBLE);
381                                 else
382                                         fvalue = va_arg (args, double);
383                                 if (fmtfp(buffer, &currlen, maxlen, fvalue,
384                                     min, max, flags) == -1)
385                                         return -1;
386                                 break;
387                         case 'G':
388                                 flags |= DP_F_UP;
389                         case 'g':
390                                 if (cflags == DP_C_LDOUBLE)
391                                         fvalue = va_arg (args, LDOUBLE);
392                                 else
393                                         fvalue = va_arg (args, double);
394                                 if (fmtfp(buffer, &currlen, maxlen, fvalue,
395                                     min, max, flags) == -1)
396                                         return -1;
397                                 break;
398                         case 'c':
399                                 DOPR_OUTCH(buffer, currlen, maxlen,
400                                     va_arg (args, int));
401                                 break;
402                         case 's':
403                                 strvalue = va_arg (args, char *);
404                                 if (!strvalue) strvalue = "(NULL)";
405                                 if (max == -1) {
406                                         max = strlen(strvalue);
407                                 }
408                                 if (min > 0 && max >= 0 && min > max) max = min;
409                                 if (fmtstr(buffer, &currlen, maxlen,
410                                     strvalue, flags, min, max) == -1)
411                                         return -1;
412                                 break;
413                         case 'p':
414                                 strvalue = va_arg (args, void *);
415                                 if (fmtint(buffer, &currlen, maxlen,
416                                     (long) strvalue, 16, min, max, flags) == -1)
417                                         return -1;
418                                 break;
419                         case 'n':
420                                 if (cflags == DP_C_SHORT) {
421                                         short int *num;
422                                         num = va_arg (args, short int *);
423                                         *num = currlen;
424                                 } else if (cflags == DP_C_LONG) {
425                                         long int *num;
426                                         num = va_arg (args, long int *);
427                                         *num = (long int)currlen;
428                                 } else if (cflags == DP_C_LLONG) {
429                                         LLONG *num;
430                                         num = va_arg (args, LLONG *);
431                                         *num = (LLONG)currlen;
432                                 } else {
433                                         int *num;
434                                         num = va_arg (args, int *);
435                                         *num = currlen;
436                                 }
437                                 break;
438                         case '%':
439                                 DOPR_OUTCH(buffer, currlen, maxlen, ch);
440                                 break;
441                         case 'w':
442                                 /* not supported yet, treat as next char */
443                                 ch = *format++;
444                                 break;
445                         default:
446                                 /* Unknown, skip */
447                                 break;
448                         }
449                         ch = *format++;
450                         state = DP_S_DEFAULT;
451                         flags = cflags = min = 0;
452                         max = -1;
453                         break;
454                 case DP_S_DONE:
455                         break;
456                 default:
457                         /* hmm? */
458                         break; /* some picky compilers need this */
459                 }
460         }
461         if (maxlen != 0) {
462                 if (currlen < maxlen - 1) 
463                         buffer[currlen] = '\0';
464                 else if (maxlen > 0) 
465                         buffer[maxlen - 1] = '\0';
466         }
467         
468         return currlen < INT_MAX ? (int)currlen : -1;
469 }
470
471 static int
472 fmtstr(char *buffer, size_t *currlen, size_t maxlen,
473     char *value, int flags, int min, int max)
474 {
475         int padlen, strln;     /* amount to pad */
476         int cnt = 0;
477
478 #ifdef DEBUG_SNPRINTF
479         printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
480 #endif
481         if (value == 0) {
482                 value = "<NULL>";
483         }
484
485         for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
486         padlen = min - strln;
487         if (padlen < 0) 
488                 padlen = 0;
489         if (flags & DP_F_MINUS) 
490                 padlen = -padlen; /* Left Justify */
491         
492         while ((padlen > 0) && (cnt < max)) {
493                 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
494                 --padlen;
495                 ++cnt;
496         }
497         while (*value && (cnt < max)) {
498                 DOPR_OUTCH(buffer, *currlen, maxlen, *value);
499                 *value++;
500                 ++cnt;
501         }
502         while ((padlen < 0) && (cnt < max)) {
503                 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
504                 ++padlen;
505                 ++cnt;
506         }
507         return 0;
508 }
509
510 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
511
512 static int
513 fmtint(char *buffer, size_t *currlen, size_t maxlen,
514                     LLONG value, int base, int min, int max, int flags)
515 {
516         int signvalue = 0;
517         unsigned LLONG uvalue;
518         char convert[20];
519         int place = 0;
520         int spadlen = 0; /* amount to space pad */
521         int zpadlen = 0; /* amount to zero pad */
522         int caps = 0;
523         
524         if (max < 0)
525                 max = 0;
526         
527         uvalue = value;
528         
529         if(!(flags & DP_F_UNSIGNED)) {
530                 if( value < 0 ) {
531                         signvalue = '-';
532                         uvalue = -value;
533                 } else {
534                         if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
535                                 signvalue = '+';
536                         else if (flags & DP_F_SPACE)
537                                 signvalue = ' ';
538                 }
539         }
540   
541         if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
542
543         do {
544                 convert[place++] =
545                         (caps? "0123456789ABCDEF":"0123456789abcdef")
546                         [uvalue % (unsigned)base  ];
547                 uvalue = (uvalue / (unsigned)base );
548         } while(uvalue && (place < 20));
549         if (place == 20) place--;
550         convert[place] = 0;
551
552         zpadlen = max - place;
553         spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
554         if (zpadlen < 0) zpadlen = 0;
555         if (spadlen < 0) spadlen = 0;
556         if (flags & DP_F_ZERO) {
557                 zpadlen = MAX(zpadlen, spadlen);
558                 spadlen = 0;
559         }
560         if (flags & DP_F_MINUS) 
561                 spadlen = -spadlen; /* Left Justifty */
562
563 #ifdef DEBUG_SNPRINTF
564         printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
565                zpadlen, spadlen, min, max, place);
566 #endif
567
568         /* Spaces */
569         while (spadlen > 0) {
570                 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
571                 --spadlen;
572         }
573
574         /* Sign */
575         if (signvalue) 
576                 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
577
578         /* Zeros */
579         if (zpadlen > 0) {
580                 while (zpadlen > 0) {
581                         DOPR_OUTCH(buffer, *currlen, maxlen, '0');
582                         --zpadlen;
583                 }
584         }
585
586         /* Digits */
587         while (place > 0) {
588                 --place;
589                 DOPR_OUTCH(buffer, *currlen, maxlen, convert[place]);
590         }
591   
592         /* Left Justified spaces */
593         while (spadlen < 0) {
594                 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
595                 ++spadlen;
596         }
597         return 0;
598 }
599
600 static LDOUBLE abs_val(LDOUBLE value)
601 {
602         LDOUBLE result = value;
603
604         if (value < 0)
605                 result = -value;
606         
607         return result;
608 }
609
610 static LDOUBLE POW10(int val)
611 {
612         LDOUBLE result = 1;
613         
614         while (val) {
615                 result *= 10;
616                 val--;
617         }
618   
619         return result;
620 }
621
622 static LLONG ROUND(LDOUBLE value)
623 {
624         LLONG intpart;
625
626         intpart = (LLONG)value;
627         value = value - intpart;
628         if (value >= 0.5) intpart++;
629         
630         return intpart;
631 }
632
633 /* a replacement for modf that doesn't need the math library. Should
634    be portable, but slow */
635 static double my_modf(double x0, double *iptr)
636 {
637         int i;
638         long l;
639         double x = x0;
640         double f = 1.0;
641
642         for (i=0;i<100;i++) {
643                 l = (long)x;
644                 if (l <= (x+1) && l >= (x-1)) break;
645                 x *= 0.1;
646                 f *= 10.0;
647         }
648
649         if (i == 100) {
650                 /*
651                  * yikes! the number is beyond what we can handle.
652                  * What do we do?
653                  */
654                 (*iptr) = 0;
655                 return 0;
656         }
657
658         if (i != 0) {
659                 double i2;
660                 double ret;
661
662                 ret = my_modf(x0-l*f, &i2);
663                 (*iptr) = l*f + i2;
664                 return ret;
665         } 
666
667         (*iptr) = l;
668         return x - (*iptr);
669 }
670
671
672 static int
673 fmtfp (char *buffer, size_t *currlen, size_t maxlen,
674     LDOUBLE fvalue, int min, int max, int flags)
675 {
676         int signvalue = 0;
677         double ufvalue;
678         char iconvert[311];
679         char fconvert[311];
680         int iplace = 0;
681         int fplace = 0;
682         int padlen = 0; /* amount to pad */
683         int zpadlen = 0; 
684         int caps = 0;
685         int idx;
686         double intpart;
687         double fracpart;
688         double temp;
689   
690         /* 
691          * AIX manpage says the default is 0, but Solaris says the default
692          * is 6, and sprintf on AIX defaults to 6
693          */
694         if (max < 0)
695                 max = 6;
696
697         ufvalue = abs_val (fvalue);
698
699         if (fvalue < 0) {
700                 signvalue = '-';
701         } else {
702                 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
703                         signvalue = '+';
704                 } else {
705                         if (flags & DP_F_SPACE)
706                                 signvalue = ' ';
707                 }
708         }
709
710 #if 0
711         if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
712 #endif
713
714 #if 0
715          if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
716 #endif
717
718         /* 
719          * Sorry, we only support 16 digits past the decimal because of our 
720          * conversion method
721          */
722         if (max > 16)
723                 max = 16;
724
725         /* We "cheat" by converting the fractional part to integer by
726          * multiplying by a factor of 10
727          */
728
729         temp = ufvalue;
730         my_modf(temp, &intpart);
731
732         fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
733         
734         if (fracpart >= POW10(max)) {
735                 intpart++;
736                 fracpart -= POW10(max);
737         }
738
739         /* Convert integer part */
740         do {
741                 temp = intpart*0.1;
742                 my_modf(temp, &intpart);
743                 idx = (int) ((temp -intpart +0.05)* 10.0);
744                 /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
745                 /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
746                 iconvert[iplace++] =
747                         (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
748         } while (intpart && (iplace < 311));
749         if (iplace == 311) iplace--;
750         iconvert[iplace] = 0;
751
752         /* Convert fractional part */
753         if (fracpart)
754         {
755                 do {
756                         temp = fracpart*0.1;
757                         my_modf(temp, &fracpart);
758                         idx = (int) ((temp -fracpart +0.05)* 10.0);
759                         /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
760                         /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
761                         fconvert[fplace++] =
762                         (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
763                 } while(fracpart && (fplace < 311));
764                 if (fplace == 311) fplace--;
765         }
766         fconvert[fplace] = 0;
767   
768         /* -1 for decimal point, another -1 if we are printing a sign */
769         padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
770         zpadlen = max - fplace;
771         if (zpadlen < 0) zpadlen = 0;
772         if (padlen < 0) 
773                 padlen = 0;
774         if (flags & DP_F_MINUS) 
775                 padlen = -padlen; /* Left Justifty */
776         
777         if ((flags & DP_F_ZERO) && (padlen > 0)) {
778                 if (signvalue) {
779                         DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
780                         --padlen;
781                         signvalue = 0;
782                 }
783                 while (padlen > 0) {
784                         DOPR_OUTCH(buffer, *currlen, maxlen, '0');
785                         --padlen;
786                 }
787         }
788         while (padlen > 0) {
789                 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
790                 --padlen;
791         }
792         if (signvalue) 
793                 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
794         
795         while (iplace > 0) {
796                 --iplace;
797                 DOPR_OUTCH(buffer, *currlen, maxlen, iconvert[iplace]);
798         }
799
800 #ifdef DEBUG_SNPRINTF
801         printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
802 #endif
803
804         /*
805          * Decimal point.  This should probably use locale to find the correct
806          * char to print out.
807          */
808         if (max > 0) {
809                 DOPR_OUTCH(buffer, *currlen, maxlen, '.');
810                 
811                 while (zpadlen > 0) {
812                         DOPR_OUTCH(buffer, *currlen, maxlen, '0');
813                         --zpadlen;
814                 }
815
816                 while (fplace > 0) {
817                         --fplace;
818                         DOPR_OUTCH(buffer, *currlen, maxlen, fconvert[fplace]);
819                 }
820         }
821
822         while (padlen < 0) {
823                 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
824                 ++padlen;
825         }
826         return 0;
827 }
828 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
829
830 #if !defined(HAVE_VSNPRINTF)
831 int
832 vsnprintf (char *str, size_t count, const char *fmt, va_list args)
833 {
834         return dopr(str, count, fmt, args);
835 }
836 #endif
837
838 #if !defined(HAVE_SNPRINTF)
839 int
840 snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...)
841 {
842         size_t ret;
843         va_list ap;
844
845         va_start(ap, fmt);
846         ret = vsnprintf(str, count, fmt, ap);
847         va_end(ap);
848         return ret;
849 }
850 #endif