HelenOS sources
This source file includes following definitions.
- printf_putnchars
- printf_wputnchars
- printf_putstr
- printf_putchar
- printf_putuchar
- print_char
- print_wchar
- print_str
- print_wstr
- print_number
- get_sign_char
- print_padding
- print_special
- fp_trim_trailing_zeros
- fp_round_up
- print_double_str_fixed
- print_double_fixed
- print_exponent
- print_double_str_scient
- print_double_scientific
- print_double_generic
- print_double
- printf_core
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <printf_core.h>
#include <ctype.h>
#include <str.h>
#include <assert.h>
#include <macros.h>
#include <uchar.h>
#if __STDC_HOSTED__
#define HAS_FLOAT
#endif
#ifdef HAS_FLOAT
#include <double_to_str.h>
#include <ieee_double.h>
#endif
#define __PRINTF_FLAG_PREFIX 0x00000001
#define __PRINTF_FLAG_DECIMALPT 0x00000001
#define __PRINTF_FLAG_SIGNED 0x00000002
#define __PRINTF_FLAG_ZEROPADDED 0x00000004
#define __PRINTF_FLAG_LEFTALIGNED 0x00000010
#define __PRINTF_FLAG_SHOWPLUS 0x00000020
#define __PRINTF_FLAG_SPACESIGN 0x00000040
#define __PRINTF_FLAG_BIGCHARS 0x00000080
#define __PRINTF_FLAG_NEGATIVE 0x00000100
#define __PRINTF_FLAG_NOFRACZEROS 0x00000200
#define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
#define PRINTF_GET_INT_ARGUMENT(type, ap, flags) \
({ \
unsigned type res; \
\
if ((flags) & __PRINTF_FLAG_SIGNED) { \
signed type arg = va_arg((ap), signed type); \
\
if (arg < 0) { \
res = -arg; \
(flags) |= __PRINTF_FLAG_NEGATIVE; \
} else \
res = arg; \
} else \
res = va_arg((ap), unsigned type); \
\
res; \
})
typedef enum {
PrintfQualifierByte = 0,
PrintfQualifierShort,
PrintfQualifierInt,
PrintfQualifierLong,
PrintfQualifierLongLong,
PrintfQualifierPointer,
PrintfQualifierSize,
PrintfQualifierMax
} qualifier_t;
static const char *nullstr = "(NULL)";
static const char *digits_small = "0123456789abcdef";
static const char *digits_big = "0123456789ABCDEF";
static const char invalch = U_SPECIAL;
static int printf_putnchars(const char *buf, size_t size,
printf_spec_t *ps)
{
return ps->str_write((void *) buf, size, ps->data);
}
static int printf_wputnchars(const char32_t *buf, size_t size,
printf_spec_t *ps)
{
return ps->wstr_write((void *) buf, size, ps->data);
}
static int printf_putstr(const char *str, printf_spec_t *ps)
{
if (str == NULL)
return printf_putnchars(nullstr, str_size(nullstr), ps);
return ps->str_write((void *) str, str_size(str), ps->data);
}
static int printf_putchar(const char ch, printf_spec_t *ps)
{
if (!ascii_check(ch))
return ps->str_write((void *) &invalch, 1, ps->data);
return ps->str_write(&ch, 1, ps->data);
}
static int printf_putuchar(const char32_t ch, printf_spec_t *ps)
{
if (!chr_check(ch))
return ps->str_write((void *) &invalch, 1, ps->data);
return ps->wstr_write(&ch, sizeof(char32_t), ps->data);
}
static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
{
size_t counter = 0;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (--width > 0) {
if (printf_putchar(' ', ps) > 0)
counter++;
}
}
if (printf_putchar(ch, ps) > 0)
counter++;
while (--width > 0) {
if (printf_putchar(' ', ps) > 0)
counter++;
}
return (int) (counter);
}
static int print_wchar(const char32_t ch, int width, uint32_t flags, printf_spec_t *ps)
{
size_t counter = 0;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (--width > 0) {
if (printf_putchar(' ', ps) > 0)
counter++;
}
}
if (printf_putuchar(ch, ps) > 0)
counter++;
while (--width > 0) {
if (printf_putchar(' ', ps) > 0)
counter++;
}
return (int) (counter);
}
static int print_str(char *str, int width, unsigned int precision,
uint32_t flags, printf_spec_t *ps)
{
if (str == NULL)
return printf_putstr(nullstr, ps);
size_t strw = str_length(str);
if ((precision == 0) || (precision > strw))
precision = strw;
size_t counter = 0;
width -= precision;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
}
int retval;
size_t size = str_lsize(str, precision);
if ((retval = printf_putnchars(str, size, ps)) < 0)
return -counter;
counter += retval;
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
return ((int) counter);
}
static int print_wstr(char32_t *str, int width, unsigned int precision,
uint32_t flags, printf_spec_t *ps)
{
if (str == NULL)
return printf_putstr(nullstr, ps);
size_t strw = wstr_length(str);
if ((precision == 0) || (precision > strw))
precision = strw;
size_t counter = 0;
width -= precision;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
}
int retval;
size_t size = wstr_lsize(str, precision);
if ((retval = printf_wputnchars(str, size, ps)) < 0)
return -counter;
counter += retval;
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
return ((int) counter);
}
static int print_number(uint64_t num, int width, int precision, int base,
uint32_t flags, printf_spec_t *ps)
{
if (precision < 0) {
precision = 0;
}
const char *digits;
if (flags & __PRINTF_FLAG_BIGCHARS)
digits = digits_big;
else
digits = digits_small;
char data[PRINT_NUMBER_BUFFER_SIZE];
char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
int size = 0;
*ptr-- = 0;
if (num == 0) {
*ptr-- = '0';
size++;
} else {
do {
*ptr-- = digits[num % base];
size++;
} while (num /= base);
}
int number_size = size;
if (flags & __PRINTF_FLAG_PREFIX) {
switch (base) {
case 2:
size += 2;
break;
case 8:
size++;
break;
case 16:
size += 2;
break;
}
}
char sgn = 0;
if (flags & __PRINTF_FLAG_SIGNED) {
if (flags & __PRINTF_FLAG_NEGATIVE) {
sgn = '-';
size++;
} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
sgn = '+';
size++;
} else if (flags & __PRINTF_FLAG_SPACESIGN) {
sgn = ' ';
size++;
}
}
if (flags & __PRINTF_FLAG_LEFTALIGNED)
flags &= ~__PRINTF_FLAG_ZEROPADDED;
if (flags & __PRINTF_FLAG_ZEROPADDED) {
if ((precision == 0) && (width > size))
precision = width - size + number_size;
}
if (number_size > precision) {
precision = number_size;
}
width -= precision + size - number_size;
size_t counter = 0;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
}
if (sgn) {
if (printf_putchar(sgn, ps) == 1)
counter++;
}
if (flags & __PRINTF_FLAG_PREFIX) {
switch (base) {
case 2:
if (printf_putchar('0', ps) == 1)
counter++;
if (flags & __PRINTF_FLAG_BIGCHARS) {
if (printf_putchar('B', ps) == 1)
counter++;
} else {
if (printf_putchar('b', ps) == 1)
counter++;
}
break;
case 8:
if (printf_putchar('o', ps) == 1)
counter++;
break;
case 16:
if (printf_putchar('0', ps) == 1)
counter++;
if (flags & __PRINTF_FLAG_BIGCHARS) {
if (printf_putchar('X', ps) == 1)
counter++;
} else {
if (printf_putchar('x', ps) == 1)
counter++;
}
break;
}
}
precision -= number_size;
while (precision-- > 0) {
if (printf_putchar('0', ps) == 1)
counter++;
}
int retval;
if ((retval = printf_putstr(++ptr, ps)) > 0)
counter += retval;
while (width-- > 0) {
if (printf_putchar(' ', ps) == 1)
counter++;
}
return ((int) counter);
}
#ifdef HAS_FLOAT
typedef struct {
char *str;
int len;
int dec_exp;
bool neg;
} double_str_t;
static int get_sign_char(bool negative, uint32_t flags)
{
if (negative) {
return '-';
} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
return '+';
} else if (flags & __PRINTF_FLAG_SPACESIGN) {
return ' ';
} else {
return 0;
}
}
static int print_padding(char ch, int count, printf_spec_t *ps)
{
for (int i = 0; i < count; ++i) {
if (ps->str_write(&ch, 1, ps->data) < 0) {
return -1;
}
}
return count;
}
static int print_special(ieee_double_t val, int width, uint32_t flags,
printf_spec_t *ps)
{
assert(val.is_special);
char sign = get_sign_char(val.is_negative, flags);
const int str_len = 3;
const char *str;
if (flags & __PRINTF_FLAG_BIGCHARS) {
str = val.is_infinity ? "INF" : "NAN";
} else {
str = val.is_infinity ? "inf" : "nan";
}
int padding_len = max(0, width - ((sign ? 1 : 0) + str_len));
int counter = 0;
int ret;
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
if ((ret = print_padding(' ', padding_len, ps)) < 0)
return -1;
counter += ret;
}
if (sign) {
if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
return -1;
counter += ret;
}
if ((ret = ps->str_write(str, str_len, ps->data)) < 0)
return -1;
counter += ret;
if (flags & __PRINTF_FLAG_LEFTALIGNED) {
if ((ret = print_padding(' ', padding_len, ps)) < 0)
return -1;
counter += ret;
}
return counter;
}
static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)
{
while (2 <= *len && '0' == buf[*len - 1]) {
--*len;
++*dec_exp;
}
}
static void fp_round_up(char *buf, int *len, int *dec_exp)
{
assert(1 <= *len);
char *last_digit = &buf[*len - 1];
int carry = ('5' <= *last_digit);
--*len;
++*dec_exp;
--last_digit;
if (carry) {
while (buf <= last_digit && '9' == *last_digit) {
--last_digit;
}
if (buf <= last_digit) {
*last_digit += 1;
int new_len = last_digit - buf + 1;
*dec_exp += *len - new_len;
*len = new_len;
} else {
buf[0] = '1';
*dec_exp += *len;
*len = 1;
}
} else {
if (last_digit < buf) {
buf[0] = '0';
*dec_exp = 0;
*len = 1;
}
}
}
static int print_double_str_fixed(double_str_t *val_str, int precision, int width,
uint32_t flags, printf_spec_t *ps)
{
int len = val_str->len;
char *buf = val_str->str;
int dec_exp = val_str->dec_exp;
assert(0 < len);
assert(0 <= precision);
assert(0 <= dec_exp || -dec_exp <= precision);
int int_len = max(1, len + dec_exp);
char sign = get_sign_char(val_str->neg, flags);
int last_frac_signif_pos = max(0, -dec_exp);
int leading_frac_zeros = max(0, last_frac_signif_pos - len);
int signif_frac_figs = min(last_frac_signif_pos, len);
int trailing_frac_zeros = precision - last_frac_signif_pos;
char *buf_frac = buf + len - signif_frac_figs;
if (flags & __PRINTF_FLAG_NOFRACZEROS) {
trailing_frac_zeros = 0;
}
int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros;
bool has_decimal_pt = (0 < frac_len) || (flags & __PRINTF_FLAG_DECIMALPT);
int num_len = (sign ? 1 : 0) + int_len + (has_decimal_pt ? 1 : 0) + frac_len;
int padding_len = max(0, width - num_len);
int ret = 0;
int counter = 0;
if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
if ((ret = print_padding(' ', padding_len, ps)) < 0)
return -1;
counter += ret;
}
if (sign) {
if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
return -1;
counter += ret;
}
if (flags & __PRINTF_FLAG_ZEROPADDED) {
if ((ret = print_padding('0', padding_len, ps)) < 0)
return -1;
counter += ret;
}
int buf_int_len = min(len, len + dec_exp);
if (0 < buf_int_len) {
if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0)
return -1;
counter += ret;
if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0)
return -1;
} else {
char ch = '0';
if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
return -1;
}
counter += ret;
if (has_decimal_pt) {
char ch = '.';
if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
return -1;
counter += ret;
if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0)
return -1;
counter += ret;
if (0 < signif_frac_figs) {
if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0)
return -1;
counter += ret;
}
if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
return -1;
counter += ret;
}
if (flags & __PRINTF_FLAG_LEFTALIGNED) {
if ((ret = print_padding(' ', padding_len, ps)) < 0)
return -1;
counter += ret;
}
return counter;
}
static int print_double_fixed(double g, int precision, int width, uint32_t flags,
printf_spec_t *ps)
{
if (flags & __PRINTF_FLAG_LEFTALIGNED) {
flags &= ~__PRINTF_FLAG_ZEROPADDED;
}
if (flags & __PRINTF_FLAG_DECIMALPT) {
flags &= ~__PRINTF_FLAG_NOFRACZEROS;
}
ieee_double_t val = extract_ieee_double(g);
if (val.is_special) {
return print_special(val, width, flags, ps);
}
char buf[MAX_DOUBLE_STR_BUF_SIZE];
const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
double_str_t val_str;
val_str.str = buf;
val_str.neg = val.is_negative;
if (0 <= precision) {
val_str.len = double_to_fixed_str(val, -1, precision + 1, buf, buf_size,
&val_str.dec_exp);
fp_round_up(buf, &val_str.len, &val_str.dec_exp);
if (flags & __PRINTF_FLAG_NOFRACZEROS) {
fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
}
} else {
val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
precision = max(0, -val_str.dec_exp);
}
return print_double_str_fixed(&val_str, precision, width, flags, ps);
}
static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps)
{
int counter = 0;
int ret;
char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e';
if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0)
return -1;
counter += ret;
char exp_sign = (exp_val < 0) ? '-' : '+';
if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0)
return -1;
counter += ret;
exp_val = abs(exp_val);
char exp_str[4] = { 0 };
exp_str[0] = '0' + exp_val / 100;
exp_str[1] = '0' + (exp_val % 100) / 10;
exp_str[2] = '0' + (exp_val % 10);
int exp_len = (exp_str[0] == '0') ? 2 : 3;
const char *exp_str_start = &exp_str[3] - exp_len;
if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0)
return -1;
counter += ret;
return counter;
}
static int print_double_str_scient(double_str_t *val_str, int precision,
int width, uint32_t flags, printf_spec_t *ps)
{
int len = val_str->len;
int dec_exp = val_str->dec_exp;
char *buf = val_str->str;
assert(0 < len);
char sign = get_sign_char(val_str->neg, flags);
bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT);
int dec_pt_len = has_decimal_pt ? 1 : 0;
int signif_frac_figs = len - 1;
int trailing_frac_zeros = precision - signif_frac_figs;
if (flags & __PRINTF_FLAG_NOFRACZEROS) {
trailing_frac_zeros = 0;
}
int frac_len = signif_frac_figs + trailing_frac_zeros;
int exp_val = dec_exp + len - 1;
int exp_len = 2 + (abs(exp_val) >= 100 ? 3 : 2);
int num_len = (sign ? 1 : 0) + 1 + dec_pt_len + frac_len + exp_len;
int padding_len = max(0, width - num_len);
int ret = 0;
int counter = 0;
if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
if ((ret = print_padding(' ', padding_len, ps)) < 0)
return -1;
counter += ret;
}
if (sign) {
if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
return -1;
counter += ret;
}
if (flags & __PRINTF_FLAG_ZEROPADDED) {
if ((ret = print_padding('0', padding_len, ps)) < 0)
return -1;
counter += ret;
}
if ((ret = ps->str_write(buf, 1, ps->data)) < 0)
return -1;
counter += ret;
if (has_decimal_pt) {
char ch = '.';
if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
return -1;
counter += ret;
if (0 < signif_frac_figs) {
if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0)
return -1;
counter += ret;
}
if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
return -1;
counter += ret;
}
if ((ret = print_exponent(exp_val, flags, ps)) < 0)
return -1;
counter += ret;
if (flags & __PRINTF_FLAG_LEFTALIGNED) {
if ((ret = print_padding(' ', padding_len, ps)) < 0)
return -1;
counter += ret;
}
return counter;
}
static int print_double_scientific(double g, int precision, int width,
uint32_t flags, printf_spec_t *ps)
{
if (flags & __PRINTF_FLAG_LEFTALIGNED) {
flags &= ~__PRINTF_FLAG_ZEROPADDED;
}
ieee_double_t val = extract_ieee_double(g);
if (val.is_special) {
return print_special(val, width, flags, ps);
}
char buf[MAX_DOUBLE_STR_BUF_SIZE];
const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
double_str_t val_str;
val_str.str = buf;
val_str.neg = val.is_negative;
if (0 <= precision) {
val_str.len = double_to_fixed_str(val, precision + 2, -1, buf, buf_size,
&val_str.dec_exp);
fp_round_up(buf, &val_str.len, &val_str.dec_exp);
if (flags & __PRINTF_FLAG_NOFRACZEROS) {
fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
}
} else {
val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
precision = val_str.len - 1;
}
return print_double_str_scient(&val_str, precision, width, flags, ps);
}
static int print_double_generic(double g, int precision, int width,
uint32_t flags, printf_spec_t *ps)
{
ieee_double_t val = extract_ieee_double(g);
if (val.is_special) {
return print_special(val, width, flags, ps);
}
char buf[MAX_DOUBLE_STR_BUF_SIZE];
const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
int dec_exp;
int len;
if (0 <= precision) {
len = double_to_fixed_str(val, 1, -1, buf, buf_size, &dec_exp);
assert(0 < len);
precision = max(1, precision);
if (-4 <= dec_exp && dec_exp < precision) {
precision = precision - (dec_exp + 1);
return print_double_fixed(g, precision, width,
flags | __PRINTF_FLAG_NOFRACZEROS, ps);
} else {
--precision;
return print_double_scientific(g, precision, width,
flags | __PRINTF_FLAG_NOFRACZEROS, ps);
}
} else {
len = double_to_short_str(val, buf, buf_size, &dec_exp);
assert(0 < len);
if (flags & __PRINTF_FLAG_LEFTALIGNED) {
flags &= ~__PRINTF_FLAG_ZEROPADDED;
}
double_str_t val_str;
val_str.str = buf;
val_str.len = len;
val_str.neg = val.is_negative;
val_str.dec_exp = dec_exp;
int first_digit_pos = len + dec_exp;
int last_digit_pos = dec_exp;
if (len <= 15 && -6 <= last_digit_pos && first_digit_pos <= 15) {
precision = max(0, -val_str.dec_exp);
return print_double_str_fixed(&val_str, precision, width, flags, ps);
} else {
precision = val_str.len - 1;
return print_double_str_scient(&val_str, precision, width, flags, ps);
}
}
}
static int print_double(double g, char spec, int precision, int width,
uint32_t flags, printf_spec_t *ps)
{
switch (spec) {
case 'F':
flags |= __PRINTF_FLAG_BIGCHARS;
case 'f':
precision = (precision < 0) ? 6 : precision;
return print_double_fixed(g, precision, width, flags, ps);
case 'E':
flags |= __PRINTF_FLAG_BIGCHARS;
case 'e':
precision = (precision < 0) ? 6 : precision;
return print_double_scientific(g, precision, width, flags, ps);
case 'G':
flags |= __PRINTF_FLAG_BIGCHARS;
case 'g':
return print_double_generic(g, precision, width, flags, ps);
default:
assert(false);
return -1;
}
}
#endif
int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
{
size_t i;
size_t nxt = 0;
size_t j = 0;
size_t counter = 0;
int retval;
while (true) {
i = nxt;
char32_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 0)
break;
if (uc == '%') {
if (i > j) {
if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
counter = -counter;
goto out;
}
counter += retval;
}
j = i;
uint32_t flags = 0;
bool end = false;
do {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
switch (uc) {
case '#':
flags |= __PRINTF_FLAG_PREFIX;
flags |= __PRINTF_FLAG_DECIMALPT;
break;
case '-':
flags |= __PRINTF_FLAG_LEFTALIGNED;
break;
case '+':
flags |= __PRINTF_FLAG_SHOWPLUS;
break;
case ' ':
flags |= __PRINTF_FLAG_SPACESIGN;
break;
case '0':
flags |= __PRINTF_FLAG_ZEROPADDED;
break;
default:
end = true;
}
} while (!end);
int width = 0;
if (isdigit(uc)) {
while (true) {
width *= 10;
width += uc - '0';
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 0)
break;
if (!isdigit(uc))
break;
}
} else if (uc == '*') {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
width = (int) va_arg(ap, int);
if (width < 0) {
width *= -1;
flags |= __PRINTF_FLAG_LEFTALIGNED;
}
}
int precision = -1;
if (uc == '.') {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (isdigit(uc)) {
precision = 0;
while (true) {
precision *= 10;
precision += uc - '0';
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 0)
break;
if (!isdigit(uc))
break;
}
} else if (uc == '*') {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
precision = (int) va_arg(ap, int);
if (precision < 0) {
precision = -1;
}
}
}
qualifier_t qualifier;
switch (uc) {
case 't':
if (sizeof(ptrdiff_t) == sizeof(int32_t))
qualifier = PrintfQualifierInt;
else
qualifier = PrintfQualifierLongLong;
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
break;
case 'h':
qualifier = PrintfQualifierShort;
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 'h') {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
qualifier = PrintfQualifierByte;
}
break;
case 'l':
qualifier = PrintfQualifierLong;
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
if (uc == 'l') {
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
qualifier = PrintfQualifierLongLong;
}
break;
case 'z':
qualifier = PrintfQualifierSize;
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
break;
case 'j':
qualifier = PrintfQualifierMax;
i = nxt;
uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
break;
default:
qualifier = PrintfQualifierInt;
}
unsigned int base = 10;
switch (uc) {
case 's':
precision = max(0, precision);
if (qualifier == PrintfQualifierLong)
retval = print_wstr(va_arg(ap, char32_t *), width, precision, flags, ps);
else
retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
if (retval < 0) {
counter = -counter;
goto out;
}
counter += retval;
j = nxt;
continue;
case 'c':
if (qualifier == PrintfQualifierLong)
retval = print_wchar(va_arg(ap, wint_t), width, flags, ps);
else
retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
if (retval < 0) {
counter = -counter;
goto out;
}
counter += retval;
j = nxt;
continue;
#ifdef HAS_FLOAT
case 'G':
case 'g':
case 'F':
case 'f':
case 'E':
case 'e':
retval = print_double(va_arg(ap, double), uc, precision,
width, flags, ps);
if (retval < 0) {
counter = -counter;
goto out;
}
counter += retval;
j = nxt;
continue;
#endif
case 'P':
flags |= __PRINTF_FLAG_BIGCHARS;
case 'p':
flags |= __PRINTF_FLAG_PREFIX;
flags |= __PRINTF_FLAG_ZEROPADDED;
base = 16;
qualifier = PrintfQualifierPointer;
break;
case 'b':
base = 2;
break;
case 'o':
base = 8;
break;
case 'd':
case 'i':
flags |= __PRINTF_FLAG_SIGNED;
case 'u':
break;
case 'X':
flags |= __PRINTF_FLAG_BIGCHARS;
case 'x':
base = 16;
break;
case '%':
j = i;
continue;
default:
continue;
}
size_t size;
uint64_t number;
switch (qualifier) {
case PrintfQualifierByte:
size = sizeof(unsigned char);
number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
break;
case PrintfQualifierShort:
size = sizeof(unsigned short);
number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
break;
case PrintfQualifierInt:
size = sizeof(unsigned int);
number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
break;
case PrintfQualifierLong:
size = sizeof(unsigned long);
number = PRINTF_GET_INT_ARGUMENT(long, ap, flags);
break;
case PrintfQualifierLongLong:
size = sizeof(unsigned long long);
number = PRINTF_GET_INT_ARGUMENT(long long, ap, flags);
break;
case PrintfQualifierPointer:
size = sizeof(void *);
precision = size << 1;
number = (uint64_t) (uintptr_t) va_arg(ap, void *);
break;
case PrintfQualifierSize:
size = sizeof(size_t);
number = (uint64_t) va_arg(ap, size_t);
break;
case PrintfQualifierMax:
size = sizeof(uintmax_t);
number = (uint64_t) va_arg(ap, uintmax_t);
break;
default:
counter = -counter;
goto out;
}
if ((retval = print_number(number, width, precision,
base, flags, ps)) < 0) {
counter = -counter;
goto out;
}
counter += retval;
j = nxt;
}
}
if (i > j) {
if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
counter = -counter;
goto out;
}
counter += retval;
}
out:
return ((int) counter);
}
HelenOS homepage, sources at GitHub