70
70
* don't declare argument types to (v)snprintf if stdarg is not used.
71
71
* use int instead of short int as 2nd arg to va_arg.
73
* alexk (INN) 2002-08-21
74
* use LLONG in fmtfp to handle more characters during floating
77
* herb (Samba) 2002-12-19
78
* actually print args for %g and %e
80
* Hrvoje Niksic <hniksic@xemacs.org> 2005-04-15
81
* use the PARAMS macro to handle prototypes.
82
* write function definitions in the ansi2knr-friendly way.
83
* if string precision is specified, don't read VALUE past it.
84
* fix bug in fmtfp that caused 0.01 to be printed as 0.1.
85
* don't include <ctype.h> because none of it is used.
86
* interpret precision as number of significant digits with %g
87
* omit trailing decimal zeros with %g
73
89
**************************************************************/
75
91
#ifdef HAVE_CONFIG_H
76
92
# include <config.h>
95
/* For testing purposes, always compile in the code. */
98
# undef HAVE_VSNPRINTF
99
# ifndef SIZEOF_LONG_LONG
101
# define SIZEOF_LONG_LONG 8
79
106
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
111
# include <strings.h>
82
113
#include <sys/types.h>
83
114
#include <stdio.h> /* for NULL */
84
#include <safe-ctype.h>
86
116
/* varargs declarations: */
113
143
# define LLONG long
146
/* If we're running the test suite, rename snprintf and vsnprintf to
147
avoid conflicts with the system version. */
149
# define snprintf test_snprintf
150
# define vsnprintf test_vsnprintf
116
153
#ifdef HAVE_STDARGS
117
154
int snprintf (char *str, size_t count, const char *fmt, ...);
118
155
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
121
158
int vsnprintf ();
124
static int dopr (char *buffer, size_t maxlen, const char *format,
126
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
127
char *value, int flags, int min, int max);
128
static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
129
LLONG value, int base, int min, int max, int flags);
130
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
131
LDOUBLE fvalue, int min, int max, int flags);
132
static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
165
static int dopr PARAMS ((char *buffer, size_t maxlen, const char *format,
167
static int fmtstr PARAMS ((char *buffer, size_t *currlen, size_t maxlen,
168
const char *value, int flags, int min, int max));
169
static int fmtint PARAMS ((char *buffer, size_t *currlen, size_t maxlen,
170
LLONG value, int base, int min, int max, int flags));
171
static int fmtfp PARAMS ((char *buffer, size_t *currlen, size_t maxlen,
172
LDOUBLE fvalue, int min, int max, int flags));
173
static int dopr_outch PARAMS ((char *buffer, size_t *currlen, size_t maxlen,
135
177
* dopr(): poor man's version of doprintf
165
208
#define MAX(p,q) ((p >= q) ? p : q)
166
209
#define MIN(p,q) ((p <= q) ? p : q)
168
static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
212
dopr (char *buffer, size_t maxlen, const char *format, va_list args)
311
355
if (cflags == DP_C_SHORT)
312
value = (short int)va_arg (args, int);
356
value = (short int) va_arg (args, int);
313
357
else if (cflags == DP_C_LONG)
314
358
value = va_arg (args, long int);
315
359
else if (cflags == DP_C_LLONG)
322
366
flags |= DP_F_UNSIGNED;
323
367
if (cflags == DP_C_SHORT)
324
value = (unsigned short int)va_arg (args, unsigned int);
368
value = (unsigned short int) va_arg (args, unsigned int);
325
369
else if (cflags == DP_C_LONG)
326
370
value = va_arg (args, unsigned long int);
327
371
else if (cflags == DP_C_LLONG)
334
378
flags |= DP_F_UNSIGNED;
335
379
if (cflags == DP_C_SHORT)
336
value = (unsigned short int)va_arg (args, unsigned int);
380
value = (unsigned short int) va_arg (args, unsigned int);
337
381
else if (cflags == DP_C_LONG)
338
382
value = va_arg (args, unsigned long int);
339
383
else if (cflags == DP_C_LLONG)
348
392
flags |= DP_F_UNSIGNED;
349
393
if (cflags == DP_C_SHORT)
350
value = (unsigned short int)va_arg (args, unsigned int);
394
value = (unsigned short int) va_arg (args, unsigned int);
351
395
else if (cflags == DP_C_LONG)
352
396
value = va_arg (args, unsigned long int);
353
397
else if (cflags == DP_C_LLONG)
361
405
fvalue = va_arg (args, LDOUBLE);
363
407
fvalue = va_arg (args, double);
364
/* um, floating point? */
365
408
total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
371
414
fvalue = va_arg (args, LDOUBLE);
373
416
fvalue = va_arg (args, double);
417
total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
376
420
flags |= DP_F_UP;
378
423
if (cflags == DP_C_LDOUBLE)
379
424
fvalue = va_arg (args, LDOUBLE);
381
426
fvalue = va_arg (args, double);
428
/* C99 says: if precision [for %g] is zero, it is taken as one */
430
total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
384
433
total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
454
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
455
char *value, int flags, int min, int max)
504
fmtstr (char *buffer, size_t *currlen, size_t maxlen,
505
const char *value, int flags, int min, int max)
457
507
int padlen, strln; /* amount to pad */
466
for (strln = 0; value[strln]; ++strln); /* strlen */
467
if (max >= 0 && max < strln)
517
strln = strlen (value);
519
/* When precision is specified, don't read VALUE past precision. */
520
/*strln = strnlen (value, max);*/
521
for (strln = 0; strln < max && value[strln]; ++strln);
469
522
padlen = min - strln;
493
546
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
495
static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
496
LLONG value, int base, int min, int max, int flags)
549
fmtint (char *buffer, size_t *currlen, size_t maxlen,
550
LLONG value, int base, int min, int max, int flags)
498
552
int signvalue = 0;
499
553
unsigned LLONG uvalue;
625
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
626
LDOUBLE fvalue, int min, int max, int flags)
683
fmtfp (char *buffer, size_t *currlen, size_t maxlen,
684
LDOUBLE fvalue, int min, int max, int flags)
628
686
int signvalue = 0;
634
692
int padlen = 0; /* amount to pad */
698
int leadingfrac0s = 0; /* zeros at the start of fractional part */
642
703
* AIX manpage says the default is 0, but Solaris says the default
663
724
intpart = ufvalue;
726
/* With %g precision is the number of significant digits, which
727
includes the digits in intpart. */
728
if (flags & DP_F_FP_G)
732
/* For each digit of INTPART, print one less fractional digit. */
733
LLONG temp = intpart;
734
for (temp = intpart; temp != 0; temp /= 10)
741
/* For each leading 0 in fractional part, print one more
745
for (temp = ufvalue; temp < 0.1; temp *= 10)
750
/* C99: trailing zeros are removed from the fractional portion of the
751
result unless the # flag is specified */
752
if ((flags & DP_F_FP_G) && !(flags & DP_F_NUM))
755
#if SIZEOF_LONG_LONG > 0
756
# define MAX_DIGITS 18 /* grok more digits with long long */
758
# define MAX_DIGITS 9 /* just long */
666
* Sorry, we only support 9 digits past the decimal because of our
762
* Sorry, we only support several digits past the decimal because of
763
* our conversion method
765
if (max > MAX_DIGITS)
768
/* Factor of 10 with the needed number of digits, e.g. 1000 for max==3 */
769
mask10 = pow10 (max);
672
771
/* We "cheat" by converting the fractional part to integer by
673
772
* multiplying by a factor of 10
675
fracpart = round ((pow10 (max)) * (ufvalue - intpart));
774
fracpart = round (mask10 * (ufvalue - intpart));
677
if (fracpart >= pow10 (max))
776
if (fracpart >= mask10)
680
fracpart -= pow10 (max);
781
else if (fracpart != 0)
782
/* If fracpart has less digits than the 10* mask, we need to
783
manually insert leading 0s. For example 2.01's fractional part
784
requires one leading zero to distinguish it from 2.1. */
785
while (fracpart < mask10 / 10)
683
791
#ifdef DEBUG_SNPRINTF
684
792
dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
687
795
/* Convert integer part */
690
(caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
797
iconvert[iplace++] = '0' + intpart % 10;
691
798
intpart = (intpart / 10);
692
} while(intpart && (iplace < 20));
693
if (iplace == 20) iplace--;
799
} while(intpart && (iplace < sizeof(iconvert)));
800
if (iplace == sizeof(iconvert)) iplace--;
694
801
iconvert[iplace] = 0;
696
803
/* Convert fractional part */
699
(caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
805
fconvert[fplace++] = '0' + fracpart % 10;
700
806
fracpart = (fracpart / 10);
701
} while(fracpart && (fplace < 20));
702
if (fplace == 20) fplace--;
807
} while(fracpart && (fplace < sizeof(fconvert)));
808
while (leadingfrac0s-- > 0 && fplace < sizeof(fconvert))
809
fconvert[fplace++] = '0';
810
if (fplace == sizeof(fconvert)) fplace--;
703
811
fconvert[fplace] = 0;
813
while (omitcount < fplace && fconvert[omitcount] == '0')
705
816
/* -1 for decimal point, another -1 if we are printing a sign */
706
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
707
zpadlen = max - fplace;
817
padlen = min - iplace - (max - omitcount) - 1 - ((signvalue) ? 1 : 0);
819
zpadlen = max - fplace;
741
853
* Decimal point. This should probably use locale to find the correct
742
854
* char to print out.
856
if (max > 0 && (fplace > omitcount || zpadlen > 0))
746
858
total += dopr_outch (buffer, currlen, maxlen, '.');
860
while (fplace > omitcount)
749
861
total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
767
static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
880
dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
769
882
if (*currlen + 1 < maxlen)
770
883
buffer[(*currlen)++] = c;
774
887
#ifndef HAVE_VSNPRINTF
775
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
889
vsnprintf (char *str, size_t count, const char *fmt, va_list args)
781
895
#endif /* !HAVE_VSNPRINTF */
783
897
#ifndef HAVE_SNPRINTF
786
int snprintf (char *str,size_t count,const char *fmt,...)
788
int snprintf (va_alist) va_dcl
899
snprintf (char *str, size_t count,const char *fmt,...)
791
901
#ifndef HAVE_STDARGS
948
#if SIZEOF_LONG_LONG != 0
960
#if SIZEOF_LONG_LONG != 0
837
966
double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
838
0.9996, 1.996, 4.136, 0};
967
0.9996, 1.996, 4.136, 0.00205, 0.0001, 321.000009,
839
969
char *int_fmt[] = {