81,53 → 81,54 |
static char nullstr[] = "(NULL)"; |
static char digits_small[] = "0123456789abcdef"; |
static char digits_big[] = "0123456789ABCDEF"; |
static char invalch = U_SPECIAL; |
|
/** Print one or more UTF-8 characters without adding newline. |
/** Print one or more characters without adding newline. |
* |
* @param buf Buffer holding UTF-8 characters with size of |
* @param buf Buffer holding characters with size of |
* at least size bytes. NULL is not allowed! |
* @param size Size of the buffer in bytes. |
* @param ps Output method and its data. |
* |
* @return Number of UTF-8 characters printed. |
* @return Number of characters printed. |
* |
*/ |
static int printf_putnchars_utf8(const char *buf, size_t size, |
static int printf_putnchars(const char *buf, size_t size, |
printf_spec_t *ps) |
{ |
return ps->write_utf8((void *) buf, size, ps->data); |
return ps->str_write((void *) buf, size, ps->data); |
} |
|
/** Print one or more UTF-32 characters without adding newline. |
/** Print one or more wide characters without adding newline. |
* |
* @param buf Buffer holding UTF-32 characters with size of |
* @param buf Buffer holding wide characters with size of |
* at least size bytes. NULL is not allowed! |
* @param size Size of the buffer in bytes. |
* @param ps Output method and its data. |
* |
* @return Number of UTF-32 characters printed. |
* @return Number of wide characters printed. |
* |
*/ |
static int printf_putnchars_utf32(const wchar_t *buf, size_t size, |
static int printf_wputnchars(const wchar_t *buf, size_t size, |
printf_spec_t *ps) |
{ |
return ps->write_utf32((void *) buf, size, ps->data); |
return ps->wstr_write((void *) buf, size, ps->data); |
} |
|
/** Print UTF-8 string without adding a newline. |
/** Print string without adding a newline. |
* |
* @param str UTF-8 string to print. |
* @param str String to print. |
* @param ps Write function specification and support data. |
* |
* @return Number of UTF-8 characters printed. |
* @return Number of characters printed. |
* |
*/ |
static int printf_putstr(const char *str, printf_spec_t *ps) |
{ |
if (str == NULL) |
return printf_putnchars_utf8(nullstr, strlen(nullstr), ps); |
return printf_putnchars(nullstr, str_size(nullstr), ps); |
|
return ps->write_utf8((void *) str, strlen(str), ps->data); |
return ps->str_write((void *) str, str_size(str), ps->data); |
} |
|
/** Print one ASCII character. |
141,14 → 142,14 |
static int printf_putchar(const char ch, printf_spec_t *ps) |
{ |
if (!ascii_check(ch)) |
return ps->write_utf8((void *) &invalch, 1, ps->data); |
return ps->str_write((void *) &invalch, 1, ps->data); |
|
return ps->write_utf8(&ch, 1, ps->data); |
return ps->str_write(&ch, 1, ps->data); |
} |
|
/** Print one UTF-32 character. |
/** Print one wide character. |
* |
* @param c UTF-32 character to be printed. |
* @param c Wide character to be printed. |
* @param ps Output method. |
* |
* @return Number of characters printed. |
156,10 → 157,10 |
*/ |
static int printf_putwchar(const wchar_t ch, printf_spec_t *ps) |
{ |
if (!unicode_check(ch)) |
return ps->write_utf8((void *) &invalch, 1, ps->data); |
if (!chr_check(ch)) |
return ps->str_write((void *) &invalch, 1, ps->data); |
|
return ps->write_utf32(&ch, sizeof(wchar_t), ps->data); |
return ps->wstr_write(&ch, sizeof(wchar_t), ps->data); |
} |
|
/** Print one formatted ASCII character. |
200,7 → 201,7 |
return (int) (counter + 1); |
} |
|
/** Print one formatted UTF-32 character. |
/** Print one formatted wide character. |
* |
* @param ch Character to print. |
* @param width Width modifier. |
238,26 → 239,27 |
return (int) (counter + 1); |
} |
|
/** Print UTF-8 string. |
/** Print string. |
* |
* @param str UTF-8 string to be printed. |
* @param str String to be printed. |
* @param width Width modifier. |
* @param precision Precision modifier. |
* @param flags Flags that modify the way the string is printed. |
* |
* @return Number of UTF-8 characters printed, negative value on failure. |
* @return Number of characters printed, negative value on failure. |
*/ |
static int print_utf8(char *str, int width, unsigned int precision, |
uint32_t flags, printf_spec_t *ps) |
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); |
|
/* Print leading spaces */ |
size_t size = strlen_utf8(str); |
|
/* Print leading spaces. */ |
count_t strw = str_length(str); |
if (precision == 0) |
precision = size; |
|
precision = strw; |
|
/* Left padding */ |
count_t counter = 0; |
width -= precision; |
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { |
266,42 → 268,49 |
counter++; |
} |
} |
|
|
/* Part of @a str fitting into the alloted space. */ |
int retval; |
size_t bytes = utf8_count_bytes(str, min(size, precision)); |
if ((retval = printf_putnchars_utf8(str, bytes, ps)) < 0) |
size_t size = str_lsize(str, precision); |
if ((retval = printf_putnchars(str, size, ps)) < 0) |
return -counter; |
|
|
counter += retval; |
|
|
/* Right padding */ |
while (width-- > 0) { |
if (printf_putchar(' ', ps) == 1) |
counter++; |
} |
|
|
return ((int) counter); |
|
} |
|
/** Print UTF-32 string. |
/** Print wide string. |
* |
* @param str UTF-32 string to be printed. |
* @param str Wide string to be printed. |
* @param width Width modifier. |
* @param precision Precision modifier. |
* @param flags Flags that modify the way the string is printed. |
* |
* @return Number of UTF-32 characters printed, negative value on failure. |
* @return Number of wide characters printed, negative value on failure. |
*/ |
static int print_utf32(wchar_t *str, int width, unsigned int precision, |
uint32_t flags, printf_spec_t *ps) |
static int print_wstr(wchar_t *str, int width, unsigned int precision, |
uint32_t flags, printf_spec_t *ps) |
{ |
if (str == NULL) |
return printf_putstr(nullstr, ps); |
|
/* Print leading spaces */ |
size_t size = strlen_utf32(str); |
if (*str == U_BOM) |
str++; |
|
/* Print leading spaces. */ |
size_t strw = wstr_length(str); |
if (precision == 0) |
precision = size; |
precision = strw; |
|
/* Left padding */ |
count_t counter = 0; |
width -= precision; |
if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { |
311,18 → 320,20 |
} |
} |
|
/* Part of @a wstr fitting into the alloted space. */ |
int retval; |
size_t bytes = min(size, precision) * sizeof(wchar_t); |
if ((retval = printf_putnchars_utf32(str, bytes, ps)) < 0) |
size_t size = wstr_lsize(str, precision); |
if ((retval = printf_wputnchars(str, size, ps)) < 0) |
return -counter; |
|
counter += retval; |
|
/* Right padding */ |
while (width-- > 0) { |
if (printf_putchar(' ', ps) == 1) |
counter++; |
} |
|
|
return ((int) counter); |
} |
|
537,8 → 548,8 |
* - "h" Signed or unsigned short.@n |
* - "" Signed or unsigned int (default value).@n |
* - "l" Signed or unsigned long int.@n |
* If conversion is "c", the character is wchar_t (UTF-32).@n |
* If conversion is "s", the string is wchar_t * (UTF-32).@n |
* If conversion is "c", the character is wchar_t (wide character).@n |
* If conversion is "s", the string is wchar_t * (wide string).@n |
* - "ll" Signed or unsigned long long int.@n |
* |
* CONVERSION:@n |
546,15 → 557,12 |
* |
* - c Print single character. The character is expected to be plain |
* ASCII (e.g. only values 0 .. 127 are valid).@n |
* If type is "l", then the character is expected to be UTF-32 |
* If type is "l", then the character is expected to be wide character |
* (e.g. values 0 .. 0x10ffff are valid). |
* |
* - s Print zero terminated string. If a NULL value is passed as |
* value, "(NULL)" is printed instead.@n |
* The string is expected to be correctly encoded UTF-8 (or plain |
* ASCII, which is a subset of UTF-8).@n |
* If type is "l", then the string is expected to be correctly |
* encoded UTF-32. |
* If type is "l", then the string is expected to be wide string. |
* |
* - P, p Print value of a pointer. Void * value is expected and it is |
* printed in hexadecimal notation with prefix (as with \%#X / \%#x |
574,29 → 582,35 |
* - X, x Print hexadecimal number with upper- or lower-case. Prefix is |
* not printed by default. |
* |
* All other characters from fmt except the formatting directives are printed in |
* All other characters from fmt except the formatting directives are printed |
* verbatim. |
* |
* @param fmt Formatting NULL terminated string (UTF-8 or plain ASCII). |
* @param fmt Format NULL-terminated string. |
* |
* @return Number of UTF-8 characters printed, negative value on failure. |
* @return Number of characters printed, negative value on failure. |
* |
*/ |
int printf_core(const char *fmt, printf_spec_t *ps, va_list ap) |
{ |
index_t i = 0; /* Index of the currently processed character from fmt */ |
index_t j = 0; /* Index to the first not printed nonformating character */ |
size_t i; /* Index of the currently processed character from fmt */ |
size_t nxt = 0; /* Index of the next character from fmt */ |
size_t j = 0; /* Index to the first not printed nonformating character */ |
|
wchar_t uc; /* Current UTF-32 character decoded from fmt */ |
count_t counter = 0; /* Number of UTF-8 characters printed */ |
count_t counter = 0; /* Number of characters printed */ |
int retval; /* Return values from nested functions */ |
|
while ((uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT)) != 0) { |
while (true) { |
i = nxt; |
wchar_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
|
if (uc == 0) |
break; |
|
/* Control character */ |
if (uc == '%') { |
/* Print common characters if any processed */ |
if (i > j) { |
if ((retval = printf_putnchars_utf8(&fmt[j], i - j, ps)) < 0) { |
if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) { |
/* Error */ |
counter = -counter; |
goto out; |
611,8 → 625,8 |
bool end = false; |
|
do { |
i++; |
uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT); |
i = nxt; |
uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
switch (uc) { |
case '#': |
flags |= __PRINTF_FLAG_PREFIX; |
637,18 → 651,21 |
/* Width & '*' operator */ |
int width = 0; |
if (isdigit(uc)) { |
while ((uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT)) != 0) { |
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; |
|
width *= 10; |
width += uc - '0'; |
i++; |
} |
} else if (uc == '*') { |
/* Get width value from argument list */ |
i++; |
uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT); |
i = nxt; |
uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
width = (int) va_arg(ap, int); |
if (width < 0) { |
/* Negative width sets '-' flag */ |
660,21 → 677,24 |
/* Precision and '*' operator */ |
int precision = 0; |
if (uc == '.') { |
i++; |
uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT); |
i = nxt; |
uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
if (isdigit(uc)) { |
while ((uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT)) != 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; |
|
precision *= 10; |
precision += uc - '0'; |
i++; |
} |
} else if (fmt[i] == '*') { |
} else if (uc == '*') { |
/* Get precision value from the argument list */ |
i++; |
uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT); |
i = nxt; |
uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
precision = (int) va_arg(ap, int); |
if (precision < 0) { |
/* Ignore negative precision */ |
692,11 → 712,11 |
case 'h': |
/* Char or short */ |
qualifier = PrintfQualifierShort; |
i++; |
uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT); |
i = nxt; |
uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
if (uc == 'h') { |
i++; |
uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT); |
i = nxt; |
uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
qualifier = PrintfQualifierByte; |
} |
break; |
703,11 → 723,11 |
case 'l': |
/* Long or long long */ |
qualifier = PrintfQualifierLong; |
i++; |
uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT); |
i = nxt; |
uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
if (uc == 'l') { |
i++; |
uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT); |
i = nxt; |
uc = str_decode(fmt, &nxt, STR_NO_LIMIT); |
qualifier = PrintfQualifierLongLong; |
} |
break; |
724,9 → 744,9 |
*/ |
case 's': |
if (qualifier == PrintfQualifierLong) |
retval = print_utf32(va_arg(ap, wchar_t *), width, precision, flags, ps); |
retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps); |
else |
retval = print_utf8(va_arg(ap, char *), width, precision, flags, ps); |
retval = print_str(va_arg(ap, char *), width, precision, flags, ps); |
|
if (retval < 0) { |
counter = -counter; |
734,7 → 754,7 |
} |
|
counter += retval; |
j = i + 1; |
j = nxt; |
goto next_char; |
case 'c': |
if (qualifier == PrintfQualifierLong) |
748,7 → 768,7 |
}; |
|
counter += retval; |
j = i + 1; |
j = nxt; |
goto next_char; |
|
/* |
852,15 → 872,14 |
} |
|
counter += retval; |
j = i + 1; |
j = nxt; |
} |
next_char: |
|
i++; |
; |
} |
|
if (i > j) { |
if ((retval = printf_putnchars_utf8(&fmt[j], i - j, ps)) < 0) { |
if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) { |
/* Error */ |
counter = -counter; |
goto out; |