changeset 531:f43c961cc85d

Move bulk of the printf() implementation into a separate file th_printf.c from th_string.c
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 28 Dec 2019 11:09:29 +0200
parents 94d4130cc29c
children ad64c3f7cf64
files Makefile.inc th_printf.c th_string.c
diffstat 3 files changed, 508 insertions(+), 500 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.inc	Sat Dec 28 10:00:41 2019 +0200
+++ b/Makefile.inc	Sat Dec 28 11:09:29 2019 +0200
@@ -37,7 +37,7 @@
 all: $(NOBUILD_TARGETS) $(NOINST_TARGETS) $(TARGETS)
 
 
-$(THLIBS)th_string.c: $(addprefix $(THLIBS), th_printf1.c th_strmatch.c th_string.h)
+$(THLIBS)th_string.c: $(addprefix $(THLIBS), th_printf.c th_printf1.c th_strmatch.c th_string.h)
 	@touch $@
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/th_printf.c	Sat Dec 28 11:09:29 2019 +0200
@@ -0,0 +1,504 @@
+/*
+ * A printf() implementation
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2016-2019 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+
+
+#ifdef TH_PRINTF_DEBUG
+BOOL th_printf_debug = FALSE;
+char *th_printf_debug_prefix = NULL;
+
+
+static void pflag(char *buf, const char *str, const int sep, const int flags, const int flg)
+{
+    strcat(buf, (flags & flg) ? str : "   ");
+    if (sep)
+        strcat(buf, "|");
+}
+
+
+static const char *get_flags(const int flags)
+{
+    static char buf[256];
+
+    buf[0] = 0;
+
+    pflag(buf, "ALT", 1, flags, TH_PF_ALT);
+    pflag(buf, "SGN", 1, flags, TH_PF_SIGN);
+    pflag(buf, "SPC", 1, flags, TH_PF_SPACE);
+    pflag(buf, "GRP", 1, flags, TH_PF_GROUP);
+    pflag(buf, "ZER", 1, flags, TH_PF_ZERO);
+    pflag(buf, "LFT", 0, flags, TH_PF_LEFT);
+
+    return buf;
+}
+
+#define PP_LINE(...) \
+    do { \
+        if (th_printf_debug) { \
+            if (th_printf_debug_prefix != NULL) \
+                fputs(th_printf_debug_prefix, stdout); \
+            fprintf(stdout, __VA_ARGS__); \
+        } \
+    } while (0)
+
+#define PP_PRINTF(...) \
+    do { \
+        if (th_printf_debug) { \
+            fprintf(stdout, __VA_ARGS__); \
+        } \
+    } while (0)
+
+#else
+#define PP_LINE(...) /* stub */
+#define PP_PRINTF(...) /* stub */
+#endif
+
+
+static int th_vprintf_put_pstr(th_vprintf_ctx *ctx, th_vprintf_putch vputch, const char *str)
+{
+    while (*str)
+    {
+        int ret;
+        if ((ret = vputch(ctx, *str++)) == EOF)
+            return ret;
+    }
+    return 0;
+}
+
+
+static int th_vprintf_put_repch(th_vprintf_ctx *ctx, th_vprintf_putch vputch, int count, const char ch)
+{
+    while (count-- > 0)
+    {
+        int ret;
+        if ((ret = vputch(ctx, ch)) == EOF)
+            return ret;
+    }
+    return 0;
+}
+
+
+static int th_printf_pad_pre(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
+    int f_width, const int f_flags)
+{
+    if (f_width > 0 && (f_flags & TH_PF_LEFT) == 0)
+        return th_vprintf_put_repch(ctx, vputch, f_width, ' ');
+    else
+        return 0;
+}
+
+
+static int th_printf_pad_post(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
+    int f_width, const int f_flags)
+{
+    if (f_width > 0 && (f_flags & TH_PF_LEFT))
+        return th_vprintf_put_repch(ctx, vputch, f_width, ' ');
+    else
+        return 0;
+}
+
+
+#define TH_PFUNC_NAME th_vprintf_buf_int
+#define TH_PFUNC_TYPE_S int
+#define TH_PFUNC_TYPE_U unsigned int
+#include "th_printf1.c"
+
+
+#define TH_PFUNC_NAME th_vprintf_buf_int64
+#define TH_PFUNC_TYPE_S int64_t
+#define TH_PFUNC_TYPE_U uint64_t
+#include "th_printf1.c"
+
+
+char * th_vprintf_altfmt_oct(const char *buf, const size_t len, const int vret, const int flags)
+{
+    (void) vret;
+    (void) flags;
+    PP_LINE("BUF='%s', '%c'\n", buf, buf[len - 1]);
+    return (buf[len - 1] != '0') ? "0" : "";
+}
+
+
+char * th_vprintf_altfmt_hex(const char *buf, const size_t len, const int vret, const int flags)
+{
+    (void) buf;
+    (void) vret;
+    (void) len;
+    if (vret != 0)
+        return (flags & TH_PF_UPCASE) ? "0X" : "0x";
+    else
+        return "";
+}
+
+
+int th_vprintf_put_int_format(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
+    char *buf, int f_flags, int f_width, int f_prec, int f_len, int vret,
+    BOOL f_neg, BOOL f_unsig, char *(f_alt)(const char *buf, const size_t blen, const int vret, const int flags))
+{
+    int ret = 0, nwidth, nprec;
+    char f_sign, *f_altstr;
+
+    // Special case for value of 0
+    if (vret == 0)
+    {
+        if (f_flags & TH_PF_POINTER)
+        {
+            strcpy(buf, ")lin(");
+            f_len = 5;
+        }
+        else
+        if (f_prec != 0)
+        {
+            buf[f_len++] = '0';
+            buf[f_len] = 0;
+        }
+    }
+
+    // Get alternative format string, if needed and available
+    f_altstr = (f_flags & TH_PF_ALT) && f_alt != NULL ? f_alt(buf, f_len, vret, f_flags) : NULL;
+
+    // Are we using a sign prefix?
+    f_sign = f_unsig ? 0 : ((f_flags & TH_PF_SIGN) ?
+        (f_neg ? '-' : '+') :
+        (f_neg ? '-' : ((f_flags & TH_PF_SPACE) ? ' ' : 0)));
+
+    // Calculate necessary padding, etc
+    //
+    // << XXX TODO FIXME: The logic here is not very elegant, and it's incorrect
+    // at least for some alternate format modifier cases.
+    //
+
+    int nlen =  (f_sign ? 1 : 0) + (f_altstr ? strlen(f_altstr) : 0);
+    int qlen = (f_prec > f_len ? f_prec : f_len) + nlen;
+
+    if (f_flags & TH_PF_LEFT)
+        f_flags &= ~TH_PF_ZERO;
+
+    if (f_flags & TH_PF_POINTER && vret == 0)
+    {
+        PP_LINE("^");
+        qlen = f_len + nlen;
+        nwidth = f_width > qlen ? f_width - qlen : 0;
+        nprec = 0;
+    }
+    else
+    if ((f_flags & TH_PF_ZERO) && f_prec < 0 && f_width > 0)
+    {
+        PP_LINE("#");
+        nprec = f_width - qlen;
+        nwidth = 0;
+    }
+    else
+    {
+        PP_LINE("$");
+        nprec = (f_prec >= 0) ? f_prec - f_len : 0;
+        nwidth = (f_width >= 0) ? f_width - qlen : 0;
+    }
+
+    PP_PRINTF(": vret=%3d, f_flags=[%s], f_unsig=%d, f_sign='%c', f_len=%3d, f_width=%3d, f_prec=%3d, nwidth=%3d, nprec=%3d, qlen=%3d\n",
+        vret, get_flags(f_flags), f_unsig, f_sign ? f_sign : '?', f_len, f_width, f_prec, nwidth, nprec, qlen);
+
+    // << XXX TODO FIXME
+
+    // Prefix padding
+    if ((ret = th_printf_pad_pre(ctx, vputch, nwidth, f_flags)) == EOF)
+        return ret;
+
+    // Sign prefix
+    if (f_sign && (ret = vputch(ctx, f_sign)) == EOF)
+        return ret;
+
+    // Alternative format string
+    if (f_altstr && (ret = th_vprintf_put_pstr(ctx, vputch, f_altstr)) == EOF)
+        return ret;
+
+    // Zero padding
+    if (nprec > 0 && (ret = th_vprintf_put_repch(ctx, vputch, nprec, '0')) == EOF)
+        return ret;
+
+    // Output the value
+    while (f_len-- > 0)
+    {
+        if ((ret = vputch(ctx, buf[f_len])) == EOF)
+            return ret;
+    }
+
+    // Postfix padding?
+    return th_printf_pad_post(ctx, vputch, nwidth, f_flags);
+}
+
+
+int th_vprintf_put_int(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
+    va_list ap, const int f_radix, int f_flags, int f_width, int f_prec,
+    const BOOL f_unsig, char *(f_alt)(const char *buf, const size_t blen, const int vret, const int flags))
+{
+    char buf[64];
+    int f_len = 0, vret;
+    BOOL f_neg = FALSE;
+
+    if (f_flags & TH_PF_LONGLONG)
+    {
+        vret = th_vprintf_buf_int64(buf, sizeof(buf), &f_len, va_arg(ap, int64_t),
+            f_radix, f_flags & TH_PF_UPCASE, f_unsig, &f_neg);
+    }
+    else
+    {
+       vret = th_vprintf_buf_int(buf, sizeof(buf), &f_len, va_arg(ap, unsigned int),
+            f_radix, f_flags & TH_PF_UPCASE, f_unsig, &f_neg);
+    }
+
+    if (vret == EOF)
+        return 0;
+
+    return th_vprintf_put_int_format(ctx, vputch, buf, f_flags, f_width, f_prec, f_len, vret, f_neg, f_unsig, f_alt);
+}
+
+
+int th_vprintf_put_str(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
+    const char *str, int f_flags, const int f_width, const int f_prec)
+{
+    int nwidth, f_len, ret = 0;
+
+    // Check for null strings
+    if (str == NULL)
+        str = "(null)";
+
+    f_len = strlen(str);
+    if (f_prec >= 0 && f_len > f_prec)
+        f_len = f_prec;
+
+    nwidth = f_width - f_len;
+
+    // Prefix padding?
+    if ((ret = th_printf_pad_pre(ctx, vputch, nwidth, f_flags)) == EOF)
+        return ret;
+
+    while (*str && f_len--)
+    {
+        if ((ret = vputch(ctx, *str++)) == EOF)
+            return ret;
+    }
+
+    // Postfix padding?
+    return th_printf_pad_post(ctx, vputch, nwidth, f_flags);
+}
+
+
+#ifdef WIP_FLOAT_SUPPORT
+int th_vprintf_put_float(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
+    va_list ap, int f_flags, int f_width, int f_prec)
+{
+    double pval = va_arg(ap, double);   // This needs to be double for type promotion to occur
+    int64_t val;
+
+    // This is a hack, trying to avoid dereferencing a type-punned
+    // pointer and all that stuff related to strict aliasing (although
+    // double and int64_t should be same size and have same aliasing rules.)
+    memcpy(&val, &pval, sizeof(int64_t));
+
+    // We have sign, exponent and mantissa
+    BOOL f_sign    = (val >> 63) & 0x01;
+    int64_t d_exp  = (val >> 52) & 0x7ff;
+    uint64_t d_man = val & 0x0fffffffffffff;
+
+    return 0;
+}
+#endif
+
+
+int th_vprintf_do(th_vprintf_ctx *ctx, th_vprintf_putch vputch, const char *fmt, va_list ap)
+{
+    int ret = 0;
+
+    while (*fmt)
+    {
+        if (*fmt != '%')
+        {
+            if ((ret = vputch(ctx, *fmt)) == EOF)
+                goto out;
+        }
+        else
+        {
+            int f_width = -1, f_prec = -1, f_flags = 0;
+            BOOL end = FALSE;
+
+            fmt++;
+
+            // Check for flags
+            while (!end)
+            {
+                switch (*fmt)
+                {
+                    case '#':
+                        f_flags |= TH_PF_ALT;
+                        break;
+
+                    case '+':
+                        f_flags |= TH_PF_SIGN;
+                        break;
+
+                    case '0':
+                        f_flags |= TH_PF_ZERO;
+                        break;
+
+                    case '-':
+                        f_flags |= TH_PF_LEFT;
+                        break;
+
+                    case ' ':
+                        f_flags |= TH_PF_SPACE;
+                        break;
+
+                    case '\'':
+                        f_flags |= TH_PF_GROUP;
+                        break;
+
+                    default:
+                        end = TRUE;
+                        break;
+                }
+                if (!end) fmt++;
+            }
+
+            // Get field width
+            if (*fmt == '*')
+            {
+                fmt++;
+                f_width = va_arg(ap, int);
+                if (f_width < 0)
+                {
+                    f_flags |= TH_PF_LEFT;
+                    f_width = -f_width;
+                }
+            }
+            else
+            {
+                f_width = 0;
+                while (th_isdigit(*fmt))
+                    f_width = f_width * 10 + (*fmt++ - '0');
+            }
+
+            // Check for field precision
+            if (*fmt == '.')
+            {
+                fmt++;
+                if (*fmt == '*')
+                {
+                    fmt++;
+                    f_prec = va_arg(ap, int);
+                }
+                else
+                {
+                    // If no digit after '.', precision is to be 0
+                    f_prec = 0;
+                    while (th_isdigit(*fmt))
+                        f_prec = f_prec * 10 + (*fmt++ - '0');
+                }
+            }
+
+
+            // Check for length modifiers (only some are supported currently)
+            switch (*fmt)
+            {
+                case 'l':
+                    if (*++fmt == 'l')
+                    {
+                        f_flags |= TH_PF_LONGLONG;
+                        fmt++;
+                    }
+                    else
+                        f_flags |= TH_PF_LONG;
+                    break;
+
+                case 'L':
+                    fmt++;
+                    f_flags |= TH_PF_LONGLONG;
+                    break;
+
+                case 'h':
+                case 'j':
+                case 'z':
+                case 't':
+                    return -202;
+            }
+
+            switch (*fmt)
+            {
+                case 0:
+                    return -104;
+
+                case 'c':
+                    if ((ret = th_printf_pad_pre(ctx, vputch, f_width - 1, f_flags)) == EOF)
+                        goto out;
+                    if ((ret = vputch(ctx, va_arg(ap, int))) == EOF)
+                        goto out;
+                    if ((ret = th_printf_pad_post(ctx, vputch, f_width - 1, f_flags)) == EOF)
+                        goto out;
+                    break;
+
+                case 'o':
+                    if ((ret = th_vprintf_put_int(ctx, vputch, ap, 8, f_flags, f_width, f_prec, TRUE, th_vprintf_altfmt_oct)) == EOF)
+                        goto out;
+                    break;
+
+                case 'u':
+                case 'i':
+                case 'd':
+                    if ((ret = th_vprintf_put_int(ctx, vputch, ap, 10, f_flags, f_width, f_prec, *fmt == 'u', NULL)) == EOF)
+                        goto out;
+                    break;
+
+                case 'x':
+                case 'X':
+                    if (*fmt == 'X')
+                        f_flags |= TH_PF_UPCASE;
+                    if ((ret = th_vprintf_put_int(ctx, vputch, ap, 16, f_flags, f_width, f_prec, TRUE, th_vprintf_altfmt_hex)) == EOF)
+                        goto out;
+                    break;
+
+                case 'p':
+                    if (f_flags & (TH_PF_LONG | TH_PF_LONGLONG))
+                        return -120;
+
+#if (TH_PTRSIZE == 32)
+                    f_flags |= TH_PF_LONG;
+#elif (TH_PTRSIZE == 64)
+                    f_flags |= TH_PF_LONGLONG;
+#endif
+                    f_flags |= TH_PF_ALT | TH_PF_POINTER;
+                    if ((ret = th_vprintf_put_int(ctx, vputch, ap, 16, f_flags, f_width, f_prec, TRUE, th_vprintf_altfmt_hex)) == EOF)
+                        goto out;
+                    break;
+
+#ifdef WIP_FLOAT_SUPPORT
+                case 'f':
+                case 'F':
+                    if ((ret = th_vprintf_put_float(ctx, vputch, ap,
+                        f_flags, f_width, f_prec)) == EOF)
+                        goto out;
+                    break;
+#endif
+
+                case 's':
+                    if ((ret = th_vprintf_put_str(ctx, vputch, va_arg(ap, char *),
+                        f_flags, f_width, f_prec)) == EOF)
+                        goto out;
+                    break;
+
+                //case '%':
+                default:
+                    if ((ret = vputch(ctx, *fmt)) == EOF)
+                        goto out;
+                    break;
+            }
+        }
+        fmt++;
+    }
+
+out:
+    return ret == EOF ? ret : ctx->ipos;
+}
--- a/th_string.c	Sat Dec 28 10:00:41 2019 +0200
+++ b/th_string.c	Sat Dec 28 11:09:29 2019 +0200
@@ -8,6 +8,9 @@
 #include "th_util.h"
 #include "th_string.h"
 
