2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Function to format a string like printf().
8 #define __vcformat __vcformat
10 /* Original source from libnix */
15 #ifndef AROS_NO_LIMITS_H
18 # define ULONG_MAX 4294967295UL
25 #include <aros/config.h>
27 /* Prevent 'missing math function' problem on AROSfA */
28 #if !(AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
29 #define FULL_SPECIFIERS
33 # ifdef FULL_SPECIFIERS
34 # undef FULL_SPECIFIERS
39 # define BITSPERBYTE 8
42 #if (__WORDSIZE != 64) && defined(AROSC_STATIC)
43 #undef AROS_HAVE_LONG_LONG
46 /* a little macro to make life easier */
48 { if((*outc)((c),data)==EOF) \
53 #define MINFLOATSIZE (DBL_DIG+1) /* Why not 1 more - it's 97% reliable */
54 #define MININTSIZE (sizeof(unsigned long)*BITSPERBYTE/3+1)
55 #define MINPOINTSIZE (sizeof(void *)*BITSPERBYTE/4+1)
56 #define REQUIREDBUFFER (MININTSIZE>MINPOINTSIZE? \
57 (MININTSIZE>MINFLOATSIZE?MININTSIZE:MINFLOATSIZE): \
58 (MINPOINTSIZE>MINFLOATSIZE?MINPOINTSIZE:MINFLOATSIZE))
60 #define ALTERNATEFLAG 1 /* '#' is set */
61 #define ZEROPADFLAG 2 /* '0' is set */
62 #define LALIGNFLAG 4 /* '-' is set */
63 #define BLANKFLAG 8 /* ' ' is set */
64 #define SIGNFLAG 16 /* '+' is set */
66 const unsigned char *const __decimalpoint
= ".";
68 /*****************************************************************************
76 int (* outc
)(int, void *),
81 Format a list of arguments and call a function for each char
85 data - This is passed to the usercallback outc
86 outc - Call this function for every character that should be
87 emitted. The function should return EOF on error and
89 format - A printf() format string.
90 args - A list of arguments for the format string.
93 The number of characters written.
105 ******************************************************************************/
113 static const char flagc
[]=
114 { '#','0','-',' ','+' };
115 static const char lowertabel
[]=
116 { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
117 static const char uppertabel
[]=
118 { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
119 size_t width
=0,preci
=ULONG_MAX
,flags
=0; /* Specifications */
120 char type
,subtype
='i';
121 #ifdef AROS_HAVE_LONG_LONG
124 char buffer1
[2]; /* Signs and that like */
125 char buffer
[REQUIREDBUFFER
]; /* The body */
126 char *buffer2
=buffer
; /* So we can set this to any other strings */
127 size_t size1
=0,size2
=0; /* How many chars in buffer? */
128 const char *ptr
=format
+1; /* pointer to format string */
129 size_t i
,pad
; /* Some temporary variables */
132 for(i
=0;i
<sizeof(flagc
);i
++)
137 while(i
<sizeof(flagc
));
139 if(*ptr
=='*') /* read width from arguments */
142 a
=va_arg(args
,signed int);
150 width
=width
*10+(*ptr
++-'0');
154 if(*ptr
=='*') /* read precision from arguments */
157 a
=va_arg(args
,signed int);
163 preci
=preci
*10+(*ptr
++-'0');
167 if(*ptr
=='h'||*ptr
=='l'||*ptr
=='L')
170 #ifdef AROS_HAVE_LONG_LONG
189 #ifdef AROS_HAVE_LONG_LONG
190 unsigned long long v
;
198 { subtype
='l'; /* This is written as %#lx */
200 flags
|=ALTERNATEFLAG
; }
202 if(type
=='d'||type
=='i') /* These are signed */
204 #ifdef AROS_HAVE_LONG_LONG
210 #ifdef AROS_HAVE_LONG_LONG
212 v2
=va_arg(args
,signed long long);
214 v2
=va_arg(args
,signed long); }
216 v2
=va_arg(args
,signed long);
219 v2
=va_arg(args
,signed int);
221 { buffer1
[size1
++]='-';
225 buffer1
[size1
++]='+';
226 else if(flags
&BLANKFLAG
)
227 buffer1
[size1
++]=' ';
229 }else /* These are unsigned */
231 #ifdef AROS_HAVE_LONG_LONG
233 v
=va_arg(args
,unsigned long long);
235 v
=va_arg(args
,unsigned long); }
237 v
=va_arg(args
,unsigned long);
240 v
=va_arg(args
,unsigned int);
241 if(flags
&ALTERNATEFLAG
)
242 { if(type
=='o'&&(preci
&&v
))
243 buffer1
[size1
++]='0';
244 if((type
=='x'||type
=='X')&&v
)
245 { buffer1
[size1
++]='0';
246 buffer1
[size1
++]=type
; }
250 buffer2
=&buffer
[sizeof(buffer
)]; /* Calculate body string */
251 base
=type
=='x'||type
=='X'?16:(type
=='o'?8:10);
252 tabel
=type
!='X'?lowertabel
:uppertabel
;
254 { *--buffer2
=tabel
[v
%base
];
258 if(preci
==ULONG_MAX
) /* default */
266 #ifdef AROS_HAVE_LONG_LONG
268 *buffer2
=va_arg(args
,long long);
270 *buffer2
=va_arg(args
,long); }
272 *buffer2
=va_arg(args
,long);
275 *buffer2
=va_arg(args
,int);
280 buffer2
=va_arg(args
,char *);
283 size2
=strlen(buffer2
);
284 size2
=size2
<=preci
?size2
:preci
;
287 #ifdef FULL_SPECIFIERS
294 char killzeros
=0,sign
=0; /* some flags */
295 int ex1
,ex2
; /* Some temporary variables */
296 size_t size
,dnum
,dreq
;
299 v
=va_arg(args
,double);
310 { size2
=strlen(udstr
);
315 if(preci
==ULONG_MAX
) /* old default */
316 preci
=6; /* new default */
324 else if(flags
&BLANKFLAG
)
332 v
=v
*pow(10,- --ex1
); /* Caution: (int)log10(.5)!=-1 */
335 if(v
<1.0) /* adjust if we are too low (log10(.1)=-.999999999) */
336 { v
*=10.0; /* luckily this cannot happen with FLT_MAX and FLT_MIN */
337 ex1
--; } /* The case too high (log(10.)=.999999999) is done later */
343 if(tolower(type
)=='g')
345 v
+=.5/pow(10,ex2
<MINFLOATSIZE
?ex2
:MINFLOATSIZE
); /* Round up */
347 if(v
>=10.0) /* Adjusts log10(10.)=.999999999 too */
351 if(tolower(type
)=='g') /* This changes to one of the other types */
352 { if(ex1
<(signed long)preci
&&ex1
>=-4)
356 type
=type
=='g'?'e':'E';
358 if(!(flags
&ALTERNATEFLAG
))
359 killzeros
=1; /* set flag to kill trailing zeros */
362 dreq
=preci
+1; /* Calculate number of decimal places required */
364 dreq
+=ex1
; /* even more before the decimal point */
367 while(dnum
<dreq
&&dnum
<MINFLOATSIZE
) /* Calculate all decimal places needed */
368 { buffer
[dnum
++]=(char)v
+'0';
369 v
=(v
-(double)(char)v
)*10.0; }
371 if(killzeros
) /* Kill trailing zeros if possible */
372 while(preci
&&(dreq
-->dnum
||buffer
[dreq
]=='0'))
375 if(type
=='f')/* Calculate actual size of string (without sign) */
376 { size
=preci
+1; /* numbers after decimal point + 1 before */
378 size
+=ex1
; /* numbers >= 10 */
379 if(preci
||flags
&ALTERNATEFLAG
)
380 size
++; /* 1 for decimal point */
382 { size
=preci
+5; /* 1 for the number before the decimal point, and 4 for the exponent */
383 if(preci
||flags
&ALTERNATEFLAG
)
386 size
++; /* exponent needs an extra decimal place */
390 pad
=pad
>=width
?0:width
-pad
;
392 if(sign
&&flags
&ZEROPADFLAG
)
395 if(!(flags
&LALIGNFLAG
))
397 OUT(flags
&ZEROPADFLAG
?'0':' ');
399 if(sign
&&!(flags
&ZEROPADFLAG
))
408 { OUT(dreq
<dnum
?buffer
[dreq
++]:'0');
410 if(preci
||flags
&ALTERNATEFLAG
)
411 { OUT(__decimalpoint
[0]);
416 OUT(dreq
<dnum
?buffer
[dreq
++]:'0');
419 { OUT(buffer
[dreq
++]);
420 if(preci
||flags
&ALTERNATEFLAG
)
421 { OUT(__decimalpoint
[0]);
423 OUT(dreq
<dnum
?buffer
[dreq
++]:'0');
441 width
=preci
=0; /* Everything already done */
451 *va_arg(args
,int *)=outcount
;
456 ptr
--; /* We've gone too far - step one back */
457 buffer2
=(char *)format
;
462 pad
=size1
+(size2
>=preci
?size2
:preci
); /* Calculate the number of characters */
463 pad
=pad
>=width
?0:width
-pad
; /* and the number of resulting pad bytes */
465 if(flags
&ZEROPADFLAG
) /* print sign and that like */
469 if(!(flags
&LALIGNFLAG
)) /* Pad left */
471 OUT(flags
&ZEROPADFLAG
?'0':' ');
473 if(!(flags
&ZEROPADFLAG
)) /* print sign if not zero padded */
477 for(i
=size2
;i
<preci
;i
++) /* extend to precision */
480 for(i
=0;i
<size2
;i
++) /* print body */
483 if(flags
&LALIGNFLAG
) /* Pad right */