Mercurial > hg > th-libs
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) {