changeset 228:ca9cd98dbcff

Initial work on printf() style function family implementation.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 16 Feb 2016 13:59:51 +0200
parents 5f9de1d542ee
children 38a0719359ef
files th_string.c th_string.h
diffstat 2 files changed, 278 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/th_string.c	Tue Feb 16 12:02:17 2016 +0200
+++ b/th_string.c	Tue Feb 16 13:59:51 2016 +0200
@@ -108,6 +108,272 @@
 }
 
 
+/* Simple implementations of printf() type functions
+ */
+static int th_vput_itoa(void *ctx, int (*vputch)(void *ctx, const char ch), int val, int radix, char padMode, int width, BOOL unsig, BOOL upcase, BOOL sign)
+{
+    char buf[64];
+    size_t pos = 0;
+    BOOL neg = FALSE;
+    int ret = 0;
+
+    if (radix > 16)
+        return 0;
+
+    if (val < 0)
+    {
+        neg = TRUE;
+        val = -val;
+    }
+
+    do
+    {
+        int digit = val % radix;
+        if (digit < 10)
+            buf[pos] = '0' + digit;
+        else
+            buf[pos] = (upcase ? 'A' : 'a') + digit - 10;
+        val /= radix;
+        pos++;
+    }
+    while (val > 0 && pos < sizeof(buf) - 1);
+    buf[pos] = 0;
+
+    if (!unsig)
+    {
+        char ch = sign ? (neg ? '-' : '+') : (neg ? '-' : 0);
+        if (ch && (ret = vputch(ctx, ch)) == EOF)
+            goto out;
+    }
+
+    int nwidth = width - pos;
+
+    if (nwidth > 0 && padMode != '-')
+    {
+        while (nwidth--)
+            if ((ret = vputch(ctx, padMode)) == EOF)
+                goto out;
+    }
+
+    while (pos--)
+    {
+        if ((ret = vputch(ctx, buf[pos])) == EOF)
+            goto out;
+    }
+
+    if (nwidth > 0 && padMode == '-')
+    {
+        while (nwidth--)
+            if ((ret = vputch(ctx, ' ')) == EOF)
+                goto out;
+    }
+
+out:
+    return ret;
+}
+
+
+static int th_vput_str(void *ctx, int (*vputch)(void *ctx, const char ch), const char *str, char padMode, int width)
+{
+    int nwidth = width - strlen(str);
+    int ret = 0;
+
+    if (nwidth > 0 && padMode != '-')
+    {
+        while (nwidth--)
+            if ((ret = vputch(ctx, padMode)) == EOF)
+                goto out;
+    }
+
+    while (*str)
+    {
+        if ((ret = vputch(ctx, *str++)) == EOF)
+            goto out;
+    }
+
+    if (nwidth > 0 && padMode == '-')
+    {
+        while (nwidth--)
+            if ((ret = vputch(ctx, ' ')) == EOF)
+                goto out;
+    }
+
+out:
+    return ret;
+}
+
+
+int th_vprintf_do(void *ctx, int (*vputch)(void *ctx, const char ch), const char *fmt, va_list ap)
+{
+    int ret;
+
+    while (*fmt)
+    {
+        if (*fmt != '%')
+        {
+            if ((ret = vputch(ctx, *fmt)) == EOF)
+                return ret;
+        }
+        else
+        {
+            char padMode = ' ', padChar = 0;
+            BOOL sign = FALSE;
+            int width = 0;
+
+            fmt++;
+
+            if (*fmt == '+')
+            {
+                sign = TRUE;
+                fmt++;
+            }
+
+            if (*fmt == '0' || *fmt == '-' || *fmt == '\'')
+            {
+                padMode = *fmt++;
+                if (padMode == '\'')
+                {
+                    padChar = *fmt++;
+                    if (*fmt != '\'')
+                        goto out;
+                    fmt++;
+                }
+
+                if (*fmt == 0)
+                    goto out;
+            }
+
+            while (th_isdigit(*fmt))
+                width = width * 10 + (*fmt++ - '0');
+
+            switch (*fmt)
+            {
+                case '%':
+                    vputch(ctx, *fmt);
+                    break;
+
+                case 0:
+                    goto out;
+
+                case 'u':
+                case 'd':
+                    if (padMode != '0' && padMode != '-' && padMode != ' ')
+                        goto out;
+
+                    if ((ret = th_vput_itoa(ctx, vputch, va_arg(ap, unsigned int), 10, padMode, width, *fmt == 'u', FALSE, sign)) == EOF)
+                        goto out;
+                    break;
+
+                case 'x':
+                case 'X':
+                    if (padMode != '0' && padMode != '-' && padMode != ' ')
+                        goto out;
+
+                    if ((ret = th_vput_itoa(ctx, vputch, va_arg(ap, unsigned int), 16, padMode, width, TRUE, *fmt == 'X', FALSE)) == EOF)
+                        goto out;
+                    break;
+
+                case 'f':
+                    goto out;
+
+                case 's':
+                    if (padMode != '-' && padMode != ' ')
+                        goto out;
+
+                    if ((ret = th_vput_str(ctx, vputch, va_arg(ap, char *), padMode, width)) == EOF)
+                        goto out;
+                    break;
+
+                default:
+                    vputch(ctx, *fmt);
+                    break;
+            }
+        }
+        fmt++;
+    }
+out:
+    return ret;
+}
+
+
+typedef struct
+{
+    char *buf;
+    size_t size, pos;
+} th_pbuf_ctx;
+
+
+static int th_pbuf_vputch(void *pctx, const char ch)
+{
+    th_pbuf_ctx *ctx = (th_pbuf_ctx *) pctx;
+    if (ctx->pos < ctx->size)
+        ctx->buf[ctx->pos] = ch;
+    ctx->pos++;
+    return ch;
+}
+
+
+int th_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
+{
+#ifdef TH_USE_INTERNAL_SPRINTF
+    th_pbuf_ctx ctx;
+    ctx.buf = buf;
+    ctx.size = size;
+    ctx.pos = 0;
+
+    return th_vprintf_do((void *) &ctx, th_pbuf_vputch, fmt, ap);
+#else
+    return vsnpintf(buf, size, fmt, ap);
+#endif
+}
+
+
+int th_snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+    int n;
+    va_list ap;
+    va_start(ap, fmt);
+#ifdef TH_USE_INTERNAL_SPRINTF
+    n = th_vsnprintf(buf, size, fmt, ap);
+#else
+    n = vsnprintf(buf, size, fmt, ap);
+#endif
+    va_end(ap);
+    return n;
+}
+
+
+static int th_stdio_vputch(void *ctx, const char ch)
+{
+    return fputc(ch, (FILE *) ctx);
+}
+
+
+int th_vfprintf(FILE *fh, const char *fmt, va_list ap)
+{
+#ifdef TH_USE_INTERNAL_SPRINTF
+    return th_vprintf_do((void *) fh, th_stdio_vputch, fmt, ap);
+#else
+    return vfprintf(fh, fmt, ap);
+#endif
+}
+
+
+int th_fprintf(FILE *fh, const char *fmt, ...)
+{
+    int ret;
+    va_list ap;
+    va_start(ap, fmt);
+#ifdef TH_USE_INTERNAL_SPRINTF
+    ret = th_vprintf_do((void *) fh, th_stdio_vputch, fmt, ap);
+#else
+    ret = fprintf(fh, fmt, ap);
+#endif
+    va_end(ap);
+    return ret;
+}
+
+
 /* Simulate a sprintf() that allocates memory
  */
 char *th_strdup_vprintf(const char *fmt, va_list args)
