lkml.org 
[lkml]   [2022]   [Feb]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 21/42] tools/nolibc/stdio: add a minimal [vf]printf() implementation
    Date
    This adds a minimal vfprintf() implementation as well as the commonly
    used fprintf() and printf() that rely on it.

    For now the function supports:
    - formats: %s, %c, %u, %d, %x
    - modifiers: %l and %ll
    - unknown chars are considered as modifiers and are ignored

    It is designed to remain minimalist, despite this printf() is 549 bytes
    on x86_64. It would be wise not to add too many formats.

    Signed-off-by: Willy Tarreau <w@1wt.eu>
    ---
    tools/include/nolibc/stdio.h | 128 +++++++++++++++++++++++++++++++++++
    1 file changed, 128 insertions(+)

    diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
    index 996bf89a30d2..a73cf24cb68d 100644
    --- a/tools/include/nolibc/stdio.h
    +++ b/tools/include/nolibc/stdio.h
    @@ -7,6 +7,8 @@
    #ifndef _NOLIBC_STDIO_H
    #define _NOLIBC_STDIO_H

    +#include <stdarg.h>
    +
    #include "std.h"
    #include "arch.h"
    #include "types.h"
    @@ -158,4 +160,130 @@ char *fgets(char *s, int size, FILE *stream)
    return ofs ? s : NULL;
    }

    +
    +/* minimal vfprintf(). It supports the following formats:
    + * - %[l*]{d,u,c,x}
    + * - %s
    + * - unknown modifiers are ignored.
    + */
    +static __attribute__((unused))
    +int vfprintf(FILE *stream, const char *fmt, va_list args)
    +{
    + char escape, lpref, c;
    + unsigned long long v;
    + unsigned int written;
    + size_t len, ofs;
    + char tmpbuf[21];
    + const char *outstr;
    +
    + written = ofs = escape = lpref = 0;
    + while (1) {
    + c = fmt[ofs++];
    +
    + if (escape) {
    + /* we're in an escape sequence, ofs == 1 */
    + escape = 0;
    + if (c == 'c' || c == 'd' || c == 'u' || c == 'x') {
    + if (lpref) {
    + if (lpref > 1)
    + v = va_arg(args, unsigned long long);
    + else
    + v = va_arg(args, unsigned long);
    + } else
    + v = va_arg(args, unsigned int);
    +
    + if (c == 'd') {
    + /* sign-extend the value */
    + if (lpref == 0)
    + v = (long long)(int)v;
    + else if (lpref == 1)
    + v = (long long)(long)v;
    + }
    +
    + switch (c) {
    + case 'd':
    + i64toa_r(v, tmpbuf);
    + break;
    + case 'u':
    + u64toa_r(v, tmpbuf);
    + break;
    + case 'x':
    + u64toh_r(v, tmpbuf);
    + break;
    + default: /* 'c' */
    + tmpbuf[0] = v;
    + tmpbuf[1] = 0;
    + break;
    + }
    + outstr = tmpbuf;
    + }
    + else if (c == 's') {
    + outstr = va_arg(args, char *);
    + }
    + else if (c == '%') {
    + /* queue it verbatim */
    + continue;
    + }
    + else {
    + /* modifiers or final 0 */
    + if (c == 'l') {
    + /* long format prefix, maintain the escape */
    + lpref++;
    + }
    + escape = 1;
    + goto do_escape;
    + }
    + len = strlen(outstr);
    + goto flush_str;
    + }
    +
    + /* not an escape sequence */
    + if (c == 0 || c == '%') {
    + /* flush pending data on escape or end */
    + escape = 1;
    + lpref = 0;
    + outstr = fmt;
    + len = ofs - 1;
    + flush_str:
    + if (_fwrite(outstr, len, stream) != 0)
    + break;
    +
    + written += len;
    + do_escape:
    + if (c == 0)
    + break;
    + fmt += ofs;
    + ofs = 0;
    + continue;
    + }
    +
    + /* literal char, just queue it */
    + }
    + return written;
    +}
    +
    +static __attribute__((unused))
    +int fprintf(FILE *stream, const char *fmt, ...)
    +{
    + va_list args;
    + int ret;
    +
    + va_start(args, fmt);
    + ret = vfprintf(stream, fmt, args);
    + va_end(args);
    + return ret;
    +}
    +
    +static __attribute__((unused))
    +int printf(const char *fmt, ...)
    +{
    + va_list args;
    + int ret;
    +
    + va_start(args, fmt);
    + ret = vfprintf(stdout, fmt, args);
    + va_end(args);
    + return ret;
    +}
    +
    #endif /* _NOLIBC_STDIO_H */
    --
    2.35.1
    \
     
     \ /
      Last update: 2022-02-07 18:09    [W:5.717 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site