enhanced xprintf

This commit is contained in:
hyung-hwan 2013-10-16 15:32:51 +00:00
parent b70e378041
commit 35e9b1777f
3 changed files with 150 additions and 89 deletions

View File

@ -481,6 +481,12 @@ typedef qse_int_t qse_intptr_t;
# define QSE_SIZEOF_FLTMAX_T QSE_SIZEOF_FLT_T # define QSE_SIZEOF_FLTMAX_T QSE_SIZEOF_FLT_T
#endif #endif
/** @typedef qse_ptrdiff_t
*/
typedef qse_ssize_t qse_ptrdiff_t;
#define QSE_SIZEOF_PTRDIFF_T QSE_SIZEOF_SSIZE_T
/** /**
* The qse_mchar_t type defines a multi-byte character type. * The qse_mchar_t type defines a multi-byte character type.
*/ */

View File

@ -40,10 +40,11 @@ enum
LF_J = (1 << 2), LF_J = (1 << 2),
LF_L = (1 << 3), LF_L = (1 << 3),
LF_Q = (1 << 4), LF_Q = (1 << 4),
LF_Z = (1 << 5), LF_T = (1 << 5),
LF_Z = (1 << 6),
/* long double */ /* long double */
LF_LD = (1 << 6) LF_LD = (1 << 7)
}; };
static struct static struct
@ -71,7 +72,7 @@ static struct
{ LF_Q, 0 }, /* q */ { LF_Q, 0 }, /* q */
{ 0, 0 }, /* r */ { 0, 0 }, /* r */
{ 0, 0 }, /* s */ { 0, 0 }, /* s */
{ 0, 0 }, /* t */ { LF_T, 0 }, /* t */
{ 0, 0 }, /* u */ { 0, 0 }, /* u */
{ 0, 0 }, /* v */ { 0, 0 }, /* v */
{ 0, 0 }, /* w */ { 0, 0 }, /* w */
@ -97,6 +98,10 @@ enum
}; };
#include <stdio.h> /* TODO: remove dependency on this */ #include <stdio.h> /* TODO: remove dependency on this */
#if defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1200))
# define snprintf _snprintf
# define vsnprintf _vsnprintf
#endif
static int put_wchar (qse_wchar_t c, void *arg) static int put_wchar (qse_wchar_t c, void *arg)
{ {
@ -186,8 +191,7 @@ int qse_mvprintf (const char_t* fmt, va_list ap)
#define sprintn w_sprintn #define sprintn w_sprintn
#define xprintf qse_wxprintf #define xprintf qse_wxprintf
static const qse_wchar_t w_hex2ascii[] = static const qse_wchar_t w_hex2ascii[] = QSE_WT("0123456789abcdefghijklmnopqrstuvwxyz");
QSE_WT("0123456789abcdefghijklmnopqrstuvwxyz");
#define hex2ascii(hex) (w_hex2ascii[hex]) #define hex2ascii(hex) (w_hex2ascii[hex])
#include "printf.h" #include "printf.h"

View File

@ -87,15 +87,15 @@ static char_t* sprintn (char_t* nbuf, qse_uintmax_t num, int base, int *lenp, in
/* TODO: error check */ /* TODO: error check */
#define PUT_CHAR(c) do { \ #define PUT_CHAR(c) do { \
if (put_char (c, arg) <= -1) goto oops; \ if (put_char (c, arg) <= -1) goto oops; \
retval++; \ outcnt++; \
} while (0) } while (0)
#define PUT_OCHAR(c) do { \ #define PUT_OCHAR(c) do { \
if (put_ochar (c, arg) <= -1) goto oops; \ if (put_ochar (c, arg) <= -1) goto oops; \
retval++; \ outcnt++; \
} while (0) } while (0)
int xprintf (char_t const *fmt, int (*put_char)(char_t, void*), int (*put_ochar) (ochar_t, void*), void *arg, va_list ap) int xprintf (const char_t* fmt, int (*put_char)(char_t, void*), int (*put_ochar) (ochar_t, void*), void *arg, va_list ap)
{ {
char_t nbuf[MAXNBUF]; char_t nbuf[MAXNBUF];
const char_t* p, * percent; const char_t* p, * percent;
@ -105,18 +105,34 @@ int xprintf (char_t const *fmt, int (*put_char)(char_t, void*), int (*put_ochar)
ochar_t oach, opadc, * osp; ochar_t oach, opadc, * osp;
int lm_flag, lm_dflag, flagc, numlen; int lm_flag, lm_dflag, flagc, numlen;
qse_uintmax_t num = 0; qse_uintmax_t num = 0;
int stop = 0, retval = 0; int stop = 0;
char_t fltbuf[100]; int outcnt = 0;
qse_mchar_t fltfmt[64]; struct
qse_mchar_t* fltfmtp = QSE_NULL; {
qse_size_t fltfmtc; qse_mchar_t sbuf[32];
qse_mchar_t* ptr;
qse_size_t capa;
} fltfmt;
struct
{
char_t sbuf[96];
char_t* ptr;
qse_size_t capa;
} fltout;
fltfmt.ptr = fltfmt.sbuf;
fltfmt.capa = QSE_COUNTOF(fltfmt.sbuf) - 1;
fltout.ptr = fltout.sbuf;
fltout.capa = QSE_COUNTOF(fltout.sbuf) - 1;
while (1) while (1)
{ {
while ((ch = (uchar_t)*fmt++) != T('%') || stop) while ((ch = (uchar_t)*fmt++) != T('%') || stop)
{ {
if (ch == T('\0')) return retval; if (ch == T('\0')) goto done;
PUT_CHAR(ch); PUT_CHAR(ch);
} }
percent = fmt - 1; percent = fmt - 1;
@ -248,9 +264,7 @@ reswitch:
case T('q'): /* long long int */ case T('q'): /* long long int */
case T('j'): /* uintmax_t */ case T('j'): /* uintmax_t */
case T('z'): /* size_t */ case T('z'): /* size_t */
#if 0
case T('t'): /* ptrdiff_t */ case T('t'): /* ptrdiff_t */
#endif
if (lm_flag & LF_LD) goto invalid_format; if (lm_flag & LF_LD) goto invalid_format;
flagc |= FLAGC_LENMOD; flagc |= FLAGC_LENMOD;
@ -293,31 +307,28 @@ reswitch:
/* end of length modifiers */ /* end of length modifiers */
case T('n'): case T('n'):
if (lm_flag & LF_J) if (lm_flag & LF_J) /* j */
*(va_arg(ap, qse_intmax_t*)) = retval; *(va_arg(ap, qse_intmax_t*)) = outcnt;
else if (lm_flag & LF_Z) /* z */
*(va_arg(ap, qse_size_t*)) = outcnt;
#if (QSE_SIZEOF_LONG_LONG > 0) #if (QSE_SIZEOF_LONG_LONG > 0)
else if (lm_flag & LF_Q) else if (lm_flag & LF_Q) /* ll */
*(va_arg(ap, long long int*)) = retval; *(va_arg(ap, long long int*)) = outcnt;
#endif #endif
else if (lm_flag & LF_L) else if (lm_flag & LF_L) /* l */
*(va_arg(ap, long int*)) = retval; *(va_arg(ap, long int*)) = outcnt;
else if (lm_flag & LF_Z) else if (lm_flag & LF_H) /* h */
*(va_arg(ap, qse_size_t*)) = retval; *(va_arg(ap, short int*)) = outcnt;
else if (lm_flag & LF_H) else if (lm_flag & LF_C) /* hh */
*(va_arg(ap, short int*)) = retval; *(va_arg(ap, char*)) = outcnt;
else if (lm_flag & LF_C)
*(va_arg(ap, char*)) = retval;
else else
*(va_arg(ap, int*)) = retval; *(va_arg(ap, int*)) = outcnt;
break; break;
/* signed integer conversions */ /* signed integer conversions */
case T('d'): case T('d'):
case T('i'): /* signed conversion */ case T('i'): /* signed conversion */
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 10; base = 10;
sign = 1; sign = 1;
goto handle_sign; goto handle_sign;
@ -325,31 +336,19 @@ reswitch:
/* unsigned integer conversions */ /* unsigned integer conversions */
case T('o'): case T('o'):
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 8; base = 8;
goto handle_nosign; goto handle_nosign;
case T('u'): case T('u'):
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 10; base = 10;
goto handle_nosign; goto handle_nosign;
case T('X'): case T('X'):
upper = 1; upper = 1;
case T('x'): case T('x'):
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 16; base = 16;
goto handle_nosign; goto handle_nosign;
/* end of unsigned integer conversions */ /* end of unsigned integer conversions */
case T('p'): /* pointer */ case T('p'): /* pointer */
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 16; base = 16;
if (width == 0) flagc |= FLAGC_SHARP; if (width == 0) flagc |= FLAGC_SHARP;
@ -470,37 +469,89 @@ reswitch:
case T('A'): case T('A'):
*/ */
{ {
qse_mchar_t tmpbuf[100]; /* let me rely on snprintf until i implement
qse_mchar_t* tmpbufp; * float-point to string conversion */
const char_t* xx;
const qse_mchar_t* yy;
int q; int q;
qse_size_t fmtlen;
qse_fltmax_t v_fltmax;
long double v_ld;
double v_d;
#if defined(NO_MERCY) if (lm_flag & LF_J)
if (lm_flag & ~LF_LD) goto invalid_format; v_fltmax = va_arg (ap, qse_fltmax_t);
#endif else if (lm_flag & (LF_LD | LF_L | LF_Q | LF_Z))
v_ld = va_arg (ap, long double);
if (fmt - percent < QSE_COUNTOF(fltfmt))
{
fltfmtp = fltfmt;
}
else else
v_d = va_arg (ap, double);
fmtlen = fmt - percent;
if (fmtlen > fltfmt.capa)
{ {
fltfmtp = QSE_MMGR_ALLOC (QSE_MMGR_GETDFL(), QSE_SIZEOF(*fltfmtp) * (fmt - percent + 1)); if (fltfmt.ptr == fltfmt.sbuf)
if (fltfmtp == QSE_NULL) goto oops; {
fltfmt.ptr = QSE_MMGR_ALLOC (QSE_MMGR_GETDFL(), QSE_SIZEOF(*fltfmt.ptr) * (fmtlen + 1));
if (fltfmt.ptr == QSE_NULL) goto oops;
}
else
{
qse_mchar_t* tmpptr;
tmpptr = QSE_MMGR_REALLOC (QSE_MMGR_GETDFL(), fltfmt.ptr, QSE_SIZEOF(*fltfmt.ptr) * (fmtlen + 1));
if (tmpptr == QSE_NULL) goto oops;
fltfmt.ptr = tmpptr;
}
fltfmt.capa = fmtlen;
} }
for (xx = percent, q = 0; xx < fmt; xx++) fltfmtp[q++] = *xx;
fltfmtp[q] = QSE_MT('\0');
if (lm_flag & LF_LD) fltfmt.ptr[fmtlen] = QSE_MT('\0');
snprintf (tmpbuf, QSE_SIZEOF(tmpbuf), fltfmtp, va_arg (ap, long double)); while (fmtlen > 0)
else {
snprintf (tmpbuf, QSE_SIZEOF(tmpbuf), fltfmtp, va_arg (ap, double)); fmtlen--;
fltfmt.ptr[fmtlen] = percent[fmtlen];
}
for (yy = tmpbuf, q = 0; *yy; ) fltbuf[q++] = *yy++; while (1)
fltbuf[q] = QSE_T('\0'); {
sp = fltbuf; qse_size_t newcapa;
if (lm_flag & LF_J)
q = snprintf ((qse_mchar_t*)fltout.ptr, fltout.capa + 1, fltfmt.ptr, v_fltmax);
else if (lm_flag & (LF_LD | LF_L | LF_Q | LF_Z))
q = snprintf ((qse_mchar_t*)fltout.ptr, fltout.capa + 1, fltfmt.ptr, v_ld);
else
q = snprintf ((qse_mchar_t*)fltout.ptr, fltout.capa + 1, fltfmt.ptr, v_d);
if (q <= -1) goto oops;
if (q <= fltout.capa) break;
newcapa = fltout.capa * 2;
if (fltout.ptr == fltout.sbuf)
{
fltout.ptr = QSE_MMGR_ALLOC (QSE_MMGR_GETDFL(), QSE_SIZEOF(char_t) * (newcapa + 1));
if (fltout.ptr == QSE_NULL) goto oops;
}
else
{
char_t* tmpptr;
tmpptr = QSE_MMGR_REALLOC (QSE_MMGR_GETDFL(), fltout.ptr, QSE_SIZEOF(char_t) * (newcapa + 1));
if (tmpptr == QSE_NULL) goto oops;
fltout.ptr = tmpptr;
}
fltout.capa = newcapa;
}
if (QSE_SIZEOF(char_t) != QSE_SIZEOF(qse_mchar_t))
{
fltout.ptr[q] = T('\0');
while (q > 0)
{
q--;
fltout.ptr[q] = ((qse_mchar_t*)fltout.ptr)[q];
}
}
sp = fltout.ptr;
flagc &= ~FLAGC_DOT; flagc &= ~FLAGC_DOT;
width = 0; width = 0;
precision = 0; precision = 0;
@ -532,20 +583,16 @@ handle_nosign:
num = va_arg (ap, qse_uintmax_t); num = va_arg (ap, qse_uintmax_t);
#endif #endif
} }
else if (lm_flag & LF_T)
num = va_arg (ap, qse_ptrdiff_t);
else if (lm_flag & LF_Z)
num = va_arg (ap, qse_size_t);
#if (QSE_SIZEOF_LONG_LONG > 0) #if (QSE_SIZEOF_LONG_LONG > 0)
else if (lm_flag & LF_Q) else if (lm_flag & LF_Q)
num = va_arg (ap, unsigned long long int); num = va_arg (ap, unsigned long long int);
#endif #endif
else if (lm_flag & (LF_L | LF_LD))
#if 0
else if (lm_flag & LF_T)
num = va_arg (ap, ptrdiff_t);
#endif
else if (lm_flag & LF_L)
num = va_arg (ap, long int); num = va_arg (ap, long int);
else if (lm_flag & LF_Z)
num = va_arg (ap, qse_size_t);
else if (lm_flag & LF_H) else if (lm_flag & LF_H)
num = (unsigned short int)va_arg (ap, int); num = (unsigned short int)va_arg (ap, int);
else if (lm_flag & LF_C) else if (lm_flag & LF_C)
@ -579,19 +626,16 @@ handle_sign:
#endif #endif
} }
else if (lm_flag & LF_T)
num = va_arg(ap, qse_ptrdiff_t);
else if (lm_flag & LF_Z)
num = va_arg (ap, qse_ssize_t);
#if (QSE_SIZEOF_LONG_LONG > 0) #if (QSE_SIZEOF_LONG_LONG > 0)
else if (lm_flag & LF_Q) else if (lm_flag & LF_Q)
num = va_arg (ap, long long int); num = va_arg (ap, long long int);
#endif #endif
else if (lm_flag & (LF_L | LF_LD))
#if 0
else if (lm_flag & LF_T)
num = va_arg(ap, ptrdiff_t);
#endif
else if (lm_flag & LF_L)
num = va_arg (ap, long int); num = va_arg (ap, long int);
else if (lm_flag & LF_Z)
num = va_arg (ap, qse_ssize_t);
else if (lm_flag & LF_H) else if (lm_flag & LF_H)
num = (short int)va_arg (ap, int); num = (short int)va_arg (ap, int);
else if (lm_flag & LF_C) else if (lm_flag & LF_C)
@ -684,11 +728,18 @@ invalid_format:
} }
} }
done:
if (fltfmt.ptr != fltfmt.sbuf)
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), fltfmt.ptr);
if (fltout.ptr != fltout.sbuf)
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), fltout.ptr);
return outcnt;
oops: oops:
if (fltfmtp && fltfmtp != fltfmt) if (fltfmt.ptr != fltfmt.sbuf)
{ QSE_MMGR_FREE (QSE_MMGR_GETDFL(), fltfmt.ptr);
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), fltfmtp); if (fltout.ptr != fltout.sbuf)
} QSE_MMGR_FREE (QSE_MMGR_GETDFL(), fltout.ptr);
return -1; return -1;
} }
#undef PUT_CHAR #undef PUT_CHAR