@@ -123,7 +389,11 @@
         int n;
         va_list ap;
         va_copy(ap, args);
+#ifdef TH_USE_INTERNAL_SPRINTF
+        n = th_vsnprintf(buf, size, fmt, ap);
+#else
         n = vsnprintf(buf, size, fmt, ap);
+#endif
         va_end(ap);
 
         if (n > -1 && n < size)
@@ -232,7 +502,7 @@
     const size_t
         slen = strlen(str),
         nlen = strlen(needle);
-    
+
     if (slen < nlen)
         return NULL;
 
--- a/th_string.h	Tue Feb 16 12:02:17 2016 +0200
+++ b/th_string.h	Tue Feb 16 13:59:51 2016 +0200
@@ -60,6 +60,13 @@
 char    *th_strrcasecmp(char *haystack, const char *needle);
 void    th_strip_ctrlchars(char *str);
 
+int     th_vprintf_do(void *ctx, int (*vputch)(void *ctx, const char ch), const char *fmt, va_list ap);
+int     th_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap);
+int     th_snprintf(char *buf, size_t size, const char *fmt, ...);
+int     th_vfprintf(FILE *fh, const char *fmt, va_list ap);
+int     th_fprintf(FILE *fh, const char *fmt, ...);
+
+
 char    *th_strdup_vprintf(const char *fmt, va_list ap);
 char    *th_strdup_printf(const char *fmt, ...);