in libc/baselibc/src/tinyprintf.c [244:425]
size_t tfp_format(FILE *putp, const char *fmt, va_list va)
{
size_t written = 0;
struct param p;
char bf[23];
char ch;
char lng;
void *v;
#if MYNEWT_VAL(FLOAT_USER)
double d;
int n;
#endif
int i;
p.bf = bf;
while ((ch = *(fmt++))) {
if (ch != '%') {
written += putf(putp, ch);
} else {
/* Init parameter struct */
p.lz = 0;
p.alt = 0;
p.width = 0;
p.sign = 0;
p.left = 0;
p.uc = 0;
p.hh = 0;
lng = 0;
/* Flags */
while ((ch = *(fmt++))) {
switch (ch) {
case '0':
if (!p.left) {
p.lz = 1;
}
continue;
case '#':
p.alt = 1;
continue;
case '-':
p.left = 1;
p.lz = 0;
continue;
default:
break;
}
break;
}
/* Width */
if (ch == '*') {
i = intarg(0, 1, &va);
if (i > UCHAR_MAX) {
p.width = UCHAR_MAX;
} else if (i > 0) {
p.width = i;
}
ch = *(fmt++);
} else if (ch >= '0' && ch <= '9') {
ch = a2i(ch, &fmt, 10, &(p.width));
}
if (ch == 'l') {
ch = *(fmt++);
lng = 1;
if (ch == 'l') {
ch = *(fmt++);
lng = 2;
}
} else if (ch == 'h') {
ch = *(fmt++);
p.hh = 1;
if (ch == 'h') {
ch = *(fmt++);
p.hh = 2;
}
}
if (ch == 'z') {
ch = *(fmt++);
}
switch (ch) {
case 0:
goto abort;
case 'u':
p.base = 10;
ui2a(intarg(lng, 0, &va), &p);
written += putchw(putp, &p);
break;
case 'd':
case 'i':
p.base = 10;
i2a(intarg(lng, 1, &va), &p);
written += putchw(putp, &p);
break;
case 'x':
case 'X':
p.base = 16;
p.uc = (ch == 'X');
ui2a(intarg(lng, 0, &va), &p);
written += putchw(putp, &p);
break;
case 'o':
p.base = 8;
ui2a(intarg(lng, 0, &va), &p);
written += putchw(putp, &p);
break;
case 'p':
v = va_arg(va, void *);
p.base = 16;
ui2a((uintptr_t)v, &p);
p.width = 2 * sizeof(void*);
p.lz = 1;
written += putf(putp, '0');
written += putf(putp, 'x');
written += putchw(putp, &p);
break;
case 'c':
written += putf(putp, (char)(va_arg(va, int)));
break;
case 's':
p.bf = va_arg(va, char *);
written += putchw(putp, &p);
p.bf = bf;
break;
#if MYNEWT_VAL(FLOAT_USER)
case 'f':
p.base = 10;
d = va_arg(va, double);
/* Convert to an int to get the integer part of the number. */
n = d;
/* Convert to ascii */
i2a(n, &p);
/* When the double was converted to an int it was truncated
* towards 0. If the number is in the range (-1, 0), the
* negative sign was lost. Preserve the sign in this case.
*/
if (d < 0.0) {
p.sign = 1;
}
/* Ignore left align for integer part */
p.left = 0;
/* Subtract width for decimal part and decimal point */
if (p.width >= 4) {
p.width -= 4;
} else {
p.width = 0;
}
/* Write integer part to console */
written += putchw(putp, &p);
/* Take the decimal part and multiply by 1000 */
n = (d-n)*1000;
/* Convert to ascii */
i2a(n, &p);
/* Set the leading zeros for the next integer output to 3 */
p.lz = 3;
/* Always use the same decimal width */
p.width = 3;
/* Ignore sign for decimal part*/
p.sign = 0;
/* Output a decimal point */
putf(putp, '.');
/* Output the decimal part. */
written += putchw(putp, &p);
break;
#endif
case '%':
written += putf(putp, ch);
break;
default:
break;
}
}
}
abort:;
return written;
}