Changeset c7c6afd in mainline


Ignore:
Timestamp:
2025-04-13T23:27:44Z (4 days ago)
Author:
GitHub <noreply@…>
Children:
b6061f8c
Parents:
240b2e4 (diff), f5e1692 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Wayne Thornton <wmthornton-dev@…> (2025-04-13 23:27:44)
git-committer:
GitHub <noreply@…> (2025-04-13 23:27:44)
Message:

Merge branch 'HelenOS:master' into master

Files:
6 deleted
20 edited
2 moved

Legend:

Unmodified
Added
Removed
  • boot/arch/arm32/meson.build

    r240b2e4 rc7c6afd  
    6666        'src/putchar.c',
    6767        '../../../common/stdc/mem.c',
     68        '../../../common/printf/printf_core.c',
    6869        '../../genarch/src/division.c',
    69         '../../generic/src/printf_core.c',
    7070        '../../generic/src/vprintf.c',
    7171        '../../generic/src/printf.c',
  • boot/arch/arm64/meson.build

    r240b2e4 rc7c6afd  
    4949        'src/relocate.c',
    5050        '../../../common/stdc/mem.c',
     51        '../../../common/printf/printf_core.c',
    5152        '../../genarch/src/efi.c',
    5253        '../../generic/src/gzip.c',
     
    5556        '../../generic/src/payload.c',
    5657        '../../generic/src/printf.c',
    57         '../../generic/src/printf_core.c',
    5858        '../../../common/str.c',
    5959        '../../generic/src/tar.c',
  • boot/arch/ia64/meson.build

    r240b2e4 rc7c6afd  
    4545        '../../genarch/src/division.c',
    4646        '../../generic/src/balloc.c',
    47         '../../generic/src/printf_core.c',
     47        '../../../common/printf/printf_core.c',
    4848        '../../generic/src/vprintf.c',
    4949        '../../generic/src/printf.c',
  • boot/arch/mips32/meson.build

    r240b2e4 rc7c6afd  
    4545        '../../genarch/src/division.c',
    4646        '../../genarch/src/multiplication.c',
    47         '../../generic/src/printf_core.c',
     47        '../../../common/printf/printf_core.c',
    4848        '../../generic/src/vprintf.c',
    4949        '../../generic/src/printf.c',
  • boot/arch/ppc32/meson.build

    r240b2e4 rc7c6afd  
    4343        '../../genarch/src/multiplication.c',
    4444        '../../generic/src/balloc.c',
    45         '../../generic/src/printf_core.c',
     45        '../../../common/printf/printf_core.c',
    4646        '../../generic/src/vprintf.c',
    4747        '../../generic/src/printf.c',
  • boot/arch/riscv64/meson.build

    r240b2e4 rc7c6afd  
    3939
    4040        '../../../common/stdc/mem.c',
    41         '../../generic/src/printf_core.c',
     41        '../../../common/printf/printf_core.c',
    4242        '../../generic/src/vprintf.c',
    4343        '../../generic/src/printf.c',
  • boot/arch/sparc64/meson.build

    r240b2e4 rc7c6afd  
    4141        '../../genarch/src/ofw_tree.c',
    4242        '../../generic/src/balloc.c',
    43         '../../generic/src/printf_core.c',
     43        '../../../common/printf/printf_core.c',
    4444        '../../generic/src/vprintf.c',
    4545        '../../generic/src/printf.c',
  • boot/generic/include/macros.h

    r240b2e4 rc7c6afd  
    3434
    3535#define min(a, b)  ((a) < (b) ? (a) : (b))
     36#define max(a, b)  ((a) > (b) ? (a) : (b))
    3637
    3738#define isdigit(d)  (((d) >= '0') && ((d) <= '9'))
  • boot/generic/src/vprintf.c

    r240b2e4 rc7c6afd  
    3636#include <str.h>
    3737
    38 static int vprintf_str_write(const char *str, size_t size, void *data)
     38static errno_t vprintf_str_write(const char *str, size_t size, void *data)
    3939{
    4040        size_t offset = 0;
    41         size_t chars = 0;
    4241
    43         while (offset < size) {
     42        while (offset < size)
    4443                putuchar(str_decode(str, &offset, size));
    45                 chars++;
    46         }
    4744
    48         return chars;
     45        return EOK;
    4946}
    5047
     
    7168        };
    7269
    73         int ret = printf_core(fmt, &ps, ap);
    74 
    75         return ret;
     70        return printf_core(fmt, &ps, ap);
    7671}
    7772
  • common/include/printf_core.h

    r240b2e4 rc7c6afd  
    3636#define _LIBC_PRINTF_CORE_H_
    3737
     38#include <errno.h>
     39#include <stdarg.h>
    3840#include <stddef.h>
    39 #include <stdarg.h>
    4041#include <uchar.h>
    4142
    4243/** Structure for specifying output methods for different printf clones. */
    4344typedef struct {
    44         /* String output function, returns number of printed characters or EOF */
    45         int (*str_write)(const char *, size_t, void *);
    46 
    47         /* Wide string output function, returns number of printed characters or EOF */
    48         int (*wstr_write)(const char32_t *, size_t, void *);
     45        /*
     46         * String output function, returns EOK on success.
     47         * Only returns an error when an irrecoverable failure occurs and
     48         * the string cannot be fully output.
     49         */
     50        errno_t (*write)(const char *, size_t, void *);
    4951
    5052        /* User data - output stream specification, state, locks, etc. */
  • common/printf/printf_core.c

    r240b2e4 rc7c6afd  
    33 * Copyright (c) 2006 Josef Cejka
    44 * Copyright (c) 2009 Martin Decky
     5 * Copyright (c) 2025 Jiří Zárevúcky
    56 * All rights reserved.
    67 *
     
    3738 */
    3839
    39 #include <stdio.h>
     40#include <_bits/uchar.h>
     41#include <_bits/wint_t.h>
     42#include <assert.h>
     43#include <ctype.h>
     44#include <errno.h>
     45#include <limits.h>
     46#include <macros.h>
     47#include <printf_core.h>
    4048#include <stddef.h>
     49#include <stdint.h>
    4150#include <stdlib.h>
    42 #include <printf_core.h>
    43 #include <ctype.h>
    4451#include <str.h>
    45 #include <assert.h>
    46 #include <macros.h>
    47 #include <uchar.h>
    4852
    4953/* Disable float support in kernel, because we usually disable floating operations there. */
     
    8892
    8993/**
    90  * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
    91  * to terminate string... (last one is only for better testing end of buffer by
    92  * zero-filling subroutine)
    93  */
    94 #define PRINT_NUMBER_BUFFER_SIZE  (64 + 5)
     94 * Buffer big enough for 64-bit number printed in base 2.
     95 */
     96#define PRINT_NUMBER_BUFFER_SIZE  64
    9597
    9698/** Get signed or unsigned integer argument */
     
    122124        PrintfQualifierLongLong,
    123125        PrintfQualifierPointer,
    124         PrintfQualifierSize,
    125         PrintfQualifierMax
    126126} qualifier_t;
    127127
    128 static const char *nullstr = "(NULL)";
    129 static const char *digits_small = "0123456789abcdef";
    130 static const char *digits_big = "0123456789ABCDEF";
    131 static const char invalch = U_SPECIAL;
    132 
    133 /** Print one or more characters without adding newline.
    134  *
    135  * @param buf  Buffer holding characters with size of
    136  *             at least size bytes. NULL is not allowed!
    137  * @param size Size of the buffer in bytes.
    138  * @param ps   Output method and its data.
    139  *
    140  * @return Number of characters printed.
    141  *
    142  */
    143 static int printf_putnchars(const char *buf, size_t size,
    144     printf_spec_t *ps)
    145 {
    146         return ps->str_write((void *) buf, size, ps->data);
    147 }
    148 
    149 /** Print one or more wide characters without adding newline.
    150  *
    151  * @param buf  Buffer holding wide characters with size of
    152  *             at least size bytes. NULL is not allowed!
    153  * @param size Size of the buffer in bytes.
    154  * @param ps   Output method and its data.
    155  *
    156  * @return Number of wide characters printed.
    157  *
    158  */
    159 static int printf_wputnchars(const char32_t *buf, size_t size,
    160     printf_spec_t *ps)
    161 {
    162         return ps->wstr_write((void *) buf, size, ps->data);
    163 }
    164 
    165 /** Print string without adding a newline.
    166  *
    167  * @param str String to print.
    168  * @param ps  Write function specification and support data.
    169  *
    170  * @return Number of characters printed.
    171  *
    172  */
    173 static int printf_putstr(const char *str, printf_spec_t *ps)
    174 {
    175         if (str == NULL)
    176                 return printf_putnchars(nullstr, str_size(nullstr), ps);
    177 
    178         return ps->str_write((void *) str, str_size(str), ps->data);
    179 }
    180 
    181 /** Print one ASCII character.
    182  *
    183  * @param c  ASCII character to be printed.
    184  * @param ps Output method.
    185  *
    186  * @return Number of characters printed.
    187  *
    188  */
    189 static int printf_putchar(const char ch, printf_spec_t *ps)
    190 {
    191         if (!ascii_check(ch))
    192                 return ps->str_write((void *) &invalch, 1, ps->data);
    193 
    194         return ps->str_write(&ch, 1, ps->data);
    195 }
    196 
    197 /** Print one wide character.
    198  *
    199  * @param c  Wide character to be printed.
    200  * @param ps Output method.
    201  *
    202  * @return Number of characters printed.
    203  *
    204  */
    205 static int printf_putuchar(const char32_t ch, printf_spec_t *ps)
    206 {
    207         if (!chr_check(ch))
    208                 return ps->str_write((void *) &invalch, 1, ps->data);
    209 
    210         return ps->wstr_write(&ch, sizeof(char32_t), ps->data);
     128static const char _digits_small[] = "0123456789abcdef";
     129static const char _digits_big[] = "0123456789ABCDEF";
     130
     131static const char _nullstr[] = "(NULL)";
     132static const char _replacement[] = u8"�";
     133static const char _spaces[] = "                                               ";
     134static const char _zeros[] = "000000000000000000000000000000000000000000000000";
     135
     136static void _set_errno(errno_t rc)
     137{
     138        #ifdef errno
     139        errno = rc;
     140        #endif
     141}
     142
     143static size_t _utf8_bytes(char32_t c)
     144{
     145        if (c < 0x80)
     146                return 1;
     147
     148        if (c < 0x800)
     149                return 2;
     150
     151        if (c < 0xD800)
     152                return 3;
     153
     154        /* Surrogate code points, invalid in UTF-32. */
     155        if (c < 0xE000)
     156                return sizeof(_replacement) - 1;
     157
     158        if (c < 0x10000)
     159                return 3;
     160
     161        if (c < 0x110000)
     162                return 4;
     163
     164        /* Invalid character. */
     165        return sizeof(_replacement) - 1;
     166}
     167
     168/** Counts characters and utf8 bytes in a wide string up to a byte limit.
     169 * @param max_bytes    Byte length limit for string's utf8 conversion.
     170 * @param[out] len     The number of wide characters
     171 * @return  Number of utf8 bytes that the first *len characters in the string
     172 *          will convert to. Will always be less than max_bytes.
     173 */
     174static size_t _utf8_wstr_bytes_len(char32_t *s, size_t max_bytes, size_t *len)
     175{
     176        size_t bytes = 0;
     177        size_t i;
     178
     179        for (i = 0; bytes < max_bytes && s[i]; i++) {
     180                size_t next = _utf8_bytes(s[i]);
     181                if (max_bytes - bytes < next)
     182                        break;
     183
     184                bytes += next;
     185        }
     186
     187        *len = i;
     188        return bytes;
     189}
     190
     191#define TRY(expr) ({ errno_t rc = (expr); if (rc != EOK) return rc; })
     192
     193static inline void _saturating_add(size_t *a, size_t b)
     194{
     195        size_t s = *a + b;
     196        /* Only works because size_t is unsigned. */
     197        *a = (s < b) ? SIZE_MAX : s;
     198}
     199
     200static errno_t _write_bytes(const char *buf, size_t n, printf_spec_t *ps,
     201    size_t *written_bytes)
     202{
     203        errno_t rc = ps->write(buf, n, ps->data);
     204        if (rc != EOK)
     205                return rc;
     206
     207        _saturating_add(written_bytes, n);
     208        return EOK;
     209}
     210
     211/** Write one UTF-32 character. */
     212static errno_t _write_uchar(char32_t ch, printf_spec_t *ps,
     213    size_t *written_bytes)
     214{
     215        char utf8[4];
     216        size_t offset = 0;
     217
     218        if (chr_encode(ch, utf8, &offset, sizeof(utf8)) == EOK)
     219                return _write_bytes(utf8, offset, ps, written_bytes);
     220
     221        /* Invalid character. */
     222        return _write_bytes(_replacement, sizeof(_replacement) - 1, ps, written_bytes);
     223}
     224
     225/** Write n UTF-32 characters. */
     226static errno_t _write_chars(const char32_t *buf, size_t n, printf_spec_t *ps,
     227    size_t *written_bytes)
     228{
     229        for (size_t i = 0; i < n; i++)
     230                TRY(_write_uchar(buf[i], ps, written_bytes));
     231
     232        return EOK;
     233}
     234
     235static errno_t _write_char(char c, printf_spec_t *ps, size_t *written_bytes)
     236{
     237        return _write_bytes(&c, 1, ps, written_bytes);
     238}
     239
     240static errno_t _write_spaces(size_t n, printf_spec_t *ps, size_t *written_bytes)
     241{
     242        size_t max_spaces = sizeof(_spaces) - 1;
     243
     244        while (n > max_spaces) {
     245                TRY(_write_bytes(_spaces, max_spaces, ps, written_bytes));
     246                n -= max_spaces;
     247        }
     248
     249        return _write_bytes(_spaces, n, ps, written_bytes);
     250}
     251
     252static errno_t _write_zeros(size_t n, printf_spec_t *ps, size_t *written_bytes)
     253{
     254        size_t max_zeros = sizeof(_zeros) - 1;
     255
     256        while (n > max_zeros) {
     257                TRY(_write_bytes(_zeros, max_zeros, ps, written_bytes));
     258                n -= max_zeros;
     259        }
     260
     261        return _write_bytes(_zeros, n, ps, written_bytes);
    211262}
    212263
     
    216267 * @param width Width modifier.
    217268 * @param flags Flags that change the way the character is printed.
    218  *
    219  * @return Number of characters printed, negative value on failure.
    220  *
    221  */
    222 static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
    223 {
    224         size_t counter = 0;
    225         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    226                 while (--width > 0) {
    227                         /*
    228                          * One space is consumed by the character itself, hence
    229                          * the predecrement.
    230                          */
    231                         if (printf_putchar(' ', ps) > 0)
    232                                 counter++;
    233                 }
    234         }
    235 
    236         if (printf_putchar(ch, ps) > 0)
    237                 counter++;
    238 
    239         while (--width > 0) {
    240                 /*
    241                  * One space is consumed by the character itself, hence
    242                  * the predecrement.
    243                  */
    244                 if (printf_putchar(' ', ps) > 0)
    245                         counter++;
    246         }
    247 
    248         return (int) (counter);
     269 */
     270static errno_t _format_char(const char c, size_t width, uint32_t flags,
     271    printf_spec_t *ps, size_t *written_bytes)
     272{
     273        size_t bytes = 1;
     274
     275        if (width <= bytes)
     276                return _write_char(c, ps, written_bytes);
     277
     278        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     279                TRY(_write_char(c, ps, written_bytes));
     280                TRY(_write_spaces(width - bytes, ps, written_bytes));
     281        } else {
     282                TRY(_write_spaces(width - bytes, ps, written_bytes));
     283                TRY(_write_char(c, ps, written_bytes));
     284        }
     285
     286        return EOK;
    249287}
    250288
     
    254292 * @param width Width modifier.
    255293 * @param flags Flags that change the way the character is printed.
    256  *
    257  * @return Number of characters printed, negative value on failure.
    258  *
    259  */
    260 static int print_wchar(const char32_t ch, int width, uint32_t flags, printf_spec_t *ps)
    261 {
    262         size_t counter = 0;
    263         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    264                 while (--width > 0) {
    265                         /*
    266                          * One space is consumed by the character itself, hence
    267                          * the predecrement.
    268                          */
    269                         if (printf_putchar(' ', ps) > 0)
    270                                 counter++;
    271                 }
    272         }
    273 
    274         if (printf_putuchar(ch, ps) > 0)
    275                 counter++;
    276 
    277         while (--width > 0) {
    278                 /*
    279                  * One space is consumed by the character itself, hence
    280                  * the predecrement.
    281                  */
    282                 if (printf_putchar(' ', ps) > 0)
    283                         counter++;
    284         }
    285 
    286         return (int) (counter);
     294 */
     295static errno_t _format_uchar(const char32_t ch, size_t width, uint32_t flags,
     296    printf_spec_t *ps, size_t *written_bytes)
     297{
     298        /*
     299         * All widths in printf() are specified in bytes. It might seem nonsensical
     300         * with unicode text, but that's the way the function is defined. The width
     301     * is barely useful if you want column alignment in terminal, but keep in
     302     * mind that counting code points is only marginally better for that.
     303     * Characters can span more than one unicode code point, even in languages
     304     * based on latin alphabet, and a single unicode code point can occupy two
     305     * spaces in east asian scripts.
     306     *
     307     * What the width can actually be useful for is padding, when you need the
     308     * output to fill an exact number of bytes in a file. That use would break
     309     * if we did our own thing here.
     310     */
     311
     312    size_t bytes = _utf8_bytes(ch);
     313
     314        if (width <= bytes)
     315                return _write_uchar(ch, ps, written_bytes);
     316
     317        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     318                TRY(_write_uchar(ch, ps, written_bytes));
     319                TRY(_write_spaces(width - bytes, ps, written_bytes));
     320        } else {
     321                TRY(_write_spaces(width - bytes, ps, written_bytes));
     322                TRY(_write_uchar(ch, ps, written_bytes));
     323        }
     324
     325        return EOK;
    287326}
    288327
     
    293332 * @param precision Precision modifier.
    294333 * @param flags     Flags that modify the way the string is printed.
    295  *
    296  * @return Number of characters printed, negative value on failure.
    297  */
    298 static int print_str(char *str, int width, unsigned int precision,
    299     uint32_t flags, printf_spec_t *ps)
     334 */
     335static errno_t _format_cstr(const char *str, size_t width, int precision,
     336    uint32_t flags, printf_spec_t *ps, size_t *written_bytes)
    300337{
    301338        if (str == NULL)
    302                 return printf_putstr(nullstr, ps);
    303 
    304         size_t strw = str_length(str);
    305 
    306         /* Precision unspecified - print everything. */
    307         if ((precision == 0) || (precision > strw))
    308                 precision = strw;
    309 
    310         /* Left padding */
    311         size_t counter = 0;
    312         width -= precision;
    313         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    314                 while (width-- > 0) {
    315                         if (printf_putchar(' ', ps) == 1)
    316                                 counter++;
    317                 }
    318         }
    319 
    320         /* Part of @a str fitting into the alloted space. */
    321         int retval;
    322         size_t size = str_lsize(str, precision);
    323         if ((retval = printf_putnchars(str, size, ps)) < 0)
    324                 return -counter;
    325 
    326         counter += retval;
    327 
    328         /* Right padding */
    329         while (width-- > 0) {
    330                 if (printf_putchar(' ', ps) == 1)
    331                         counter++;
    332         }
    333 
    334         return ((int) counter);
    335 
     339                str = _nullstr;
     340
     341        /* Negative precision == unspecified. */
     342        size_t max_bytes = (precision < 0) ? SIZE_MAX : (size_t) precision;
     343        size_t bytes = str_nsize(str, max_bytes);
     344
     345        if (width <= bytes)
     346                return _write_bytes(str, bytes, ps, written_bytes);
     347
     348        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     349                TRY(_write_bytes(str, bytes, ps, written_bytes));
     350                TRY(_write_spaces(width - bytes, ps, written_bytes));
     351        } else {
     352                TRY(_write_spaces(width - bytes, ps, written_bytes));
     353                TRY(_write_bytes(str, bytes, ps, written_bytes));
     354        }
     355
     356        return EOK;
    336357}
    337358
     
    342363 * @param precision Precision modifier.
    343364 * @param flags     Flags that modify the way the string is printed.
    344  *
    345  * @return Number of wide characters printed, negative value on failure.
    346  */
    347 static int print_wstr(char32_t *str, int width, unsigned int precision,
    348     uint32_t flags, printf_spec_t *ps)
    349 {
    350         if (str == NULL)
    351                 return printf_putstr(nullstr, ps);
    352 
    353         size_t strw = wstr_length(str);
    354 
    355         /* Precision not specified - print everything. */
    356         if ((precision == 0) || (precision > strw))
    357                 precision = strw;
    358 
    359         /* Left padding */
    360         size_t counter = 0;
    361         width -= precision;
    362         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    363                 while (width-- > 0) {
    364                         if (printf_putchar(' ', ps) == 1)
    365                                 counter++;
    366                 }
    367         }
    368 
    369         /* Part of @a wstr fitting into the alloted space. */
    370         int retval;
    371         size_t size = wstr_lsize(str, precision);
    372         if ((retval = printf_wputnchars(str, size, ps)) < 0)
    373                 return -counter;
    374 
    375         counter += retval;
    376 
    377         /* Right padding */
    378         while (width-- > 0) {
    379                 if (printf_putchar(' ', ps) == 1)
    380                         counter++;
    381         }
    382 
    383         return ((int) counter);
     365 */
     366static errno_t _format_wstr(char32_t *str, size_t width, int precision,
     367    uint32_t flags, printf_spec_t *ps, size_t *written_bytes)
     368{
     369        if (!str)
     370                return _format_cstr(_nullstr, width, precision, flags, ps, written_bytes);
     371
     372        /* Width and precision are always byte-based. See _format_uchar() */
     373        /* Negative precision == unspecified. */
     374        size_t max_bytes = (precision < 0) ? SIZE_MAX : (size_t) precision;
     375
     376        size_t len;
     377        size_t bytes = _utf8_wstr_bytes_len(str, max_bytes, &len);
     378
     379        if (width <= bytes)
     380                return _write_chars(str, len, ps, written_bytes);
     381
     382        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     383                TRY(_write_chars(str, len, ps, written_bytes));
     384                TRY(_write_spaces(width - bytes, ps, written_bytes));
     385        } else {
     386                TRY(_write_spaces(width - bytes, ps, written_bytes));
     387                TRY(_write_chars(str, len, ps, written_bytes));
     388        }
     389
     390        return EOK;
     391}
     392
     393static char _sign(uint32_t flags)
     394{
     395        if (!(flags & __PRINTF_FLAG_SIGNED))
     396                return 0;
     397
     398        if (flags & __PRINTF_FLAG_NEGATIVE)
     399                return '-';
     400
     401        if (flags & __PRINTF_FLAG_SHOWPLUS)
     402                return '+';
     403
     404        if (flags & __PRINTF_FLAG_SPACESIGN)
     405                return ' ';
     406
     407        return 0;
    384408}
    385409
     
    393417 * @param base      Base to print the number in (must be between 2 and 16).
    394418 * @param flags     Flags that modify the way the number is printed.
    395  *
    396  * @return Number of characters printed.
    397  *
    398  */
    399 static int print_number(uint64_t num, int width, int precision, int base,
    400     uint32_t flags, printf_spec_t *ps)
    401 {
    402         /* Precision not specified. */
    403         if (precision < 0) {
    404                 precision = 0;
    405         }
    406 
    407         const char *digits;
    408         if (flags & __PRINTF_FLAG_BIGCHARS)
    409                 digits = digits_big;
    410         else
    411                 digits = digits_small;
    412 
    413         char data[PRINT_NUMBER_BUFFER_SIZE];
    414         char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
    415 
    416         /* Size of number with all prefixes and signs */
    417         int size = 0;
    418 
    419         /* Put zero at end of string */
    420         *ptr-- = 0;
    421 
    422         if (num == 0) {
    423                 *ptr-- = '0';
    424                 size++;
    425         } else {
    426                 do {
    427                         *ptr-- = digits[num % base];
    428                         size++;
    429                 } while (num /= base);
    430         }
    431 
    432         /* Size of plain number */
    433         int number_size = size;
    434 
    435         /*
    436          * Collect the sum of all prefixes/signs/etc. to calculate padding and
    437          * leading zeroes.
    438          */
    439         if (flags & __PRINTF_FLAG_PREFIX) {
    440                 switch (base) {
    441                 case 2:
    442                         /* Binary formating is not standard, but usefull */
    443                         size += 2;
    444                         break;
    445                 case 8:
    446                         size++;
    447                         break;
    448                 case 16:
    449                         size += 2;
    450                         break;
    451                 }
    452         }
    453 
    454         char sgn = 0;
    455         if (flags & __PRINTF_FLAG_SIGNED) {
    456                 if (flags & __PRINTF_FLAG_NEGATIVE) {
    457                         sgn = '-';
    458                         size++;
    459                 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
    460                         sgn = '+';
    461                         size++;
    462                 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
    463                         sgn = ' ';
    464                         size++;
    465                 }
    466         }
    467 
    468         if (flags & __PRINTF_FLAG_LEFTALIGNED)
    469                 flags &= ~__PRINTF_FLAG_ZEROPADDED;
    470 
    471         /*
    472          * If the number is left-aligned or precision is specified then
    473          * padding with zeros is ignored.
    474          */
    475         if (flags & __PRINTF_FLAG_ZEROPADDED) {
    476                 if ((precision == 0) && (width > size))
    477                         precision = width - size + number_size;
    478         }
    479 
    480         /* Print leading spaces */
    481         if (number_size > precision) {
    482                 /* Print the whole number, not only a part */
    483                 precision = number_size;
    484         }
    485 
    486         width -= precision + size - number_size;
    487         size_t counter = 0;
    488 
    489         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    490                 while (width-- > 0) {
    491                         if (printf_putchar(' ', ps) == 1)
    492                                 counter++;
    493                 }
    494         }
    495 
    496         /* Print sign */
    497         if (sgn) {
    498                 if (printf_putchar(sgn, ps) == 1)
    499                         counter++;
    500         }
    501 
    502         /* Print prefix */
    503         if (flags & __PRINTF_FLAG_PREFIX) {
    504                 switch (base) {
    505                 case 2:
    506                         /* Binary formating is not standard, but useful */
    507                         if (printf_putchar('0', ps) == 1)
    508                                 counter++;
    509                         if (flags & __PRINTF_FLAG_BIGCHARS) {
    510                                 if (printf_putchar('B', ps) == 1)
    511                                         counter++;
    512                         } else {
    513                                 if (printf_putchar('b', ps) == 1)
    514                                         counter++;
    515                         }
    516                         break;
    517                 case 8:
    518                         if (printf_putchar('o', ps) == 1)
    519                                 counter++;
    520                         break;
    521                 case 16:
    522                         if (printf_putchar('0', ps) == 1)
    523                                 counter++;
    524                         if (flags & __PRINTF_FLAG_BIGCHARS) {
    525                                 if (printf_putchar('X', ps) == 1)
    526                                         counter++;
    527                         } else {
    528                                 if (printf_putchar('x', ps) == 1)
    529                                         counter++;
    530                         }
    531                         break;
    532                 }
    533         }
    534 
    535         /* Print leading zeroes */
    536         precision -= number_size;
    537         while (precision-- > 0) {
    538                 if (printf_putchar('0', ps) == 1)
    539                         counter++;
    540         }
    541 
    542         /* Print the number itself */
    543         int retval;
    544         if ((retval = printf_putstr(++ptr, ps)) > 0)
    545                 counter += retval;
    546 
    547         /* Print trailing spaces */
    548 
    549         while (width-- > 0) {
    550                 if (printf_putchar(' ', ps) == 1)
    551                         counter++;
    552         }
    553 
    554         return ((int) counter);
     419 */
     420static errno_t _format_number(uint64_t num, size_t width, int precision, int base,
     421    uint32_t flags, printf_spec_t *ps, size_t *written_bytes)
     422{
     423        assert(base >= 2 && base <= 16);
     424
     425        /* Default precision for numeric output is 1. */
     426        size_t min_digits = (precision < 0) ? 1 : precision;
     427
     428        bool bigchars = flags & __PRINTF_FLAG_BIGCHARS;
     429        bool prefix = flags & __PRINTF_FLAG_PREFIX;
     430        bool left_aligned = flags & __PRINTF_FLAG_LEFTALIGNED;
     431        bool zero_padded = flags & __PRINTF_FLAG_ZEROPADDED;
     432
     433        const char *digits = bigchars ? _digits_big : _digits_small;
     434
     435        char buffer[PRINT_NUMBER_BUFFER_SIZE];
     436        char *end = &buffer[PRINT_NUMBER_BUFFER_SIZE];
     437
     438        /* Write number to the buffer. */
     439        int offset = 0;
     440        while (num > 0) {
     441                end[--offset] = digits[num % base];
     442                num /= base;
     443        }
     444
     445        char *number = &end[offset];
     446        size_t number_len = end - number;
     447        char sign = _sign(flags);
     448
     449        if (left_aligned) {
     450                /* Space padded right-aligned. */
     451                size_t real_size = max(number_len, min_digits);
     452
     453                if (sign) {
     454                        TRY(_write_char(sign, ps, written_bytes));
     455                        real_size++;
     456                }
     457
     458                if (prefix && base == 2 && number_len > 0) {
     459                        TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes));
     460                        real_size += 2;
     461                }
     462
     463                if (prefix && base == 16 && number_len > 0) {
     464                        TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes));
     465                        real_size += 2;
     466                }
     467
     468                if (min_digits > number_len) {
     469                        TRY(_write_zeros(min_digits - number_len, ps, written_bytes));
     470                } else if (prefix && base == 8) {
     471                        TRY(_write_zeros(1, ps, written_bytes));
     472                        real_size++;
     473                }
     474
     475                TRY(_write_bytes(number, number_len, ps, written_bytes));
     476
     477                if (width > real_size)
     478                        TRY(_write_spaces(width - real_size, ps, written_bytes));
     479
     480                return EOK;
     481        }
     482
     483        /* Zero padded number (ignored when left aligned or if precision is specified). */
     484        if (precision < 0 && zero_padded) {
     485                size_t real_size = number_len;
     486
     487                if (sign) {
     488                        TRY(_write_char(sign, ps, written_bytes));
     489                        real_size++;
     490                }
     491
     492                if (prefix && base == 2 && number_len > 0) {
     493                        TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes));
     494                        real_size += 2;
     495                }
     496
     497                if (prefix && base == 16 && number_len > 0) {
     498                        TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes));
     499                        real_size += 2;
     500                }
     501
     502                if (width > real_size)
     503                        TRY(_write_zeros(width - real_size, ps, written_bytes));
     504                else if (number_len == 0 || (prefix && base == 8))
     505                        TRY(_write_char('0', ps, written_bytes));
     506
     507                return _write_bytes(number, number_len, ps, written_bytes);
     508        }
     509
     510        /* Space padded right-aligned. */
     511        size_t real_size = max(number_len, min_digits);
     512        if (sign)
     513                real_size++;
     514
     515        if (prefix && (base == 2 || base == 16) && number_len > 0)
     516                real_size += 2;
     517
     518        if (prefix && base == 8 && number_len >= min_digits)
     519                real_size += 1;
     520
     521        if (width > real_size)
     522                TRY(_write_spaces(width - real_size, ps, written_bytes));
     523
     524        if (sign)
     525                TRY(_write_char(sign, ps, written_bytes));
     526
     527        if (prefix && base == 2 && number_len > 0)
     528                TRY(_write_bytes(bigchars ? "0B" : "0b", 2, ps, written_bytes));
     529
     530        if (prefix && base == 16 && number_len > 0)
     531                TRY(_write_bytes(bigchars ? "0X" : "0x", 2, ps, written_bytes));
     532
     533        if (min_digits > number_len)
     534                TRY(_write_zeros(min_digits - number_len, ps, written_bytes));
     535        else if (prefix && base == 8)
     536                TRY(_write_char('0', ps, written_bytes));
     537
     538        return _write_bytes(number, number_len, ps, written_bytes);
    555539}
    556540
     
    570554
    571555/** Returns the sign character or 0 if no sign should be printed. */
    572 static int get_sign_char(bool negative, uint32_t flags)
     556static char _get_sign_char(bool negative, uint32_t flags)
    573557{
    574558        if (negative) {
     
    583567}
    584568
    585 /** Prints count times character ch. */
    586 static int print_padding(char ch, int count, printf_spec_t *ps)
    587 {
    588         for (int i = 0; i < count; ++i) {
    589                 if (ps->str_write(&ch, 1, ps->data) < 0) {
    590                         return -1;
    591                 }
    592         }
    593 
    594         return count;
    595 }
    596 
    597569/** Prints a special double (ie NaN, infinity) padded to width characters. */
    598 static int print_special(ieee_double_t val, int width, uint32_t flags,
    599     printf_spec_t *ps)
     570static errno_t _format_special(ieee_double_t val, int width, uint32_t flags,
     571    printf_spec_t *ps, size_t *written_bytes)
    600572{
    601573        assert(val.is_special);
    602574
    603         char sign = get_sign_char(val.is_negative, flags);
     575        char sign = _get_sign_char(val.is_negative, flags);
    604576
    605577        const int str_len = 3;
     
    614586        int padding_len = max(0, width - ((sign ? 1 : 0) + str_len));
    615587
    616         int counter = 0;
    617         int ret;
    618 
    619588        /* Leading padding. */
    620         if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    621                 if ((ret = print_padding(' ', padding_len, ps)) < 0)
    622                         return -1;
    623 
    624                 counter += ret;
    625         }
    626 
    627         if (sign) {
    628                 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
    629                         return -1;
    630 
    631                 counter += ret;
    632         }
    633 
    634         if ((ret = ps->str_write(str, str_len, ps->data)) < 0)
    635                 return -1;
    636 
    637         counter += ret;
     589        if (!(flags & __PRINTF_FLAG_LEFTALIGNED))
     590                TRY(_write_spaces(padding_len, ps, written_bytes));
     591
     592        if (sign)
     593                TRY(_write_char(sign, ps, written_bytes));
     594
     595        TRY(_write_bytes(str, str_len, ps, written_bytes));
    638596
    639597        /* Trailing padding. */
    640         if (flags & __PRINTF_FLAG_LEFTALIGNED) {
    641                 if ((ret = print_padding(' ', padding_len, ps)) < 0)
    642                         return -1;
    643 
    644                 counter += ret;
    645         }
    646 
    647         return counter;
     598        if (flags & __PRINTF_FLAG_LEFTALIGNED)
     599                TRY(_write_spaces(padding_len, ps, written_bytes));
     600
     601        return EOK;
    648602}
    649603
    650604/** Trims trailing zeros but leaves a single "0" intact. */
    651 static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)
     605static void _fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)
    652606{
    653607        /* Cut the zero off by adjusting the exponent. */
     
    659613
    660614/** Textually round up the last digit thereby eliminating it. */
    661 static void fp_round_up(char *buf, int *len, int *dec_exp)
     615static void _fp_round_up(char *buf, int *len, int *dec_exp)
    662616{
    663617        assert(1 <= *len);
     
    703657 *  to the %f specifier.
    704658 */
    705 static int print_double_str_fixed(double_str_t *val_str, int precision, int width,
    706     uint32_t flags, printf_spec_t *ps)
     659static errno_t _format_double_str_fixed(double_str_t *val_str, int precision, int width,
     660    uint32_t flags, printf_spec_t *ps, size_t *written_bytes)
    707661{
    708662        int len = val_str->len;
     
    717671        int int_len = max(1, len + dec_exp);
    718672
    719         char sign = get_sign_char(val_str->neg, flags);
     673        char sign = _get_sign_char(val_str->neg, flags);
    720674
    721675        /* Fractional portion lengths. */
     
    726680        char *buf_frac = buf + len - signif_frac_figs;
    727681
    728         if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     682        if (flags & __PRINTF_FLAG_NOFRACZEROS)
    729683                trailing_frac_zeros = 0;
    730         }
    731684
    732685        int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros;
     
    738691
    739692        int padding_len = max(0, width - num_len);
    740         int ret = 0;
    741         int counter = 0;
    742693
    743694        /* Leading padding and sign. */
    744695
    745         if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
    746                 if ((ret = print_padding(' ', padding_len, ps)) < 0)
    747                         return -1;
    748 
    749                 counter += ret;
    750         }
    751 
    752         if (sign) {
    753                 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
    754                         return -1;
    755 
    756                 counter += ret;
    757         }
    758 
    759         if (flags & __PRINTF_FLAG_ZEROPADDED) {
    760                 if ((ret = print_padding('0', padding_len, ps)) < 0)
    761                         return -1;
    762 
    763                 counter += ret;
    764         }
     696        if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED)))
     697                TRY(_write_spaces(padding_len, ps, written_bytes));
     698
     699        if (sign)
     700                TRY(_write_char(sign, ps, written_bytes));
     701
     702        if (flags & __PRINTF_FLAG_ZEROPADDED)
     703                TRY(_write_zeros(padding_len, ps, written_bytes));
    765704
    766705        /* Print the intergral part of the buffer. */
     
    769708
    770709        if (0 < buf_int_len) {
    771                 if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0)
    772                         return -1;
    773 
    774                 counter += ret;
     710                TRY(_write_bytes(buf, buf_int_len, ps, written_bytes));
    775711
    776712                /* Print trailing zeros of the integral part of the number. */
    777                 if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0)
    778                         return -1;
     713                TRY(_write_zeros(int_len - buf_int_len, ps, written_bytes));
    779714        } else {
    780715                /* Single leading integer 0. */
    781                 char ch = '0';
    782                 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
    783                         return -1;
    784         }
    785 
    786         counter += ret;
     716                TRY(_write_char('0', ps, written_bytes));
     717        }
    787718
    788719        /* Print the decimal point and the fractional part. */
    789720        if (has_decimal_pt) {
    790                 char ch = '.';
    791 
    792                 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
    793                         return -1;
    794 
    795                 counter += ret;
     721                TRY(_write_char('.', ps, written_bytes));
    796722
    797723                /* Print leading zeros of the fractional part of the number. */
    798                 if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0)
    799                         return -1;
    800 
    801                 counter += ret;
     724                TRY(_write_zeros(leading_frac_zeros, ps, written_bytes));
    802725
    803726                /* Print significant digits of the fractional part of the number. */
    804                 if (0 < signif_frac_figs) {
    805                         if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0)
    806                                 return -1;
    807 
    808                         counter += ret;
    809                 }
     727                if (0 < signif_frac_figs)
     728                        TRY(_write_bytes(buf_frac, signif_frac_figs, ps, written_bytes));
    810729
    811730                /* Print trailing zeros of the fractional part of the number. */
    812                 if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
    813                         return -1;
    814 
    815                 counter += ret;
     731                TRY(_write_zeros(trailing_frac_zeros, ps, written_bytes));
    816732        }
    817733
    818734        /* Trailing padding. */
    819         if (flags & __PRINTF_FLAG_LEFTALIGNED) {
    820                 if ((ret = print_padding(' ', padding_len, ps)) < 0)
    821                         return -1;
    822 
    823                 counter += ret;
    824         }
    825 
    826         return counter;
     735        if (flags & __PRINTF_FLAG_LEFTALIGNED)
     736                TRY(_write_spaces(padding_len, ps, written_bytes));
     737
     738        return EOK;
    827739}
    828740
     
    837749 * @param flags Printf flags.
    838750 * @param ps    Printing functions.
    839  *
    840  * @return The number of characters printed; negative on failure.
    841  */
    842 static int print_double_fixed(double g, int precision, int width, uint32_t flags,
    843     printf_spec_t *ps)
     751 */
     752static errno_t _format_double_fixed(double g, int precision, int width,
     753        uint32_t flags, printf_spec_t *ps, size_t *written_bytes)
    844754{
    845755        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     
    854764
    855765        if (val.is_special) {
    856                 return print_special(val, width, flags, ps);
     766                return _format_special(val, width, flags, ps, written_bytes);
    857767        }
    858768
     
    877787                 * digit is definitely inaccurate so also round to get rid of it.
    878788                 */
    879                 fp_round_up(buf, &val_str.len, &val_str.dec_exp);
     789                _fp_round_up(buf, &val_str.len, &val_str.dec_exp);
    880790
    881791                /* Rounding could have introduced trailing zeros. */
    882792                if (flags & __PRINTF_FLAG_NOFRACZEROS) {
    883                         fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
     793                        _fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
    884794                }
    885795        } else {
     
    891801        }
    892802
    893         return print_double_str_fixed(&val_str, precision, width, flags, ps);
     803        return _format_double_str_fixed(&val_str, precision, width, flags, ps, written_bytes);
    894804}
    895805
    896806/** Prints the decimal exponent part of a %e specifier formatted number. */
    897 static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps)
    898 {
    899         int counter = 0;
    900         int ret;
    901 
     807static errno_t _format_exponent(int exp_val, uint32_t flags, printf_spec_t *ps,
     808    size_t *written_bytes)
     809{
    902810        char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e';
    903 
    904         if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0)
    905                 return -1;
    906 
    907         counter += ret;
     811        TRY(_write_char(exp_ch, ps, written_bytes));
    908812
    909813        char exp_sign = (exp_val < 0) ? '-' : '+';
    910 
    911         if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0)
    912                 return -1;
    913 
    914         counter += ret;
     814        TRY(_write_char(exp_sign, ps, written_bytes));
    915815
    916816        /* Print the exponent. */
     
    926826        const char *exp_str_start = &exp_str[3] - exp_len;
    927827
    928         if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0)
    929                 return -1;
    930 
    931         counter += ret;
    932 
    933         return counter;
     828        return _write_bytes(exp_str_start, exp_len, ps, written_bytes);
    934829}
    935830
     
    937832 *  to the %e specifier.
    938833 */
    939 static int print_double_str_scient(double_str_t *val_str, int precision,
    940     int width, uint32_t flags, printf_spec_t *ps)
     834static errno_t _format_double_str_scient(double_str_t *val_str, int precision,
     835    int width, uint32_t flags, printf_spec_t *ps, size_t *written_bytes)
    941836{
    942837        int len = val_str->len;
     
    946841        assert(0 < len);
    947842
    948         char sign = get_sign_char(val_str->neg, flags);
     843        char sign = _get_sign_char(val_str->neg, flags);
    949844        bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT);
    950845        int dec_pt_len = has_decimal_pt ? 1 : 0;
     
    968863
    969864        int padding_len = max(0, width - num_len);
    970         int ret = 0;
    971         int counter = 0;
    972 
    973         if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
    974                 if ((ret = print_padding(' ', padding_len, ps)) < 0)
    975                         return -1;
    976 
    977                 counter += ret;
    978         }
    979 
    980         if (sign) {
    981                 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
    982                         return -1;
    983 
    984                 counter += ret;
    985         }
    986 
    987         if (flags & __PRINTF_FLAG_ZEROPADDED) {
    988                 if ((ret = print_padding('0', padding_len, ps)) < 0)
    989                         return -1;
    990 
    991                 counter += ret;
    992         }
     865
     866        if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED)))
     867                TRY(_write_spaces(padding_len, ps, written_bytes));
     868
     869        if (sign)
     870                TRY(_write_char(sign, ps, written_bytes));
     871
     872        if (flags & __PRINTF_FLAG_ZEROPADDED)
     873                TRY(_write_zeros(padding_len, ps, written_bytes));
    993874
    994875        /* Single leading integer. */
    995         if ((ret = ps->str_write(buf, 1, ps->data)) < 0)
    996                 return -1;
    997 
    998         counter += ret;
     876        TRY(_write_char(buf[0], ps, written_bytes));
    999877
    1000878        /* Print the decimal point and the fractional part. */
    1001879        if (has_decimal_pt) {
    1002                 char ch = '.';
    1003 
    1004                 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
    1005                         return -1;
    1006 
    1007                 counter += ret;
     880                TRY(_write_char('.', ps, written_bytes));
    1008881
    1009882                /* Print significant digits of the fractional part of the number. */
    1010                 if (0 < signif_frac_figs) {
    1011                         if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0)
    1012                                 return -1;
    1013 
    1014                         counter += ret;
    1015                 }
     883                if (0 < signif_frac_figs)
     884                        TRY(_write_bytes(buf + 1, signif_frac_figs, ps, written_bytes));
    1016885
    1017886                /* Print trailing zeros of the fractional part of the number. */
    1018                 if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
    1019                         return -1;
    1020 
    1021                 counter += ret;
     887                TRY(_write_zeros(trailing_frac_zeros, ps, written_bytes));
    1022888        }
    1023889
    1024890        /* Print the exponent. */
    1025         if ((ret = print_exponent(exp_val, flags, ps)) < 0)
    1026                 return -1;
    1027 
    1028         counter += ret;
    1029 
    1030         if (flags & __PRINTF_FLAG_LEFTALIGNED) {
    1031                 if ((ret = print_padding(' ', padding_len, ps)) < 0)
    1032                         return -1;
    1033 
    1034                 counter += ret;
    1035         }
    1036 
    1037         return counter;
     891        TRY(_format_exponent(exp_val, flags, ps, written_bytes));
     892
     893        if (flags & __PRINTF_FLAG_LEFTALIGNED)
     894                TRY(_write_spaces(padding_len, ps, written_bytes));
     895
     896        return EOK;
    1038897}
    1039898
     
    1057916 * @param flags Printf flags.
    1058917 * @param ps    Printing functions.
    1059  *
    1060  * @return The number of characters printed; negative on failure.
    1061  */
    1062 static int print_double_scientific(double g, int precision, int width,
    1063     uint32_t flags, printf_spec_t *ps)
    1064 {
    1065         if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     918 */
     919static errno_t _format_double_scientific(double g, int precision, int width,
     920    uint32_t flags, printf_spec_t *ps, size_t *written_bytes)
     921{
     922        if (flags & __PRINTF_FLAG_LEFTALIGNED)
    1066923                flags &= ~__PRINTF_FLAG_ZEROPADDED;
    1067         }
    1068924
    1069925        ieee_double_t val = extract_ieee_double(g);
    1070926
    1071         if (val.is_special) {
    1072                 return print_special(val, width, flags, ps);
    1073         }
     927        if (val.is_special)
     928                return _format_special(val, width, flags, ps, written_bytes);
    1074929
    1075930        char buf[MAX_DOUBLE_STR_BUF_SIZE];
     
    1094949                 * digit is definitely inaccurate so also round to get rid of it.
    1095950                 */
    1096                 fp_round_up(buf, &val_str.len, &val_str.dec_exp);
     951                _fp_round_up(buf, &val_str.len, &val_str.dec_exp);
    1097952
    1098953                /* Rounding could have introduced trailing zeros. */
    1099954                if (flags & __PRINTF_FLAG_NOFRACZEROS) {
    1100                         fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
     955                        _fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
    1101956                }
    1102957        } else {
     
    1108963        }
    1109964
    1110         return print_double_str_scient(&val_str, precision, width, flags, ps);
     965        return _format_double_str_scient(&val_str, precision, width, flags, ps, written_bytes);
    1111966}
    1112967
     
    1126981 * @return The number of characters printed; negative on failure.
    1127982 */
    1128 static int print_double_generic(double g, int precision, int width,
    1129     uint32_t flags, printf_spec_t *ps)
     983static errno_t _format_double_generic(double g, int precision, int width,
     984    uint32_t flags, printf_spec_t *ps, size_t *written_bytes)
    1130985{
    1131986        ieee_double_t val = extract_ieee_double(g);
    1132987
    1133         if (val.is_special) {
    1134                 return print_special(val, width, flags, ps);
    1135         }
     988        if (val.is_special)
     989                return _format_special(val, width, flags, ps, written_bytes);
    1136990
    1137991        char buf[MAX_DOUBLE_STR_BUF_SIZE];
     
    11531007                if (-4 <= dec_exp && dec_exp < precision) {
    11541008                        precision = precision - (dec_exp + 1);
    1155                         return print_double_fixed(g, precision, width,
    1156                             flags | __PRINTF_FLAG_NOFRACZEROS, ps);
     1009                        return _format_double_fixed(g, precision, width,
     1010                            flags | __PRINTF_FLAG_NOFRACZEROS, ps, written_bytes);
    11571011                } else {
    11581012                        --precision;
    1159                         return print_double_scientific(g, precision, width,
    1160                             flags | __PRINTF_FLAG_NOFRACZEROS, ps);
     1013                        return _format_double_scientific(g, precision, width,
     1014                            flags | __PRINTF_FLAG_NOFRACZEROS, ps, written_bytes);
    11611015                }
    11621016        } else {
     
    11821036                        /* Precision needed for the last significant digit. */
    11831037                        precision = max(0, -val_str.dec_exp);
    1184                         return print_double_str_fixed(&val_str, precision, width, flags, ps);
     1038                        return _format_double_str_fixed(&val_str, precision, width, flags, ps, written_bytes);
    11851039                } else {
    11861040                        /* Use all produced digits. */
    11871041                        precision = val_str.len - 1;
    1188                         return print_double_str_scient(&val_str, precision, width, flags, ps);
     1042                        return _format_double_str_scient(&val_str, precision, width, flags, ps, written_bytes);
    11891043                }
    11901044        }
     
    12071061 * @param flags Printf flags.
    12081062 * @param ps    Printing functions.
    1209  *
    1210  * @return The number of characters printed; negative on failure.
    1211  */
    1212 static int print_double(double g, char spec, int precision, int width,
    1213     uint32_t flags, printf_spec_t *ps)
     1063 */
     1064static errno_t _format_double(double g, char spec, int precision, int width,
     1065    uint32_t flags, printf_spec_t *ps, size_t *written_chars)
    12141066{
    12151067        switch (spec) {
     
    12191071        case 'f':
    12201072                precision = (precision < 0) ? 6 : precision;
    1221                 return print_double_fixed(g, precision, width, flags, ps);
     1073                return _format_double_fixed(g, precision, width, flags, ps, written_chars);
    12221074
    12231075        case 'E':
     
    12261078        case 'e':
    12271079                precision = (precision < 0) ? 6 : precision;
    1228                 return print_double_scientific(g, precision, width, flags, ps);
     1080                return _format_double_scientific(g, precision, width, flags, ps, written_chars);
    12291081
    12301082        case 'G':
     
    12321084                /* Fallthrough */
    12331085        case 'g':
    1234                 return print_double_generic(g, precision, width, flags, ps);
     1086                return _format_double_generic(g, precision, width, flags, ps, written_chars);
    12351087
    12361088        default:
     
    12411093
    12421094#endif
     1095
     1096static const char *_strchrnul(const char *s, int c)
     1097{
     1098        while (*s != c && *s != 0)
     1099                s++;
     1100        return s;
     1101}
     1102
     1103/** Read a sequence of digits from the format string as a number.
     1104 * If the number has too many digits to fit in int, returns INT_MAX.
     1105 */
     1106static int _read_num(const char *fmt, size_t *i)
     1107{
     1108        const char *s;
     1109        unsigned n = 0;
     1110
     1111        for (s = &fmt[*i]; isdigit(*s); s++) {
     1112                unsigned digit = (*s - '0');
     1113
     1114                /* Check for overflow */
     1115                if (n > INT_MAX / 10 || n * 10 > INT_MAX - digit) {
     1116                        n = INT_MAX;
     1117                        while (isdigit(*s))
     1118                                s++;
     1119                        break;
     1120                }
     1121
     1122                n = n * 10 + digit;
     1123        }
     1124
     1125        *i = s - fmt;
     1126        return n;
     1127}
     1128
     1129static uint32_t _parse_flags(const char *fmt, size_t *i)
     1130{
     1131        uint32_t flags = 0;
     1132
     1133        while (true) {
     1134                switch (fmt[(*i)++]) {
     1135                case '#':
     1136                        flags |= __PRINTF_FLAG_PREFIX;
     1137                        flags |= __PRINTF_FLAG_DECIMALPT;
     1138                        continue;
     1139                case '-':
     1140                        flags |= __PRINTF_FLAG_LEFTALIGNED;
     1141                        continue;
     1142                case '+':
     1143                        flags |= __PRINTF_FLAG_SHOWPLUS;
     1144                        continue;
     1145                case ' ':
     1146                        flags |= __PRINTF_FLAG_SPACESIGN;
     1147                        continue;
     1148                case '0':
     1149                        flags |= __PRINTF_FLAG_ZEROPADDED;
     1150                        continue;
     1151                }
     1152
     1153                --*i;
     1154                break;
     1155        }
     1156
     1157        return flags;
     1158}
     1159
     1160static bool _eat_char(const char *s, size_t *idx, int c)
     1161{
     1162        if (s[*idx] != c)
     1163                return false;
     1164
     1165        (*idx)++;
     1166        return true;
     1167}
     1168
     1169static qualifier_t _read_qualifier(const char *s, size_t *idx)
     1170{
     1171        switch (s[(*idx)++]) {
     1172        case 't': /* ptrdiff_t */
     1173        case 'z': /* size_t */
     1174                if (sizeof(ptrdiff_t) == sizeof(int))
     1175                        return PrintfQualifierInt;
     1176                else
     1177                        return PrintfQualifierLong;
     1178
     1179        case 'h':
     1180                if (_eat_char(s, idx, 'h'))
     1181                        return PrintfQualifierByte;
     1182                else
     1183                        return PrintfQualifierShort;
     1184
     1185        case 'l':
     1186                if (_eat_char(s, idx, 'l'))
     1187                        return PrintfQualifierLongLong;
     1188                else
     1189                        return PrintfQualifierLong;
     1190
     1191        case 'j':
     1192                return PrintfQualifierLongLong;
     1193
     1194        default:
     1195                --*idx;
     1196
     1197                /* Unspecified */
     1198                return PrintfQualifierInt;
     1199        }
     1200}
    12431201
    12441202/** Print formatted string.
     
    13331291int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
    13341292{
    1335         size_t i;        /* Index of the currently processed character from fmt */
     1293        errno_t rc = EOK;
    13361294        size_t nxt = 0;  /* Index of the next character from fmt */
    1337         size_t j = 0;    /* Index to the first not printed nonformating character */
    13381295
    13391296        size_t counter = 0;   /* Number of characters printed */
    1340         int retval;           /* Return values from nested functions */
    1341 
    1342         while (true) {
    1343                 i = nxt;
    1344                 char32_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1345 
    1346                 if (uc == 0)
    1347                         break;
    1348 
    1349                 /* Control character */
    1350                 if (uc == '%') {
    1351                         /* Print common characters if any processed */
    1352                         if (i > j) {
    1353                                 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
    1354                                         /* Error */
    1355                                         counter = -counter;
    1356                                         goto out;
    1357                                 }
    1358                                 counter += retval;
     1297
     1298        while (rc == EOK) {
     1299                /* Find the next specifier and write all the bytes before it. */
     1300                const char *s = _strchrnul(&fmt[nxt], '%');
     1301                size_t bytes = s - &fmt[nxt];
     1302                rc = _write_bytes(&fmt[nxt], bytes, ps, &counter);
     1303                if (rc != EOK)
     1304                        break;
     1305
     1306                nxt += bytes;
     1307
     1308                /* Check for end of string. */
     1309                if (_eat_char(fmt, &nxt, 0))
     1310                        break;
     1311
     1312                /* We must be at the start of a specifier. */
     1313                bool spec = _eat_char(fmt, &nxt, '%');
     1314                assert(spec);
     1315
     1316                /* Parse modifiers */
     1317                uint32_t flags = _parse_flags(fmt, &nxt);
     1318
     1319                /* Width & '*' operator */
     1320                int width = -1;
     1321                if (_eat_char(fmt, &nxt, '*')) {
     1322                        /* Get width value from argument list */
     1323                        width = va_arg(ap, int);
     1324
     1325                        if (width < 0) {
     1326                                /* Negative width sets '-' flag */
     1327                                width = (width == INT_MIN) ? INT_MAX : -width;
     1328                                flags |= __PRINTF_FLAG_LEFTALIGNED;
    13591329                        }
    1360 
    1361                         j = i;
    1362 
    1363                         /* Parse modifiers */
    1364                         uint32_t flags = 0;
    1365                         bool end = false;
    1366 
    1367                         do {
    1368                                 i = nxt;
    1369                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1370                                 switch (uc) {
    1371                                 case '#':
    1372                                         flags |= __PRINTF_FLAG_PREFIX;
    1373                                         flags |= __PRINTF_FLAG_DECIMALPT;
    1374                                         break;
    1375                                 case '-':
    1376                                         flags |= __PRINTF_FLAG_LEFTALIGNED;
    1377                                         break;
    1378                                 case '+':
    1379                                         flags |= __PRINTF_FLAG_SHOWPLUS;
    1380                                         break;
    1381                                 case ' ':
    1382                                         flags |= __PRINTF_FLAG_SPACESIGN;
    1383                                         break;
    1384                                 case '0':
    1385                                         flags |= __PRINTF_FLAG_ZEROPADDED;
    1386                                         break;
    1387                                 default:
    1388                                         end = true;
    1389                                 }
    1390                         } while (!end);
    1391 
    1392                         /* Width & '*' operator */
    1393                         int width = 0;
    1394                         if (isdigit(uc)) {
    1395                                 while (true) {
    1396                                         width *= 10;
    1397                                         width += uc - '0';
    1398 
    1399                                         i = nxt;
    1400                                         uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1401                                         if (uc == 0)
    1402                                                 break;
    1403                                         if (!isdigit(uc))
    1404                                                 break;
    1405                                 }
    1406                         } else if (uc == '*') {
    1407                                 /* Get width value from argument list */
    1408                                 i = nxt;
    1409                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1410                                 width = (int) va_arg(ap, int);
    1411                                 if (width < 0) {
    1412                                         /* Negative width sets '-' flag */
    1413                                         width *= -1;
    1414                                         flags |= __PRINTF_FLAG_LEFTALIGNED;
    1415                                 }
     1330                } else {
     1331                        width = _read_num(fmt, &nxt);
     1332                }
     1333
     1334                /* Precision and '*' operator */
     1335                int precision = -1;
     1336                if (_eat_char(fmt, &nxt, '.')) {
     1337                        if (_eat_char(fmt, &nxt, '*')) {
     1338                                /* Get precision value from the argument list */
     1339                                precision = va_arg(ap, int);
     1340
     1341                                /* Negative is treated as omitted. */
     1342                                if (precision < 0)
     1343                                        precision = -1;
     1344                        } else {
     1345                                precision = _read_num(fmt, &nxt);
    14161346                        }
    1417 
    1418                         /* Precision and '*' operator */
    1419                         int precision = -1;
    1420                         if (uc == '.') {
    1421                                 i = nxt;
    1422                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1423                                 if (isdigit(uc)) {
    1424                                         precision = 0;
    1425                                         while (true) {
    1426                                                 precision *= 10;
    1427                                                 precision += uc - '0';
    1428 
    1429                                                 i = nxt;
    1430                                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1431                                                 if (uc == 0)
    1432                                                         break;
    1433                                                 if (!isdigit(uc))
    1434                                                         break;
    1435                                         }
    1436                                 } else if (uc == '*') {
    1437                                         /* Get precision value from the argument list */
    1438                                         i = nxt;
    1439                                         uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1440                                         precision = (int) va_arg(ap, int);
    1441                                         if (precision < 0) {
    1442                                                 /* Ignore negative precision - use default instead */
    1443                                                 precision = -1;
    1444                                         }
    1445                                 }
    1446                         }
    1447 
    1448                         qualifier_t qualifier;
    1449 
    1450                         switch (uc) {
    1451                         case 't':
    1452                                 /* ptrdiff_t */
    1453                                 if (sizeof(ptrdiff_t) == sizeof(int32_t))
    1454                                         qualifier = PrintfQualifierInt;
    1455                                 else
    1456                                         qualifier = PrintfQualifierLongLong;
    1457                                 i = nxt;
    1458                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1459                                 break;
    1460                         case 'h':
    1461                                 /* Char or short */
    1462                                 qualifier = PrintfQualifierShort;
    1463                                 i = nxt;
    1464                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1465                                 if (uc == 'h') {
    1466                                         i = nxt;
    1467                                         uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1468                                         qualifier = PrintfQualifierByte;
    1469                                 }
    1470                                 break;
    1471                         case 'l':
    1472                                 /* Long or long long */
    1473                                 qualifier = PrintfQualifierLong;
    1474                                 i = nxt;
    1475                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1476                                 if (uc == 'l') {
    1477                                         i = nxt;
    1478                                         uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1479                                         qualifier = PrintfQualifierLongLong;
    1480                                 }
    1481                                 break;
    1482                         case 'z':
    1483                                 qualifier = PrintfQualifierSize;
    1484                                 i = nxt;
    1485                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1486                                 break;
    1487                         case 'j':
    1488                                 qualifier = PrintfQualifierMax;
    1489                                 i = nxt;
    1490                                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    1491                                 break;
    1492                         default:
    1493                                 /* Default type */
    1494                                 qualifier = PrintfQualifierInt;
    1495                         }
    1496 
    1497                         unsigned int base = 10;
    1498 
    1499                         switch (uc) {
    1500                                 /*
    1501                                  * String and character conversions.
    1502                                  */
    1503                         case 's':
    1504                                 precision = max(0,  precision);
    1505 
    1506                                 if (qualifier == PrintfQualifierLong)
    1507                                         retval = print_wstr(va_arg(ap, char32_t *), width, precision, flags, ps);
    1508                                 else
    1509                                         retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
    1510 
    1511                                 if (retval < 0) {
    1512                                         counter = -counter;
    1513                                         goto out;
    1514                                 }
    1515 
    1516                                 counter += retval;
    1517                                 j = nxt;
    1518                                 continue;
    1519                         case 'c':
    1520                                 if (qualifier == PrintfQualifierLong)
    1521                                         retval = print_wchar(va_arg(ap, wint_t), width, flags, ps);
    1522                                 else
    1523                                         retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
    1524 
    1525                                 if (retval < 0) {
    1526                                         counter = -counter;
    1527                                         goto out;
    1528                                 }
    1529 
    1530                                 counter += retval;
    1531                                 j = nxt;
    1532                                 continue;
    1533 
     1347                }
     1348
     1349                qualifier_t qualifier = _read_qualifier(fmt, &nxt);
     1350                unsigned int base = 10;
     1351                char specifier = fmt[nxt++];
     1352
     1353                switch (specifier) {
     1354                /*
     1355                 * String and character conversions.
     1356                 */
     1357                case 's':
     1358                        if (qualifier == PrintfQualifierLong)
     1359                                rc = _format_wstr(va_arg(ap, char32_t *), width, precision, flags, ps, &counter);
     1360                        else
     1361                                rc = _format_cstr(va_arg(ap, char *), width, precision, flags, ps, &counter);
     1362                        continue;
     1363
     1364                case 'c':
     1365                        if (qualifier == PrintfQualifierLong)
     1366                                rc = _format_uchar(va_arg(ap, wint_t), width, flags, ps, &counter);
     1367                        else
     1368                                rc = _format_char(va_arg(ap, int), width, flags, ps, &counter);
     1369                        continue;
     1370
     1371                /*
     1372                 * Floating point values
     1373                 */
     1374                case 'G':
     1375                case 'g':
     1376                case 'F':
     1377                case 'f':
     1378                case 'E':
     1379                case 'e':;
    15341380#ifdef HAS_FLOAT
    1535                                 /*
    1536                                  * Floating point values
    1537                                  */
    1538                         case 'G':
    1539                         case 'g':
    1540                         case 'F':
    1541                         case 'f':
    1542                         case 'E':
    1543                         case 'e':
    1544                                 retval = print_double(va_arg(ap, double), uc, precision,
    1545                                     width, flags, ps);
    1546 
    1547                                 if (retval < 0) {
    1548                                         counter = -counter;
    1549                                         goto out;
    1550                                 }
    1551 
    1552                                 counter += retval;
    1553                                 j = nxt;
    1554                                 continue;
     1381                        rc = _format_double(va_arg(ap, double), specifier, precision,
     1382                            width, flags, ps, &counter);
     1383#else
     1384                        rc = _format_cstr("<float unsupported>", width, -1, 0, ps, &counter);
    15551385#endif
    1556 
    1557                                 /*
    1558                                  * Integer values
    1559                                  */
    1560                         case 'P':
    1561                                 /* Pointer */
    1562                                 flags |= __PRINTF_FLAG_BIGCHARS;
    1563                                 /* Fallthrough */
    1564                         case 'p':
    1565                                 flags |= __PRINTF_FLAG_PREFIX;
    1566                                 flags |= __PRINTF_FLAG_ZEROPADDED;
    1567                                 base = 16;
    1568                                 qualifier = PrintfQualifierPointer;
    1569                                 break;
    1570                         case 'b':
    1571                                 base = 2;
    1572                                 break;
    1573                         case 'o':
    1574                                 base = 8;
    1575                                 break;
    1576                         case 'd':
    1577                         case 'i':
    1578                                 flags |= __PRINTF_FLAG_SIGNED;
    1579                                 /* Fallthrough */
    1580                         case 'u':
    1581                                 break;
    1582                         case 'X':
    1583                                 flags |= __PRINTF_FLAG_BIGCHARS;
    1584                                 /* Fallthrough */
    1585                         case 'x':
    1586                                 base = 16;
    1587                                 break;
    1588 
    1589                         case '%':
    1590                                 /* Percentile itself */
    1591                                 j = i;
    1592                                 continue;
    1593 
    1594                                 /*
    1595                                  * Bad formatting.
    1596                                  */
    1597                         default:
    1598                                 /*
    1599                                  * Unknown format. Now, j is the index of '%'
    1600                                  * so we will print whole bad format sequence.
    1601                                  */
    1602                                 continue;
    1603                         }
    1604 
    1605                         /* Print integers */
    1606                         size_t size;
    1607                         uint64_t number;
    1608 
    1609                         switch (qualifier) {
    1610                         case PrintfQualifierByte:
    1611                                 size = sizeof(unsigned char);
    1612                                 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
    1613                                 break;
    1614                         case PrintfQualifierShort:
    1615                                 size = sizeof(unsigned short);
    1616                                 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
    1617                                 break;
    1618                         case PrintfQualifierInt:
    1619                                 size = sizeof(unsigned int);
    1620                                 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
    1621                                 break;
    1622                         case PrintfQualifierLong:
    1623                                 size = sizeof(unsigned long);
    1624                                 number = PRINTF_GET_INT_ARGUMENT(long, ap, flags);
    1625                                 break;
    1626                         case PrintfQualifierLongLong:
    1627                                 size = sizeof(unsigned long long);
    1628                                 number = PRINTF_GET_INT_ARGUMENT(long long, ap, flags);
    1629                                 break;
    1630                         case PrintfQualifierPointer:
    1631                                 size = sizeof(void *);
    1632                                 precision = size << 1;
    1633                                 number = (uint64_t) (uintptr_t) va_arg(ap, void *);
    1634                                 break;
    1635                         case PrintfQualifierSize:
    1636                                 size = sizeof(size_t);
    1637                                 number = (uint64_t) va_arg(ap, size_t);
    1638                                 break;
    1639                         case PrintfQualifierMax:
    1640                                 size = sizeof(uintmax_t);
    1641                                 number = (uint64_t) va_arg(ap, uintmax_t);
    1642                                 break;
    1643                         default:
    1644                                 /* Unknown qualifier */
    1645                                 counter = -counter;
    1646                                 goto out;
    1647                         }
    1648 
    1649                         if ((retval = print_number(number, width, precision,
    1650                             base, flags, ps)) < 0) {
    1651                                 counter = -counter;
    1652                                 goto out;
    1653                         }
    1654 
    1655                         counter += retval;
    1656                         j = nxt;
    1657                 }
    1658         }
    1659 
    1660         if (i > j) {
    1661                 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
    1662                         /* Error */
    1663                         counter = -counter;
    1664                         goto out;
    1665                 }
    1666                 counter += retval;
    1667         }
    1668 
    1669 out:
    1670         return ((int) counter);
     1386                        continue;
     1387
     1388                /*
     1389                 * Integer values
     1390                 */
     1391                case 'P':
     1392                        /* Pointer */
     1393                        flags |= __PRINTF_FLAG_BIGCHARS;
     1394                        /* Fallthrough */
     1395                case 'p':
     1396                        flags |= __PRINTF_FLAG_PREFIX;
     1397                        flags |= __PRINTF_FLAG_ZEROPADDED;
     1398                        base = 16;
     1399                        qualifier = PrintfQualifierPointer;
     1400                        break;
     1401                case 'b':
     1402                        base = 2;
     1403                        break;
     1404                case 'o':
     1405                        base = 8;
     1406                        break;
     1407                case 'd':
     1408                case 'i':
     1409                        flags |= __PRINTF_FLAG_SIGNED;
     1410                        break;
     1411                case 'u':
     1412                        break;
     1413                case 'X':
     1414                        flags |= __PRINTF_FLAG_BIGCHARS;
     1415                        /* Fallthrough */
     1416                case 'x':
     1417                        base = 16;
     1418                        break;
     1419
     1420                case '%':
     1421                        /* Percentile itself */
     1422                        rc = _write_char('%', ps, &counter);
     1423                        continue;
     1424
     1425                /*
     1426                 * Bad formatting.
     1427                 */
     1428                default:
     1429                        rc = EINVAL;
     1430                        continue;
     1431                }
     1432
     1433                /* Print integers */
     1434                uint64_t number;
     1435
     1436                switch (qualifier) {
     1437                case PrintfQualifierByte:
     1438                        number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
     1439                        break;
     1440                case PrintfQualifierShort:
     1441                        number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
     1442                        break;
     1443                case PrintfQualifierInt:
     1444                        number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
     1445                        break;
     1446                case PrintfQualifierLong:
     1447                        number = PRINTF_GET_INT_ARGUMENT(long, ap, flags);
     1448                        break;
     1449                case PrintfQualifierLongLong:
     1450                        number = PRINTF_GET_INT_ARGUMENT(long long, ap, flags);
     1451                        break;
     1452                case PrintfQualifierPointer:
     1453                        precision = sizeof(void *) << 1;
     1454                        number = (uint64_t) (uintptr_t) va_arg(ap, void *);
     1455                        break;
     1456                default:
     1457                        /* Unknown qualifier */
     1458                        rc = EINVAL;
     1459                        continue;
     1460                }
     1461
     1462                rc = _format_number(number, width, precision, base, flags, ps, &counter);
     1463        }
     1464
     1465        if (rc != EOK) {
     1466                _set_errno(rc);
     1467                return -1;
     1468        }
     1469
     1470        if (counter > INT_MAX) {
     1471                _set_errno(EOVERFLOW);
     1472                return -1;
     1473        }
     1474
     1475        return (int) counter;
    16711476}
    16721477
  • common/stdc/vsnprintf.c

    r240b2e4 rc7c6afd  
    11/*
    22 * Copyright (c) 2006 Josef Cejka
     3 * Copyright (c) 2025 Jiří Zárevúcky
    34 * All rights reserved.
    45 *
     
    2728 */
    2829
    29 /** @addtogroup kernel_generic
     30/** @addtogroup libc
    3031 * @{
    3132 */
     
    3334 */
    3435
    35 #ifndef KERN_PRINTF_CORE_H_
    36 #define KERN_PRINTF_CORE_H_
     36#include <errno.h>
     37#include <macros.h>
     38#include <printf_core.h>
     39#include <stdarg.h>
     40#include <stdio.h>
     41#include <str.h>
    3742
    38 #include <stdarg.h>
    39 #include <stddef.h>
    40 #include <uchar.h>
     43typedef struct {
     44        char *dst;      /* Destination */
     45        size_t left;
     46} vsnprintf_data_t;
    4147
    42 /** Structure for specifying output methods for different printf clones. */
    43 typedef struct {
    44         /* String output function, returns number of printed characters or EOF */
    45         int (*str_write)(const char *, size_t, void *);
     48static int vsnprintf_str_write(const char *str, size_t size, void *data)
     49{
     50        vsnprintf_data_t *d = data;
     51        size_t left = min(size, d->left);
     52        if (left > 0) {
     53                memcpy(d->dst, str, left);
     54                d->dst += left;
     55                d->left -= left;
     56        }
     57        return EOK;
     58}
    4659
    47         /* Wide string output function, returns number of printed characters or EOF */
    48         int (*wstr_write)(const char32_t *, size_t, void *);
     60int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
     61{
     62        vsnprintf_data_t data = {
     63                .dst = str,
     64                .left = size ? size - 1 : 0,
     65        };
    4966
    50         /* User data - output stream specification, state, locks, etc. */
    51         void *data;
    52 } printf_spec_t;
     67        printf_spec_t ps = {
     68                vsnprintf_str_write,
     69                &data
     70        };
    5371
    54 extern int printf_core(const char *fmt, printf_spec_t *ps, va_list ap);
     72        int written = printf_core(fmt, &ps, ap);
     73        if (written < 0)
     74                return written;
    5575
    56 #endif
     76        /* Write the terminating NUL character. */
     77        if (size > 0)
     78                data.dst[0] = 0;
     79
     80        return written;
     81}
    5782
    5883/** @}
  • kernel/generic/meson.build

    r240b2e4 rc7c6afd  
    4040        'common/adt/list.c',
    4141        'common/adt/odict.c',
     42        'common/gsort.c',
    4243        'common/printf/printf_core.c',
    4344        'common/stdc/calloc.c',
    4445        'common/stdc/ctype.c',
    4546        'common/stdc/mem.c',
    46         'common/gsort.c',
     47        'common/stdc/snprintf.c',
     48        'common/stdc/vsnprintf.c',
    4749        'common/str.c',
    4850        'common/str_error.c',
     
    9698        'src/mm/reserve.c',
    9799        'src/printf/printf.c',
    98         'src/printf/snprintf.c',
    99100        'src/printf/vprintf.c',
    100         'src/printf/vsnprintf.c',
    101101        'src/proc/program.c',
    102102        'src/proc/scheduler.c',
  • kernel/generic/src/log/log.c

    r240b2e4 rc7c6afd  
    3333 */
    3434
    35 #include <sysinfo/sysinfo.h>
    36 #include <synch/spinlock.h>
    37 #include <typedefs.h>
     35#include <abi/log.h>
     36#include <arch.h>
     37#include <atomic.h>
     38#include <console/console.h>
     39#include <ddi/ddi.h>
    3840#include <ddi/irq.h>
    39 #include <ddi/ddi.h>
     41#include <errno.h>
    4042#include <ipc/event.h>
    4143#include <ipc/irq.h>
    42 #include <arch.h>
     44#include <log.h>
    4345#include <panic.h>
     46#include <print.h>
     47#include <printf_core.h>
    4448#include <putchar.h>
    45 #include <atomic.h>
     49#include <stdarg.h>
     50#include <stdlib.h>
     51#include <str.h>
     52#include <synch/spinlock.h>
    4653#include <syscall/copy.h>
    47 #include <errno.h>
    48 #include <str.h>
    49 #include <print.h>
    50 #include <printf/printf_core.h>
    51 #include <stdarg.h>
    52 #include <log.h>
    53 #include <console/console.h>
    54 #include <abi/log.h>
    55 #include <stdlib.h>
     54#include <sysinfo/sysinfo.h>
     55#include <typedefs.h>
    5656
    5757#define LOG_PAGES    8
     
    204204{
    205205        size_t offset = 0;
    206         size_t chars = 0;
    207 
    208         while (offset < size) {
     206
     207        while (offset < size)
    209208                kio_push_char(str_decode(str, &offset, size));
    210                 chars++;
    211         }
    212209
    213210        log_append((const uint8_t *)str, size);
    214211
    215         return chars;
    216 }
    217 
    218 static int log_printf_wstr_write(const char32_t *wstr, size_t size, void *data)
    219 {
    220         char buffer[16];
    221         size_t offset = 0;
    222         size_t chars = 0;
    223 
    224         for (offset = 0; offset < size; offset += sizeof(char32_t), chars++) {
    225                 kio_push_char(wstr[chars]);
    226 
    227                 size_t buffer_offset = 0;
    228                 errno_t rc = chr_encode(wstr[chars], buffer, &buffer_offset, 16);
    229                 if (rc != EOK) {
    230                         return EOF;
    231                 }
    232 
    233                 log_append((const uint8_t *)buffer, buffer_offset);
    234         }
    235 
    236         return chars;
     212        return EOK;
    237213}
    238214
     
    243219int log_vprintf(const char *fmt, va_list args)
    244220{
    245         int ret;
    246 
    247221        printf_spec_t ps = {
    248222                log_printf_str_write,
    249                 log_printf_wstr_write,
    250223                NULL
    251224        };
    252225
    253         ret = printf_core(fmt, &ps, args);
    254 
    255         return ret;
     226        return printf_core(fmt, &ps, args);
    256227}
    257228
  • kernel/generic/src/printf/vprintf.c

    r240b2e4 rc7c6afd  
    3636#include <console/console.h>
    3737#include <print.h>
    38 #include <printf/printf_core.h>
     38#include <printf_core.h>
    3939#include <putchar.h>
    4040#include <str.h>
     
    4242#include <typedefs.h>
    4343
    44 static int vprintf_str_write(const char *str, size_t size, void *data)
     44static errno_t vprintf_str_write(const char *str, size_t size, void *data)
    4545{
    4646        size_t offset = 0;
    47         size_t chars = 0;
    4847
    49         while (offset < size) {
     48        while (offset < size)
    5049                putuchar(str_decode(str, &offset, size));
    51                 chars++;
    52         }
    5350
    54         return chars;
    55 }
    56 
    57 static int vprintf_wstr_write(const char32_t *str, size_t size, void *data)
    58 {
    59         size_t offset = 0;
    60         size_t chars = 0;
    61 
    62         while (offset < size) {
    63                 putuchar(str[chars]);
    64                 chars++;
    65                 offset += sizeof(char32_t);
    66         }
    67 
    68         return chars;
     51        return EOK;
    6952}
    7053
     
    9275        printf_spec_t ps = {
    9376                vprintf_str_write,
    94                 vprintf_wstr_write,
    9577                NULL
    9678        };
  • uspace/lib/c/generic/io/asprintf.c

    r240b2e4 rc7c6afd  
    4040#include <str.h>
    4141#include <printf_core.h>
    42 
    43 static int asprintf_str_write(const char *str, size_t count, void *unused)
    44 {
    45         return str_nlength(str, count);
    46 }
    47 
    48 static int asprintf_wstr_write(const char32_t *str, size_t count, void *unused)
    49 {
    50         return wstr_nlength(str, count);
    51 }
    52 
    53 int vprintf_length(const char *fmt, va_list args)
    54 {
    55         printf_spec_t ps = {
    56                 asprintf_str_write,
    57                 asprintf_wstr_write,
    58                 NULL
    59         };
    60 
    61         return printf_core(fmt, &ps, args);
    62 }
    63 
    64 int printf_length(const char *fmt, ...)
    65 {
    66         va_list args;
    67         va_start(args, fmt);
    68         int ret = vprintf_length(fmt, args);
    69         va_end(args);
    70 
    71         return ret;
    72 }
    7342
    7443/** Allocate and print to string.
     
    11584        int ret = vasprintf(strp, fmt, args);
    11685        va_end(args);
    117 
    11886        return ret;
    11987}
  • uspace/lib/c/generic/io/kio.c

    r240b2e4 rc7c6afd  
    131131}
    132132
    133 static int kio_vprintf_str_write(const char *str, size_t size, void *data)
     133static errno_t kio_vprintf_str_write(const char *str, size_t size, void *data)
    134134{
    135         size_t wr;
    136 
    137         wr = 0;
    138         (void) kio_write(str, size, &wr);
    139         return str_nlength(str, wr);
    140 }
    141 
    142 static int kio_vprintf_wstr_write(const char32_t *str, size_t size, void *data)
    143 {
    144         size_t offset = 0;
    145         size_t chars = 0;
    146         size_t wr;
    147 
    148         while (offset < size) {
    149                 char buf[STR_BOUNDS(1)];
    150                 size_t sz = 0;
    151 
    152                 if (chr_encode(str[chars], buf, &sz, STR_BOUNDS(1)) == EOK)
    153                         kio_write(buf, sz, &wr);
    154 
    155                 chars++;
    156                 offset += sizeof(char32_t);
    157         }
    158 
    159         return chars;
     135        size_t wr = 0;
     136        return kio_write(str, size, &wr);
    160137}
    161138
     
    172149        printf_spec_t ps = {
    173150                kio_vprintf_str_write,
    174                 kio_vprintf_wstr_write,
    175151                NULL
    176152        };
  • uspace/lib/c/generic/io/vprintf.c

    r240b2e4 rc7c6afd  
    4242static FIBRIL_MUTEX_INITIALIZE(printf_mutex);
    4343
    44 static int vprintf_str_write(const char *str, size_t size, void *stream)
     44static errno_t vprintf_str_write(const char *str, size_t size, void *stream)
    4545{
    46         size_t wr = fwrite(str, 1, size, (FILE *) stream);
    47         return str_nlength(str, wr);
    48 }
     46        errno_t old_errno = errno;
    4947
    50 static int vprintf_wstr_write(const char32_t *str, size_t size, void *stream)
    51 {
    52         size_t offset = 0;
    53         size_t chars = 0;
     48        errno = EOK;
     49        size_t written = fwrite(str, 1, size, (FILE *) stream);
    5450
    55         while (offset < size) {
    56                 if (fputuc(str[chars], (FILE *) stream) <= 0)
    57                         break;
     51        if (errno == EOK && written != size)
     52                errno = EIO;
    5853
    59                 chars++;
    60                 offset += sizeof(char32_t);
    61         }
     54        if (errno != EOK)
     55                return errno;
    6256
    63         return chars;
     57        errno = old_errno;
     58        return EOK;
    6459}
    6560
     
    7772        printf_spec_t ps = {
    7873                vprintf_str_write,
    79                 vprintf_wstr_write,
    8074                stream
    8175        };
  • uspace/lib/c/include/stdio.h

    r240b2e4 rc7c6afd  
    209209};
    210210
    211 extern int vprintf_length(const char *, va_list);
    212 extern int printf_length(const char *, ...)
    213     _HELENOS_PRINTF_ATTRIBUTE(1, 2);
    214211extern FILE *fdopen(int, const char *);
    215212extern int fileno(FILE *);
  • uspace/lib/c/meson.build

    r240b2e4 rc7c6afd  
    7272        'common/stdc/mem.c',
    7373        'common/stdc/qsort.c',
     74        'common/stdc/snprintf.c',
    7475        'common/stdc/uchar.c',
     76        'common/stdc/vsnprintf.c',
    7577        'common/stdc/wchar.c',
    7678        'common/str.c',
     
    113115        'generic/io/logctl.c',
    114116        'generic/io/printf.c',
    115         'generic/io/snprintf.c',
    116117        'generic/io/table.c',
    117118        'generic/io/vprintf.c',
    118         'generic/io/vsnprintf.c',
    119119        'generic/ipc.c',
    120120        'generic/irq.c',
  • uspace/lib/posix/src/stdio.c

    r240b2e4 rc7c6afd  
    232232 * @return The number of written characters.
    233233 */
    234 static int _dprintf_str_write(const char *str, size_t size, void *fd)
     234static errno_t _dprintf_str_write(const char *str, size_t size, void *fd)
    235235{
    236236        const int fildes = *(int *) fd;
    237237        size_t wr;
    238         if (failed(vfs_write(fildes, &posix_pos[fildes], str, size, &wr)))
    239                 return -1;
    240         return str_nlength(str, wr);
    241 }
    242 
    243 /**
    244  * Write wide string to the opened file.
    245  *
    246  * @param str String to be written.
    247  * @param size Size of the string (in bytes).
    248  * @param fd File descriptor of the opened file.
    249  * @return The number of written characters.
    250  */
    251 static int _dprintf_wstr_write(const char32_t *str, size_t size, void *fd)
    252 {
    253         size_t offset = 0;
    254         size_t chars = 0;
    255         size_t sz;
    256         char buf[4];
    257 
    258         while (offset < size) {
    259                 sz = 0;
    260                 if (chr_encode(str[chars], buf, &sz, sizeof(buf)) != EOK) {
    261                         break;
    262                 }
    263 
    264                 const int fildes = *(int *) fd;
    265                 size_t nwr;
    266                 if (vfs_write(fildes, &posix_pos[fildes], buf, sz, &nwr) != EOK)
    267                         break;
    268 
    269                 chars++;
    270                 offset += sizeof(char32_t);
    271         }
    272 
    273         return chars;
     238        return vfs_write(fildes, &posix_pos[fildes], str, size, &wr);
    274239}
    275240
     
    285250{
    286251        printf_spec_t spec = {
    287                 .str_write = _dprintf_str_write,
    288                 .wstr_write = _dprintf_wstr_write,
     252                .write = _dprintf_str_write,
    289253                .data = &fildes
    290254        };
Note: See TracChangeset for help on using the changeset viewer.