purge remaining gpl code from clib, and make clib build again
[tangerine.git] / compiler / clib / __vcformat.c
blobe0237e1a52a895fe437c9c58b5209c501564c0e9
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Function to format a string like printf().
6 */
8 #define __vcformat __vcformat
10 /* Original source from libnix */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdarg.h>
14 #include <string.h>
15 #ifndef AROS_NO_LIMITS_H
16 # include <limits.h>
17 #else
18 # define ULONG_MAX 4294967295UL
19 #endif
20 #include <ctype.h>
21 #include "__math.h"
22 #include <math.h>
23 #include <float.h>
25 #include <aros/config.h>
27 /* Prevent 'missing math function' problem on AROSfA */
28 #if !(AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
29 #define FULL_SPECIFIERS
30 #endif
32 #ifdef AROS_NOFPU
33 # ifdef FULL_SPECIFIERS
34 # undef FULL_SPECIFIERS
35 # endif
36 #endif
38 #ifndef BITSPERBYTE
39 # define BITSPERBYTE 8
40 #endif
42 /* a little macro to make life easier */
43 #define OUT(c) do \
44 { if((*outc)((c),data)==EOF) \
45 return outcount; \
46 outcount++; \
47 }while(0)
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 /*****************************************************************************
66 NAME */
68 int __vcformat (
70 /* SYNOPSIS */
71 void * data,
72 int (* outc)(int, void *),
73 const char * format,
74 va_list args)
76 /* FUNCTION
77 Format a list of arguments and call a function for each char
78 to print.
80 INPUTS
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
84 > 0 otherwise.
85 format - A printf() format string.
86 args - A list of arguments for the format string.
88 RESULT
89 The number of characters written.
91 NOTES
93 EXAMPLE
95 BUGS
97 SEE ALSO
99 INTERNALS
101 ******************************************************************************/
103 size_t outcount=0;
105 while(*format)
107 if(*format=='%')
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 */
124 do /* read flags */
125 for(i=0;i<sizeof(flagc);i++)
126 if(flagc[i]==*ptr)
127 { flags|=1<<i;
128 ptr++;
129 break; }
130 while(i<sizeof(flagc));
132 if(*ptr=='*') /* read width from arguments */
133 { signed int a;
134 ptr++;
135 a=va_arg(args,signed int);
136 if(a<0)
137 { flags|=LALIGNFLAG;
138 width=-a; }
139 else
140 width=a;
141 }else
142 while(isdigit(*ptr))
143 width=width*10+(*ptr++-'0');
145 if(*ptr=='.')
146 { ptr++;
147 if(*ptr=='*') /* read precision from arguments */
148 { signed int a;
149 ptr++;
150 a=va_arg(args,signed int);
151 if(a>=0)
152 preci=a;
153 }else
154 { preci=0;
155 while(isdigit(*ptr))
156 preci=preci*10+(*ptr++-'0');
160 if(*ptr=='h'||*ptr=='l'||*ptr=='L')
161 subtype=*ptr++;
163 type=*ptr++;
165 switch(type)
166 { case 'd':
167 case 'i':
168 case 'o':
169 case 'p':
170 case 'u':
171 case 'x':
172 case 'X':
173 { unsigned long v;
174 const char *tabel;
175 int base;
177 if(type=='p')
178 { subtype='l'; /* This is written as %#lx */
179 type='x';
180 flags|=ALTERNATEFLAG; }
182 if(type=='d'||type=='i') /* These are signed */
183 { signed long v2;
184 if(subtype=='l')
185 v2=va_arg(args,signed long);
186 else
187 v2=va_arg(args,signed int);
188 if(v2<0)
189 { buffer1[size1++]='-';
190 v=-v2;
191 }else
192 { if(flags&SIGNFLAG)
193 buffer1[size1++]='+';
194 else if(flags&BLANKFLAG)
195 buffer1[size1++]=' ';
196 v=v2; }
197 }else /* These are unsigned */
198 { if(subtype=='l')
199 v=va_arg(args,unsigned long);
200 else
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];
216 v=v/base;
217 size2++;
218 }while(v);
219 if(preci==ULONG_MAX) /* default */
220 preci=0;
221 else
222 flags&=~ZEROPADFLAG;
223 break;
225 case 'c':
226 if(subtype=='l')
227 *buffer2=va_arg(args,long);
228 else
229 *buffer2=va_arg(args,int);
230 size2=1;
231 preci=0;
232 break;
233 case 's':
234 buffer2=va_arg(args,char *);
235 if (!buffer2)
236 buffer2="(null)";
237 size2=strlen(buffer2);
238 size2=size2<=preci?size2:preci;
239 preci=0;
240 break;
241 #ifdef FULL_SPECIFIERS
242 case 'f':
243 case 'e':
244 case 'E':
245 case 'g':
246 case 'G':
247 { double v;
248 char killzeros=0,sign=0; /* some flags */
249 int ex1,ex2; /* Some temporary variables */
250 size_t size,dnum,dreq;
251 char *udstr=NULL;
253 v=va_arg(args,double);
255 if(isinf(v))
256 { if(v>0)
257 udstr="+inf";
258 else
259 udstr="-inf";
260 }else if(isnan(v))
261 udstr="NaN";
263 if(udstr!=NULL)
264 { size2=strlen(udstr);
265 preci=0;
266 buffer2=udstr;
267 break; }
269 if(preci==ULONG_MAX) /* old default */
270 preci=6; /* new default */
272 if(v<0.0)
273 { sign='-';
274 v=-v;
275 }else
276 { if(flags&SIGNFLAG)
277 sign='+';
278 else if(flags&BLANKFLAG)
279 sign=' ';
282 ex1=0;
283 if(v!=0.0)
284 { ex1=log10(v);
285 if(v<1.0)
286 v=v*pow(10,- --ex1); /* Caution: (int)log10(.5)!=-1 */
287 else
288 v=v/pow(10,ex1);
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 */
294 ex2=preci;
295 if(type=='f')
296 ex2+=ex1;
297 if(tolower(type)=='g')
298 ex2--;
299 v+=.5/pow(10,ex2<MINFLOATSIZE?ex2:MINFLOATSIZE); /* Round up */
301 if(v>=10.0) /* Adjusts log10(10.)=.999999999 too */
302 { v/=10.0;
303 ex1++; }
305 if(tolower(type)=='g') /* This changes to one of the other types */
306 { if(ex1<(signed long)preci&&ex1>=-4)
307 { type='f';
308 preci-=ex1;
309 }else
310 type=type=='g'?'e':'E';
311 preci--;
312 if(!(flags&ALTERNATEFLAG))
313 killzeros=1; /* set flag to kill trailing zeros */
316 dreq=preci+1; /* Calculate number of decimal places required */
317 if(type=='f')
318 dreq+=ex1; /* even more before the decimal point */
320 dnum=0;
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'))
327 preci--;
329 if(type=='f')/* Calculate actual size of string (without sign) */
330 { size=preci+1; /* numbers after decimal point + 1 before */
331 if(ex1>0)
332 size+=ex1; /* numbers >= 10 */
333 if(preci||flags&ALTERNATEFLAG)
334 size++; /* 1 for decimal point */
335 }else
336 { size=preci+5; /* 1 for the number before the decimal point, and 4 for the exponent */
337 if(preci||flags&ALTERNATEFLAG)
338 size++;
339 if(ex1>99||ex1<-99)
340 size++; /* exponent needs an extra decimal place */
343 pad=size+(sign!=0);
344 pad=pad>=width?0:width-pad;
346 if(sign&&flags&ZEROPADFLAG)
347 OUT(sign);
349 if(!(flags&LALIGNFLAG))
350 for(i=0;i<pad;i++)
351 OUT(flags&ZEROPADFLAG?'0':' ');
353 if(sign&&!(flags&ZEROPADFLAG))
354 OUT(sign);
356 dreq=0;
357 if(type=='f')
358 { if(ex1<0)
359 OUT('0');
360 else
361 while(ex1>=0)
362 { OUT(dreq<dnum?buffer[dreq++]:'0');
363 ex1--; }
364 if(preci||flags&ALTERNATEFLAG)
365 { OUT(__decimalpoint[0]);
366 while(preci--)
367 if(++ex1<0)
368 OUT('0');
369 else
370 OUT(dreq<dnum?buffer[dreq++]:'0');
372 }else
373 { OUT(buffer[dreq++]);
374 if(preci||flags&ALTERNATEFLAG)
375 { OUT(__decimalpoint[0]);
376 while(preci--)
377 OUT(dreq<dnum?buffer[dreq++]:'0');
379 OUT(type);
380 if(ex1<0)
381 { OUT('-');
382 ex1=-ex1; }
383 else
384 OUT('+');
385 if(ex1>99)
386 OUT(ex1/100+'0');
387 OUT(ex1/10%10+'0');
388 OUT(ex1%10+'0');
391 if(flags&LALIGNFLAG)
392 for(i=0;i<pad;i++)
393 OUT(' ');
395 width=preci=0; /* Everything already done */
396 break;
398 #endif
399 case '%':
400 buffer2="%";
401 size2=1;
402 preci=0;
403 break;
404 case 'n':
405 *va_arg(args,int *)=outcount;
406 width=preci=0;
407 break;
408 default:
409 if(!type)
410 ptr--; /* We've gone too far - step one back */
411 buffer2=(char *)format;
412 size2=ptr-format;
413 width=preci=0;
414 break;
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 */
420 for(i=0;i<size1;i++)
421 OUT(buffer1[i]);
423 if(!(flags&LALIGNFLAG)) /* Pad left */
424 for(i=0;i<pad;i++)
425 OUT(flags&ZEROPADFLAG?'0':' ');
427 if(!(flags&ZEROPADFLAG)) /* print sign if not zero padded */
428 for(i=0;i<size1;i++)
429 OUT(buffer1[i]);
431 for(i=size2;i<preci;i++) /* extend to precision */
432 OUT('0');
434 for(i=0;i<size2;i++) /* print body */
435 OUT(buffer2[i]);
437 if(flags&LALIGNFLAG) /* Pad right */
438 for(i=0;i<pad;i++)
439 OUT(' ');
441 format=ptr;
443 else
444 OUT(*format++);
446 return outcount;