Mercurial > hg > th-libs
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, ...);