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 /* a little macro to make life easier */
44 { if((*outc)((c),data)==EOF) \
49 #define MINFLOATSIZE (DBL_DIG+1) /* Why not 1 more - it's 97% reliable */
50 #define MININTSIZE (sizeof(unsigned long)*BITSPERBYTE/3+1)
51 #define MINPOINTSIZE (sizeof(void *)*BITSPERBYTE/4+1)
52 #define REQUIREDBUFFER (MININTSIZE>MINPOINTSIZE? \
53 (MININTSIZE>MINFLOATSIZE?MININTSIZE:MINFLOATSIZE): \
54 (MINPOINTSIZE>MINFLOATSIZE?MINPOINTSIZE:MINFLOATSIZE))
56 #define ALTERNATEFLAG 1 /* '#' is set */
57 #define ZEROPADFLAG 2 /* '0' is set */
58 #define LALIGNFLAG 4 /* '-' is set */
59 #define BLANKFLAG 8 /* ' ' is set */
60 #define SIGNFLAG 16 /* '+' is set */
62 const unsigned char *const __decimalpoint
= ".";
64 /*****************************************************************************
72 int (* outc
)(int, void *),
77 Format a list of arguments and call a function for each char
81 data - This is passed to the usercallback outc
82 outc - Call this function for every character that should be
83 emitted. The function should return EOF on error and
85 format - A printf() format string.
86 args - A list of arguments for the format string.
89 The number of characters written.
101 ******************************************************************************/
109 static const char flagc
[]=
110 { '#','0','-',' ','+' };
111 static const char lowertabel
[]=
112 { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
113 static const char uppertabel
[]=
114 { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
115 size_t width
=0,preci
=ULONG_MAX
,flags
=0; /* Specifications */
116 char type
,subtype
='i';
117 char buffer1
[2]; /* Signs and that like */
118 char buffer
[REQUIREDBUFFER
]; /* The body */
119 char *buffer2
=buffer
; /* So we can set this to any other strings */
120 size_t size1
=0,size2
=0; /* How many chars in buffer? */
121 const char *ptr
=format
+1; /* pointer to format string */
122 size_t i
,pad
; /* Some temporary variables */
125 for(i
=0;i
<sizeof(flagc
);i
++)
130 while(i
<sizeof(flagc
));
132 if(*ptr
=='*') /* read width from arguments */
135 a
=va_arg(args
,signed int);
143 width
=width
*10+(*ptr
++-'0');
147 if(*ptr
=='*') /* read precision from arguments */
150 a
=va_arg(args
,signed int);
156 preci
=preci
*10+(*ptr
++-'0');
160 if(*ptr
=='h'||*ptr
=='l'||*ptr
=='L')
178 { subtype
='l'; /* This is written as %#lx */
180 flags
|=ALTERNATEFLAG
; }
182 if(type
=='d'||type
=='i') /* These are signed */
185 v2
=va_arg(args
,signed long);
187 v2
=va_arg(args
,signed int);
189 { buffer1
[size1
++]='-';
193 buffer1
[size1
++]='+';
194 else if(flags
&BLANKFLAG
)
195 buffer1
[size1
++]=' ';
197 }else /* These are unsigned */
199 v
=va_arg(args
,unsigned long);
201 v
=va_arg(args
,unsigned int);
202 if(flags
&ALTERNATEFLAG
)
203 { if(type
=='o'&&(preci
&&v
))
204 buffer1
[size1
++]='0';
205 if((type
=='x'||type
=='X')&&v
)
206 { buffer1
[size1
++]='0';
207 buffer1
[size1
++]=type
; }
211 buffer2
=&buffer
[sizeof(buffer
)]; /* Calculate body string */
212 base
=type
=='x'||type
=='X'?16:(type
=='o'?8:10);
213 tabel
=type
!='X'?lowertabel
:uppertabel
;
215 { *--buffer2
=tabel
[v
%base
];
219 if(preci
==ULONG_MAX
) /* default */
227 *buffer2
=va_arg(args
,long);
229 *buffer2
=va_arg(args
,int);
234 buffer2
=va_arg(args
,char *);
237 size2
=strlen(buffer2
);
238 size2
=size2
<=preci
?size2
:preci
;
241 #ifdef FULL_SPECIFIERS
248 char killzeros
=0,sign
=0; /* some flags */
249 int ex1
,ex2
; /* Some temporary variables */
250 size_t size
,dnum
,dreq
;
253 v
=va_arg(args
,double);
264 { size2
=strlen(udstr
);
269 if(preci
==ULONG_MAX
) /* old default */
270 preci
=6; /* new default */
278 else if(flags
&BLANKFLAG
)
286 v
=v
*pow(10,- --ex1
); /* Caution: (int)log10(.5)!=-1 */
289 if(v
<1.0) /* adjust if we are too low (log10(.1)=-.999999999) */
290 { v
*=10.0; /* luckily this cannot happen with FLT_MAX and FLT_MIN */
291 ex1
--; } /* The case too high (log(10.)=.999999999) is done later */
297 if(tolower(type
)=='g')
299 v
+=.5/pow(10,ex2
<MINFLOATSIZE
?ex2
:MINFLOATSIZE
); /* Round up */
301 if(v
>=10.0) /* Adjusts log10(10.)=.999999999 too */
305 if(tolower(type
)=='g') /* This changes to one of the other types */
306 { if(ex1
<(signed long)preci
&&ex1
>=-4)
310 type
=type
=='g'?'e':'E';
312 if(!(flags
&ALTERNATEFLAG
))
313 killzeros
=1; /* set flag to kill trailing zeros */
316 dreq
=preci
+1; /* Calculate number of decimal places required */
318 dreq
+=ex1
; /* even more before the decimal point */
321 while(dnum
<dreq
&&dnum
<MINFLOATSIZE
) /* Calculate all decimal places needed */
322 { buffer
[dnum
++]=(char)v
+'0';
323 v
=(v
-(double)(char)v
)*10.0; }
325 if(killzeros
) /* Kill trailing zeros if possible */
326 while(preci
&&(dreq
-->dnum
||buffer
[dreq
]=='0'))
329 if(type
=='f')/* Calculate actual size of string (without sign) */
330 { size
=preci
+1; /* numbers after decimal point + 1 before */
332 size
+=ex1
; /* numbers >= 10 */
333 if(preci
||flags
&ALTERNATEFLAG
)
334 size
++; /* 1 for decimal point */
336 { size
=preci
+5; /* 1 for the number before the decimal point, and 4 for the exponent */
337 if(preci
||flags
&ALTERNATEFLAG
)
340 size
++; /* exponent needs an extra decimal place */
344 pad
=pad
>=width
?0:width
-pad
;
346 if(sign
&&flags
&ZEROPADFLAG
)
349 if(!(flags
&LALIGNFLAG
))
351 OUT(flags
&ZEROPADFLAG
?'0':' ');
353 if(sign
&&!(flags
&ZEROPADFLAG
))
362 { OUT(dreq
<dnum
?buffer
[dreq
++]:'0');
364 if(preci
||flags
&ALTERNATEFLAG
)
365 { OUT(__decimalpoint
[0]);
370 OUT(dreq
<dnum
?buffer
[dreq
++]:'0');
373 { OUT(buffer
[dreq
++]);
374 if(preci
||flags
&ALTERNATEFLAG
)
375 { OUT(__decimalpoint
[0]);
377 OUT(dreq
<dnum
?buffer
[dreq
++]:'0');
395 width
=preci
=0; /* Everything already done */
405 *va_arg(args
,int *)=outcount
;
410 ptr
--; /* We've gone too far - step one back */
411 buffer2
=(char *)format
;
416 pad
=size1
+(size2
>=preci
?size2
:preci
); /* Calculate the number of characters */
417 pad
=pad
>=width
?0:width
-pad
; /* and the number of resulting pad bytes */
419 if(flags
&ZEROPADFLAG
) /* print sign and that like */
423 if(!(flags
&LALIGNFLAG
)) /* Pad left */
425 OUT(flags
&ZEROPADFLAG
?'0':' ');
427 if(!(flags
&ZEROPADFLAG
)) /* print sign if not zero padded */
431 for(i
=size2
;i
<preci
;i
++) /* extend to precision */
434 for(i
=0;i
<size2
;i
++) /* print body */
437 if(flags
&LALIGNFLAG
) /* Pad right */