2 Copyright © 2018, The AROS Development Team. All rights reserved.
5 Common code block to format a string like printf().
9 * This code is used by debug functions during early startup.
10 * Please keep it self-contained, at least when compiled with -DSTDC_STATIC.
19 static const char flagc
[] = { '#', '0', '-', ' ', '+' };
20 size_t width
=0, preci
=ULONG_MAX
, flags
=0; /* Specifications */
21 char type
, subtype
= 'i';
22 #ifdef AROS_HAVE_LONG_LONG
25 char buffer1
[2]; /* Signs and that like */
26 char buffer
[REQUIREDBUFFER
]; /* The body */
27 char *buffer2
= buffer
; /* So we can set this to any other strings */
28 size_t size1
= 0, size2
= 0; /* How many chars in buffer? */
29 const char *ptr
= format
+ 1; /* pointer to format string */
30 size_t i
, pad
; /* Some temporary variables */
31 #if defined(FULL_SPECIFIERS)
32 union { /* floating point arguments %[aAeEfFgG] */
38 for (i
= 0; i
< sizeof(flagc
); i
++)
45 while (i
< sizeof(flagc
));
47 if (*ptr
== '*') /* read width from arguments */
51 a
= va_arg(args
, signed int);
61 width
= width
* 10 + (*ptr
++ - '0');
66 if (*ptr
== '*') /* read precision from arguments */
70 a
= va_arg(args
, signed int);
77 preci
= preci
* 10 + (*ptr
++ - '0');
81 if (*ptr
== 'h' || *ptr
== 'l' || *ptr
== 'L' || *ptr
== 'z')
84 if (*ptr
== 'l' || *ptr
== 'q')
86 #ifdef AROS_HAVE_LONG_LONG
105 #ifdef AROS_HAVE_LONG_LONG
106 unsigned long long llv
= 0;
111 if (type
=='p') /* This is written as 0x08lx (or 0x016lx on 64 bits) */
116 width
= sizeof(void *) * 2;
117 flags
|= ZEROPADFLAG
;
120 if (type
=='d' || type
=='i') /* These are signed */
126 #ifdef AROS_HAVE_LONG_LONG
129 signed long long llv2
;
131 llv2
= va_arg(args
, signed long long);
135 v2
= -1; /* Assign a dummy value to v2 in order to process sign below */
145 v2
=va_arg(args
, signed long);
147 else if (subtype
== 'z')
148 v2
= va_arg(args
, size_t);
150 v2
= va_arg(args
, signed int);
154 buffer1
[size1
++] = '-';
159 if (flags
& SIGNFLAG
)
160 buffer1
[size1
++] = '+';
161 else if (flags
& BLANKFLAG
)
162 buffer1
[size1
++] = ' ';
166 else /* These are unsigned */
170 #ifdef AROS_HAVE_LONG_LONG
172 llv
= va_arg(args
, unsigned long long);
175 v
= va_arg(args
, unsigned long);
177 else if (subtype
== 'z')
178 v
= va_arg(args
, size_t);
180 v
= va_arg(args
, unsigned int);
182 if (flags
& ALTERNATEFLAG
)
184 if (type
== 'o' && preci
&& v
)
185 buffer1
[size1
++] = '0';
186 if ((type
== 'x' || type
== 'X') && v
)
188 buffer1
[size1
++] = '0';
189 buffer1
[size1
++] = type
;
194 buffer2
= &buffer
[sizeof(buffer
)]; /* Calculate body string */
196 #ifdef AROS_HAVE_LONG_LONG
198 * For long long type we have actual value in llv.
199 * For long we have actual value in v.
200 * This avoids slow 64-bit operations on 32-bit processors
204 size2
= format_longlong(buffer2
, type
, base
, llv
);
207 size2
= format_long(buffer2
, type
, base
, v
);
208 /* Position to the beginning of the string */
211 if (preci
== ULONG_MAX
) /* default */
214 flags
&= ~ZEROPADFLAG
;
221 #ifdef AROS_HAVE_LONG_LONG
223 *buffer2
= va_arg(args
, long long);
226 *buffer2
= va_arg(args
, long);
229 *buffer2
= va_arg(args
, int);
236 buffer2
= va_arg(args
, char *);
239 size2
= FMTPRINTF_STRLEN(buffer2
);
240 size2
= size2
<= preci
? size2
: preci
;
245 buffer2
= BADDR(va_arg(args
, BPTR
));
248 size2
= FMTPRINTF_STRLEN(buffer2
);
250 size2
= *(unsigned char *)buffer2
++;
258 size2
= size2
<= preci
? size2
: preci
;
262 #ifdef FULL_SPECIFIERS
272 char killzeros
=0, sign
=0; /* some flags */
273 int ex1
, ex2
; /* Some temporary variables */
274 size_t size
, dnum
, dreq
;
280 fparg
.ldbl
= va_arg(args
, long double);
283 fparg
.dbl
= va_arg(args
, double);
286 if (isinf(fparg
.dbl
))
292 } else if (isnan(fparg
.dbl
))
297 size2
= FMTPRINTF_STRLEN(udstr
);
302 if (preci
== ULONG_MAX
) /* old default */
303 preci
= 6; /* new default */
305 if (((subtype
!= 'L') && (fparg
.dbl
< 0.0)) || ((subtype
== 'L') && (fparg
.ldbl
< 0.0)))
309 fparg
.ldbl
= -fparg
.ldbl
;
311 fparg
.dbl
= -fparg
.dbl
;
313 if (flags
& SIGNFLAG
)
315 else if (flags
& BLANKFLAG
)
320 if (tolower(type
) != 'a')
324 if (fparg
.dbl
!= 0.0)
326 ex1
= log10(fparg
.dbl
);
328 fparg
.dbl
= fparg
.dbl
* pow(10,- --ex1
); /* Caution: (int)log10(.5)!=-1 */
330 fparg
.dbl
=fparg
.dbl
/ pow(10, ex1
);
331 if (fparg
.dbl
< 1.0) /* adjust if we are too low (log10(.1)=-.999999999) */
333 fparg
.dbl
*= 10.0; /* luckily this cannot happen with FLT_MAX and FLT_MIN */
334 ex1
--; /* The case too high (log(10.)=.999999999) is done later */
338 if (fparg
.ldbl
!= 0.0)
340 ex1
= log10l(fparg
.ldbl
);
341 if (fparg
.ldbl
< 1.0)
342 fparg
.ldbl
= fparg
.ldbl
* powl(10,- --ex1
);
344 fparg
.ldbl
=fparg
.ldbl
/ powl(10, ex1
);
345 if (fparg
.ldbl
< 1.0)
355 if (tolower(type
) == 'f')
357 if (tolower(type
) == 'g')
361 fparg
.dbl
+= .5 / pow(10, ex2
< MINFLOATSIZE
? ex2
: MINFLOATSIZE
); /* Round up */
362 if (fparg
.dbl
>= 10.0) /* Adjusts log10(10.)=.999999999 too */
368 fparg
.ldbl
+= .5 / powl(10, ex2
< MINFLOATSIZE
? ex2
: MINFLOATSIZE
); /* Round up */
369 if (fparg
.ldbl
>= 10.0) /* Adjusts log10(10.)=.999999999 too */
376 if (tolower(type
) == 'g') /* This changes to one of the other types */
378 if (ex1
< (signed long)preci
&& ex1
>= -4)
383 type
= type
== 'g' ? 'e' : 'E';
385 if (!(flags
& ALTERNATEFLAG
))
386 killzeros
= 1; /* set flag to kill trailing zeros */
389 dreq
= preci
+ 1; /* Calculate number of decimal places required */
391 dreq
+= ex1
; /* even more before the decimal point */
394 while (dnum
< dreq
&& dnum
< MINFLOATSIZE
) /* Calculate all decimal places needed */
398 buffer
[dnum
++] = (char)fparg
.dbl
+ '0';
399 fparg
.dbl
= (fparg
.dbl
- (double)(char)fparg
.dbl
) * 10.0;
401 buffer
[dnum
++] = (char)fparg
.ldbl
+ '0';
402 fparg
.ldbl
= (fparg
.ldbl
- (long double)(char)fparg
.ldbl
) * 10.0;
405 if (killzeros
) /* Kill trailing zeros if possible */
406 while(preci
&& (dreq
-- > dnum
|| buffer
[dreq
] == '0'))
409 if (tolower(type
) == 'f') /* Calculate actual size of string (without sign) */
411 size
= preci
+ 1; /* numbers after decimal point + 1 before */
413 size
+= ex1
; /* numbers >= 10 */
414 if (preci
|| flags
& ALTERNATEFLAG
)
415 size
++; /* 1 for decimal point */
418 size
= preci
+ 5; /* 1 for the number before the decimal point, and 4 for the exponent */
419 if (preci
|| flags
& ALTERNATEFLAG
)
421 if (ex1
> 99 || ex1
< -99)
422 size
++; /* exponent needs an extra decimal place */
425 pad
= size
+ (sign
!= 0);
426 pad
= pad
>= width
? 0 : width
- pad
;
428 if (sign
&& flags
& ZEROPADFLAG
)
429 FMTPRINTF_COUT(sign
);
431 if (!(flags
& LALIGNFLAG
))
432 for (i
= 0; i
< pad
; i
++)
433 FMTPRINTF_COUT(flags
& ZEROPADFLAG
? '0' : ' ');
435 if (sign
&& !(flags
& ZEROPADFLAG
))
436 FMTPRINTF_COUT(sign
);
439 if (tolower(type
) == 'a')
441 // TODO: Implement hexfloat literals
452 } else if (tolower(type
) == 'f') {
458 FMTPRINTF_COUT(dreq
< dnum
? buffer
[dreq
++] : '0');
461 if (preci
|| flags
& ALTERNATEFLAG
)
463 FMTPRINTF_COUT(FMTPRINTF_DECIMALPOINT
[0]);
468 FMTPRINTF_COUT(dreq
< dnum
? buffer
[dreq
++] : '0');
471 FMTPRINTF_COUT(buffer
[dreq
++]);
472 if (preci
|| flags
& ALTERNATEFLAG
)
474 FMTPRINTF_COUT(FMTPRINTF_DECIMALPOINT
[0]);
476 FMTPRINTF_COUT(dreq
< dnum
? buffer
[dreq
++] : '0');
478 FMTPRINTF_COUT(type
);
487 FMTPRINTF_COUT(ex1
/ 100 + '0');
488 FMTPRINTF_COUT(ex1
/ 10 % 10 + '0');
489 FMTPRINTF_COUT(ex1
% 10 + '0');
492 if (flags
& LALIGNFLAG
)
493 for (i
= 0; i
< pad
; i
++)
496 width
= preci
= 0; /* Everything already done */
506 *va_arg(args
, int *) = outcount
;
511 ptr
--; /* We've gone too far - step one back */
512 buffer2
= (char *)format
;
513 size2
= ptr
- format
;
517 pad
= size1
+ (size2
>= preci
? size2
: preci
); /* Calculate the number of characters */
518 pad
= pad
>= width
? 0 : width
- pad
; /* and the number of resulting pad bytes */
520 if (flags
& ZEROPADFLAG
) /* print sign and that like */
521 for (i
= 0; i
< size1
; i
++)
522 FMTPRINTF_COUT(buffer1
[i
]);
524 if (!(flags
& LALIGNFLAG
)) /* Pad left */
525 for (i
= 0; i
< pad
; i
++)
526 FMTPRINTF_COUT(flags
& ZEROPADFLAG
? '0' : ' ');
528 if (!(flags
& ZEROPADFLAG
)) /* print sign if not zero padded */
529 for (i
= 0; i
< size1
; i
++)
530 FMTPRINTF_COUT(buffer1
[i
]);
532 for (i
= size2
; i
< preci
; i
++) /* extend to precision */
535 for (i
= 0; i
< size2
; i
++) /* print body */
536 FMTPRINTF_COUT(buffer2
[i
]);
538 if (flags
& LALIGNFLAG
) /* Pad right */
539 for (i
= 0; i
< pad
; i
++)
545 FMTPRINTF_COUT(*format
++);