+// Include printf implementation
+#include "th_printf.c"
+
 
 /* Implementation of strdup() with a NULL check
  */
@@ -131,505 +134,6 @@
 }
 
 
-//
-// Simple implementations of printf() type functions
-//
-static int th_vprintf_put_pstr(th_vprintf_ctx *ctx, th_vprintf_putch vputch, const char *str)
-{
-    while (*str)
-    {
-        int ret;
-        if ((ret = vputch(ctx, *str++)) == EOF)
-            return ret;
-    }
-    return 0;
-}
-
-
-static int th_vprintf_put_repch(th_vprintf_ctx *ctx, th_vprintf_putch vputch, int count, const char ch)
-{
-    while (count-- > 0)
-    {
-        int ret;
-        if ((ret = vputch(ctx, ch)) == EOF)
-            return ret;
-    }
-    return 0;
-}
-
-
-static int th_printf_pad_pre(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
-    int f_width, const int f_flags)
-{
-    if (f_width > 0 && (f_flags & TH_PF_LEFT) == 0)
-        return th_vprintf_put_repch(ctx, vputch, f_width, ' ');
-    else
-        return 0;
-}
-
-
-static int th_printf_pad_post(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
-    int f_width, const int f_flags)
-{
-    if (f_width > 0 && (f_flags & TH_PF_LEFT))
-        return th_vprintf_put_repch(ctx, vputch, f_width, ' ');
-    else
-        return 0;
-}
-
-
-#define TH_PFUNC_NAME th_vprintf_buf_int
-#define TH_PFUNC_TYPE_S int
-#define TH_PFUNC_TYPE_U unsigned int
-#include "th_printf1.c"
-
-
-#define TH_PFUNC_NAME th_vprintf_buf_int64
-#define TH_PFUNC_TYPE_S int64_t
-#define TH_PFUNC_TYPE_U uint64_t
-#include "th_printf1.c"
-
-
-#ifdef TH_PRINTF_DEBUG
-BOOL th_printf_debug = FALSE;
-char *th_printf_debug_prefix = NULL;
-
-
-static void pflag(char *buf, const char *str, const int sep, const int flags, const int flg)
-{
-    strcat(buf, (flags & flg) ? str : "   ");
-    if (sep)
-        strcat(buf, "|");
-}
-
-
-static const char *get_flags(const int flags)
-{
-    static char buf[256];
-
-    buf[0] = 0;
-
-    pflag(buf, "ALT", 1, flags, TH_PF_ALT);
-    pflag(buf, "SGN", 1, flags, TH_PF_SIGN);
-    pflag(buf, "SPC", 1, flags, TH_PF_SPACE);
-    pflag(buf, "GRP", 1, flags, TH_PF_GROUP);
-    pflag(buf, "ZER", 1, flags, TH_PF_ZERO);
-    pflag(buf, "LFT", 0, flags, TH_PF_LEFT);
-
-    return buf;
-}
-
-#define PP_LINE(...) \
-    do { \
-        if (th_printf_debug) { \
-            if (th_printf_debug_prefix != NULL) \
-                fputs(th_printf_debug_prefix, stdout); \
-            fprintf(stdout, __VA_ARGS__); \
-        } \
-    } while (0)
-
-#define PP_PRINTF(...) \
-    do { \
-        if (th_printf_debug) { \
-            fprintf(stdout, __VA_ARGS__); \
-        } \
-    } while (0)
-
-#else
-#define PP_LINE(...) /* stub */
-#define PP_PRINTF(...) /* stub */
-#endif
-
-
-char * th_vprintf_altfmt_oct(const char *buf, const size_t len, const int vret, const int flags)
-{
-    (void) vret;
-    (void) flags;
-    return (buf[len - 1] != '0') ? "0" : "";
-}
-
-
-char * th_vprintf_altfmt_hex(const char *buf, const size_t len, const int vret, const int flags)
-{
-    (void) buf;
-    (void) vret;
-    (void) len;
-    if (vret != 0)
-        return (flags & TH_PF_UPCASE) ? "0X" : "0x";
-    else
-        return "";
-}
-
-
-int th_vprintf_put_int_format(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
-    char *buf, int f_flags, int f_width, int f_prec, int f_len, int vret,
-    BOOL f_neg, BOOL f_unsig, char *(f_alt)(const char *buf, const size_t blen, const int vret, const int flags))
-{
-    int ret = 0, nwidth, nprec;
-    char f_sign, *f_altstr;
-
-    // Special case for value of 0
-    if (vret == 0)
-    {
-        if (f_flags & TH_PF_POINTER)
-        {
-            strcpy(buf, ")lin(");
-            f_len = 5;
-        }
-        else
-        if (f_prec != 0)
-        {
-            buf[f_len++] = '0';
-            buf[f_len] = 0;
-        }
-    }
-
-    // Get alternative format string, if needed and available
-    f_altstr = (f_flags & TH_PF_ALT) && f_alt != NULL ? f_alt(buf, f_len, vret, f_flags) : NULL;
-
-    // Are we using a sign prefix?
-    f_sign = f_unsig ? 0 : ((f_flags & TH_PF_SIGN) ?
-        (f_neg ? '-' : '+') :
-        (f_neg ? '-' : ((f_flags & TH_PF_SPACE) ? ' ' : 0)));
-
-    // Calculate necessary padding, etc
-    //
-    // << XXX TODO FIXME: The logic here is not very elegant, and it's incorrect
-    // at least for some alternate format modifier cases.
-    //
-
-    int nlen =  (f_sign ? 1 : 0) + (f_altstr ? strlen(f_altstr) : 0);
-    int qlen = (f_prec > f_len ? f_prec : f_len) + nlen;
-
-    if (f_flags & TH_PF_LEFT)
-        f_flags &= ~TH_PF_ZERO;
-
-    if (f_flags & TH_PF_POINTER && vret == 0)
-    {
-        PP_LINE("^");
-        qlen = f_len + nlen;
-        nwidth = f_width > qlen ? f_width - qlen : 0;
-        nprec = 0;
-    }
-    else
-    if ((f_flags & TH_PF_ZERO) && f_prec < 0 && f_width > 0)
-    {
-        PP_LINE("#");
-        nprec = f_width - qlen;
-        nwidth = 0;
-    }
-    else
-    {
-        PP_LINE("$");
-        nprec = (f_prec >= 0) ? f_prec - f_len : 0;
-        nwidth = (f_width >= 0) ? f_width - qlen : 0;
-    }
-
-    PP_PRINTF(": vret=%3d, f_flags=[%s], f_unsig=%d, f_sign='%c', f_len=%3d, f_width=%3d, f_prec=%3d, nwidth=%3d, nprec=%3d, qlen=%3d\n",
-        vret, get_flags(f_flags), f_unsig, f_sign ? f_sign : '?', f_len, f_width, f_prec, nwidth, nprec, qlen);
-
-    // << XXX TODO FIXME
-
-    // Prefix padding
-    if ((ret = th_printf_pad_pre(ctx, vputch, nwidth, f_flags)) == EOF)
-        return ret;
-
-    // Sign prefix
-    if (f_sign && (ret = vputch(ctx, f_sign)) == EOF)
-        return ret;
-
-    // Alternative format string
-    if (f_altstr && (ret = th_vprintf_put_pstr(ctx, vputch, f_altstr)) == EOF)
-        return ret;
-
-    // Zero padding
-    if (nprec > 0 && (ret = th_vprintf_put_repch(ctx, vputch, nprec, '0')) == EOF)
-        return ret;
-
-    // Output the value
-    while (f_len-- > 0)
-    {
-        if ((ret = vputch(ctx, buf[f_len])) == EOF)
-            return ret;
-    }
-
-    // Postfix padding?
-    return th_printf_pad_post(ctx, vputch, nwidth, f_flags);
-}
-
-
-int th_vprintf_put_int(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
-    va_list ap, const int f_radix, int f_flags, int f_width, int f_prec,
-    const BOOL f_unsig, char *(f_alt)(const char *buf, const size_t blen, const int vret, const int flags))
-{
-    char buf[64];
-    int f_len = 0, vret;
-    BOOL f_neg = FALSE;
-
-    if (f_flags & TH_PF_LONGLONG)
-    {
-        vret = th_vprintf_buf_int64(buf, sizeof(buf), &f_len, va_arg(ap, int64_t),
-            f_radix, f_flags & TH_PF_UPCASE, f_unsig, &f_neg);
-    }
-    else
-    {
-       vret = th_vprintf_buf_int(buf, sizeof(buf), &f_len, va_arg(ap, unsigned int),
-            f_radix, f_flags & TH_PF_UPCASE, f_unsig, &f_neg);
-    }
-
-    if (vret == EOF)
-        return 0;
-
-    return th_vprintf_put_int_format(ctx, vputch, buf, f_flags, f_width, f_prec, f_len, vret, f_neg, f_unsig, f_alt);
-}
-
-
-int th_vprintf_put_str(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
-    const char *str, int f_flags, const int f_width, const int f_prec)
-{
-    int nwidth, f_len, ret = 0;
-
-    // Check for null strings
-    if (str == NULL)
-        str = "(null)";
-
-    f_len = strlen(str);
-    if (f_prec >= 0 && f_len > f_prec)
-        f_len = f_prec;
-
-    nwidth = f_width - f_len;
-
-    // Prefix padding?
-    if ((ret = th_printf_pad_pre(ctx, vputch, nwidth, f_flags)) == EOF)
-        return ret;
-
-    while (*str && f_len--)
-    {
-        if ((ret = vputch(ctx, *str++)) == EOF)
-            return ret;
-    }
-
-    // Postfix padding?
-    return th_printf_pad_post(ctx, vputch, nwidth, f_flags);
-}
-
-
-#ifdef WIP_FLOAT_SUPPORT
-int th_vprintf_put_float(th_vprintf_ctx *ctx, th_vprintf_putch vputch,
-    va_list ap, int f_flags, int f_width, int f_prec)
-{
-    double pval = va_arg(ap, double);   // This needs to be double for type promotion to occur
-    int64_t val;
-
-    // This is a hack, trying to avoid dereferencing a type-punned
-    // pointer and all that stuff related to strict aliasing (although
-    // double and int64_t should be same size and have same aliasing rules.)
-    memcpy(&val, &pval, sizeof(int64_t));
-
-    // We have sign, exponent and mantissa
-    BOOL f_sign    = (val >> 63) & 0x01;
-    int64_t d_exp  = (val >> 52) & 0x7ff;
-    uint64_t d_man = val & 0x0fffffffffffff;
-
-    return 0;
-}
-#endif
-
-
-int th_vprintf_do(th_vprintf_ctx *ctx, th_vprintf_putch vputch, const char *fmt, va_list ap)
-{
-    int ret = 0;
-
-    while (*fmt)
-    {
-        if (*fmt != '%')
-        {
-            if ((ret = vputch(ctx, *fmt)) == EOF)
-                goto out;
-        }
-        else
-        {
-            int f_width = -1, f_prec = -1, f_flags = 0;
-            BOOL end = FALSE;
-
-            fmt++;
-
-            // Check for flags
-            while (!end)
-            {
-                switch (*fmt)
-                {
-                    case '#':
-                        f_flags |= TH_PF_ALT;
-                        break;
-
-                    case '+':
-                        f_flags |= TH_PF_SIGN;
-                        break;
-
-                    case '0':
-                        f_flags |= TH_PF_ZERO;
-                        break;
-
-                    case '-':
-                        f_flags |= TH_PF_LEFT;
-                        break;
-
-                    case ' ':
-                        f_flags |= TH_PF_SPACE;
-                        break;
-
-                    case '\'':
-                        f_flags |= TH_PF_GROUP;
-                        break;
-
-                    default:
-                        end = TRUE;
-                        break;
-                }
-                if (!end) fmt++;
-            }
-
-            // Get field width
-            if (*fmt == '*')
-            {
-                fmt++;
-                f_width = va_arg(ap, int);
-                if (f_width < 0)
-                {
-                    f_flags |= TH_PF_LEFT;
-                    f_width = -f_width;
-                }
-            }
-            else
-            {
-                f_width = 0;
-                while (th_isdigit(*fmt))
-                    f_width = f_width * 10 + (*fmt++ - '0');
-            }
-
-            // Check for field precision
-            if (*fmt == '.')
-            {
-                fmt++;
-                if (*fmt == '*')
-                {
-                    fmt++;
-                    f_prec = va_arg(ap, int);
-                }
-                else
-                {
-                    // If no digit after '.', precision is to be 0
-                    f_prec = 0;
-                    while (th_isdigit(*fmt))
-                        f_prec = f_prec * 10 + (*fmt++ - '0');
-                }
-            }
-
-
-            // Check for length modifiers (only some are supported currently)
-            switch (*fmt)
-            {
-                case 'l':
-                    if (*++fmt == 'l')
-                    {
-                        f_flags |= TH_PF_LONGLONG;
-                        fmt++;
-                    }
-                    else
-                        f_flags |= TH_PF_LONG;
-                    break;
-
-                case 'L':
-                    fmt++;
-                    f_flags |= TH_PF_LONGLONG;
-                    break;
-
-                case 'h':
-                case 'j':
-                case 'z':
-                case 't':
-                    return -202;
-            }
-
-            switch (*fmt)
-            {
-                case 0:
-                    return -104;
-
-                case 'c':
-                    if ((ret = th_printf_pad_pre(ctx, vputch, f_width - 1, f_flags)) == EOF)
-                        goto out;
-                    if ((ret = vputch(ctx, va_arg(ap, int))) == EOF)
-                        goto out;
-                    if ((ret = th_printf_pad_post(ctx, vputch, f_width - 1, f_flags)) == EOF)
-                        goto out;
-                    break;
-
-                case 'o':
-                    if ((ret = th_vprintf_put_int(ctx, vputch, ap, 8, f_flags, f_width, f_prec, TRUE, th_vprintf_altfmt_oct)) == EOF)
-                        goto out;
-                    break;
-
-                case 'u':
-                case 'i':
-                case 'd':
-                    if ((ret = th_vprintf_put_int(ctx, vputch, ap, 10, f_flags, f_width, f_prec, *fmt == 'u', NULL)) == EOF)
-                        goto out;
-                    break;
-
-                case 'x':
-                case 'X':
-                    if (*fmt == 'X')
-                        f_flags |= TH_PF_UPCASE;
-                    if ((ret = th_vprintf_put_int(ctx, vputch, ap, 16, f_flags, f_width, f_prec, TRUE, th_vprintf_altfmt_hex)) == EOF)
-                        goto out;
-                    break;
-
-                case 'p':
-                    if (f_flags & (TH_PF_LONG | TH_PF_LONGLONG))
-                        return -120;
-
-#if (TH_PTRSIZE == 32)
-                    f_flags |= TH_PF_LONG;
-#elif (TH_PTRSIZE == 64)
-                    f_flags |= TH_PF_LONGLONG;
-#endif
-                    f_flags |= TH_PF_ALT | TH_PF_POINTER;
-                    if ((ret = th_vprintf_put_int(ctx, vputch, ap, 16, f_flags, f_width, f_prec, TRUE, th_vprintf_altfmt_hex)) == EOF)
-                        goto out;
-                    break;
-
-#ifdef WIP_FLOAT_SUPPORT
-                case 'f':
-                case 'F':
-                    if ((ret = th_vprintf_put_float(ctx, vputch, ap,
-                        f_flags, f_width, f_prec)) == EOF)
-                        goto out;
-                    break;
-#endif
-
-                case 's':
-                    if ((ret = th_vprintf_put_str(ctx, vputch, va_arg(ap, char *),
-                        f_flags, f_width, f_prec)) == EOF)
-                        goto out;
-                    break;
-
-                //case '%':
-                default:
-                    if ((ret = vputch(ctx, *fmt)) == EOF)
-                        goto out;
-                    break;
-            }
-        }
-        fmt++;
-    }
-
-out:
-    return ret == EOF ? ret : ctx->ipos;
-}
-
-
 #ifdef TH_USE_INTERNAL_SPRINTF
 static int th_pbuf_vputch(th_vprintf_ctx *ctx, const char ch)
 {