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
#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.
*/

View File

@ -40,10 +40,11 @@ enum
LF_J = (1 << 2),
LF_L = (1 << 3),
LF_Q = (1 << 4),
LF_Z = (1 << 5),
LF_T = (1 << 5),
LF_Z = (1 << 6),
/* long double */
LF_LD = (1 << 6)
LF_LD = (1 << 7)
};
static struct
@ -71,7 +72,7 @@ static struct
{ LF_Q, 0 }, /* q */
{ 0, 0 }, /* r */
{ 0, 0 }, /* s */
{ 0, 0 }, /* t */
{ LF_T, 0 }, /* t */
{ 0, 0 }, /* u */
{ 0, 0 }, /* v */
{ 0, 0 }, /* w */
@ -97,6 +98,10 @@ enum
};
#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)
{
@ -186,8 +191,7 @@ int qse_mvprintf (const char_t* fmt, va_list ap)
#define sprintn w_sprintn
#define xprintf qse_wxprintf
static const qse_wchar_t w_hex2ascii[] =
QSE_WT("0123456789abcdefghijklmnopqrstuvwxyz");
static const qse_wchar_t w_hex2ascii[] = QSE_WT("0123456789abcdefghijklmnopqrstuvwxyz");
#define hex2ascii(hex) (w_hex2ascii[hex])
#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 */
#define PUT_CHAR(c) do { \
if (put_char (c, arg) <= -1) goto oops; \
retval++; \
outcnt++; \
} while (0)
#define PUT_OCHAR(c) do { \
if (put_ochar (c, arg) <= -1) goto oops; \
retval++; \
outcnt++; \
} 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];
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;
int lm_flag, lm_dflag, flagc, numlen;
qse_uintmax_t num = 0;
int stop = 0, retval = 0;
char_t fltbuf[100];
int stop = 0;
int outcnt = 0;
qse_mchar_t fltfmt[64];
qse_mchar_t* fltfmtp = QSE_NULL;
qse_size_t fltfmtc;
struct
{
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 ((ch = (uchar_t)*fmt++) != T('%') || stop)
{
if (ch == T('\0')) return retval;
if (ch == T('\0')) goto done;
PUT_CHAR(ch);
}
percent = fmt - 1;
@ -248,9 +264,7 @@ reswitch:
case T('q'): /* long long int */
case T('j'): /* uintmax_t */
case T('z'): /* size_t */
#if 0
case T('t'): /* ptrdiff_t */
#endif
if (lm_flag & LF_LD) goto invalid_format;
flagc |= FLAGC_LENMOD;
@ -293,31 +307,28 @@ reswitch:
/* end of length modifiers */
case T('n'):
if (lm_flag & LF_J)
*(va_arg(ap, qse_intmax_t*)) = retval;
if (lm_flag & LF_J) /* j */
*(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)
else if (lm_flag & LF_Q)
*(va_arg(ap, long long int*)) = retval;
else if (lm_flag & LF_Q) /* ll */
*(va_arg(ap, long long int*)) = outcnt;
#endif
else if (lm_flag & LF_L)
*(va_arg(ap, long int*)) = retval;
else if (lm_flag & LF_Z)
*(va_arg(ap, qse_size_t*)) = retval;
else if (lm_flag & LF_H)
*(va_arg(ap, short int*)) = retval;
else if (lm_flag & LF_C)
*(va_arg(ap, char*)) = retval;
else if (lm_flag & LF_L) /* l */
*(va_arg(ap, long int*)) = outcnt;
else if (lm_flag & LF_H) /* h */
*(va_arg(ap, short int*)) = outcnt;
else if (lm_flag & LF_C) /* hh */
*(va_arg(ap, char*)) = outcnt;
else
*(va_arg(ap, int*)) = retval;
*(va_arg(ap, int*)) = outcnt;
break;
/* signed integer conversions */
case T('d'):
case T('i'): /* signed conversion */
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 10;
sign = 1;
goto handle_sign;
@ -325,31 +336,19 @@ reswitch:
/* unsigned integer conversions */
case T('o'):
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 8;
goto handle_nosign;
case T('u'):
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 10;
goto handle_nosign;
case T('X'):
upper = 1;
case T('x'):
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 16;
goto handle_nosign;
/* end of unsigned integer conversions */
case T('p'): /* pointer */
#if defined(NO_MERCY)
if (lm_flag & LF_LD) goto invalid_format;
#endif
base = 16;
if (width == 0) flagc |= FLAGC_SHARP;
@ -470,37 +469,89 @@ reswitch:
case T('A'):
*/
{
qse_mchar_t tmpbuf[100];
qse_mchar_t* tmpbufp;
const char_t* xx;
const qse_mchar_t* yy;
/* let me rely on snprintf until i implement
* float-point to string conversion */
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_LD) goto invalid_format;
#endif
if (fmt - percent < QSE_COUNTOF(fltfmt))
{
fltfmtp = fltfmt;
}
if (lm_flag & LF_J)
v_fltmax = va_arg (ap, qse_fltmax_t);
else if (lm_flag & (LF_LD | LF_L | LF_Q | LF_Z))
v_ld = va_arg (ap, long double);
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 (fltfmtp == QSE_NULL) goto oops;
if (fltfmt.ptr == fltfmt.sbuf)
{
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)
snprintf (tmpbuf, QSE_SIZEOF(tmpbuf), fltfmtp, va_arg (ap, long double));
else
snprintf (tmpbuf, QSE_SIZEOF(tmpbuf), fltfmtp, va_arg (ap, double));
fltfmt.ptr[fmtlen] = QSE_MT('\0');
while (fmtlen > 0)
{
fmtlen--;
fltfmt.ptr[fmtlen] = percent[fmtlen];
}
for (yy = tmpbuf, q = 0; *yy; ) fltbuf[q++] = *yy++;
fltbuf[q] = QSE_T('\0');
sp = fltbuf;
while (1)
{
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;
width = 0;
precision = 0;
@ -532,20 +583,16 @@ handle_nosign:
num = va_arg (ap, qse_uintmax_t);
#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)
else if (lm_flag & LF_Q)
num = va_arg (ap, unsigned long long int);
#endif
#if 0
else if (lm_flag & LF_T)
num = va_arg (ap, ptrdiff_t);
#endif
else if (lm_flag & LF_L)
else if (lm_flag & (LF_L | LF_LD))
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)
num = (unsigned short int)va_arg (ap, int);
else if (lm_flag & LF_C)
@ -579,19 +626,16 @@ handle_sign:
#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)
else if (lm_flag & LF_Q)
num = va_arg (ap, long long int);
#endif
#if 0
else if (lm_flag & LF_T)
num = va_arg(ap, ptrdiff_t);
#endif
else if (lm_flag & LF_L)
else if (lm_flag & (LF_L | LF_LD))
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)
num = (short int)va_arg (ap, int);
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:
if (fltfmtp && fltfmtp != fltfmt)
{
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), fltfmtp);
}
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 -1;
}
#undef PUT_CHAR