added some code to format floating-point numbers

This commit is contained in:
hyung-hwan 2013-10-15 16:35:23 +00:00
parent 99ac89fc57
commit b70e378041
6 changed files with 339 additions and 426 deletions

View File

@ -291,6 +291,14 @@ QSE_EXPORT int qse_fmtuintmaxtowcs (
# define qse_fmtuintmax(b,sz,v,bf,pr,fc,pf) qse_fmtuintmaxtowcs(b,sz,v,bf,pr,fc,pf) # define qse_fmtuintmax(b,sz,v,bf,pr,fc,pf) qse_fmtuintmaxtowcs(b,sz,v,bf,pr,fc,pf)
#endif #endif
QSE_EXPORT int qse_fmtfltmaxtombs (
qse_mchar_t* buf,
qse_size_t bufsize,
qse_fltmax_t f,
qse_mchar_t point,
int digits
);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -454,7 +454,7 @@ typedef qse_int_t qse_intptr_t;
/** @typedef qse_flt_t /** @typedef qse_flt_t
* The qse_flt_t type defines the largest floating-pointer number type * The qse_flt_t type defines the largest floating-pointer number type
* supported. * naturally supported.
*/ */
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
/* TODO: check if the support for long double is complete. /* TODO: check if the support for long double is complete.
@ -469,16 +469,17 @@ typedef qse_int_t qse_intptr_t;
# define QSE_SIZEOF_FLT_T QSE_SIZEOF_DOUBLE # define QSE_SIZEOF_FLT_T QSE_SIZEOF_DOUBLE
#endif #endif
/* TODO: qse_fltmax_t to include the quadruple precision floating-point type. /** @typedef qse_fltmax_t
* * The qse_fltmax_t type defines the largest floating-pointer number type
#if QSE_SIZEOF___FLOAT128 > 0 * ever supported.
*/
#if QSE_SIZEOF__FLOAT128 > QSE_SIZEOF_FLT_T
typedef __float128 qse_fltmax_t; typedef __float128 qse_fltmax_t;
# define QSE_SIZEOF_FLTMAX_T QSE_SIZEOF___FLOAT128 # define QSE_SIZEOF_FLTMAX_T QSE_SIZEOF___FLOAT128
#else #else
typedef qse_flt_t qse_fltmax_t; typedef qse_flt_t qse_fltmax_t;
# define QSE_SIZEOF_FLTMAX_T QSE_SIZEOF_FLT_T # define QSE_SIZEOF_FLTMAX_T QSE_SIZEOF_FLT_T
#endif #endif
*/
/** /**
* The qse_mchar_t type defines a multi-byte character type. * The qse_mchar_t type defines a multi-byte character type.

View File

@ -21,210 +21,30 @@
#include <qse/cmn/fmt.h> #include <qse/cmn/fmt.h>
#include <qse/cmn/str.h> #include <qse/cmn/str.h>
#undef T
#undef char_t
#undef fmt_uintmax
#undef strlen
#define T(x) QSE_MT(x)
#define char_t qse_mchar_t
#define fmt_uintmax fmt_unsigned_to_mbs
#define strlen(x) qse_mbslen(x)
#include "fmt.h"
#undef T
#undef char_t
#undef fmt_uintmax
#undef strlen
#define T(x) QSE_WT(x)
#define char_t qse_wchar_t
#define fmt_uintmax fmt_unsigned_to_wcs
#define strlen(x) qse_wcslen(x)
#include "fmt.h"
/* ==================== multibyte ===================================== */ /* ==================== multibyte ===================================== */
static int fmt_unsigned_to_mbs (
qse_mchar_t* buf, int size,
qse_uintmax_t value, int base_and_flags, int prec,
qse_mchar_t fillchar, qse_mchar_t signchar, const qse_mchar_t* prefix)
{
qse_mchar_t tmp[(QSE_SIZEOF(qse_uintmax_t) * 8)];
int reslen, base, fillsize, reqlen, pflen, preczero;
qse_mchar_t* p, * bp, * be;
const qse_mchar_t* xbasestr;
base = base_and_flags & 0x3F;
if (base < 2 || base > 36) return -1;
xbasestr = (base_and_flags & QSE_FMTINTMAXTOMBS_UPPERCASE)?
QSE_MT("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
QSE_MT("0123456789abcdefghijklmnopqrstuvwxyz");
if ((base_and_flags & QSE_FMTINTMAXTOMBS_NOZERO) && value == 0)
{
p = tmp;
if (base_and_flags & QSE_FMTINTMAXTOMBS_ZEROLEAD)
{
/* NOZERO emits no digit, ZEROLEAD emits 1 digit.
* so it emits '0' */
reslen = 1;
preczero = 1;
}
else
{
/* since the value is zero, emit no digits */
reslen = 0;
preczero = 0;
}
}
else
{
qse_uintmax_t v = value;
/* store the resulting numeric string into 'tmp' first */
p = tmp;
do
{
*p++ = xbasestr[v % base];
v /= base;
}
while (v > 0);
/* reslen is the length of the resulting string without padding. */
reslen = (int)(p - tmp);
/* precision specified the minum number of digits to produce.
* so if the precision is larger that the digits produced,
* reslen should be adjusted to precision */
if (prec > reslen)
{
/* if the precision is greater than the actual digits
* made from the value, 0 is inserted in front.
* ZEROLEAD doesn't have to be handled explicitly
* since it's achieved effortlessly */
preczero = prec - reslen;
reslen = prec;
}
else
{
preczero = 0;
if ((base_and_flags & QSE_FMTINTMAXTOMBS_ZEROLEAD) && value != 0)
{
/* if value is zero, 0 is emitted from it.
* so ZEROLEAD don't need to add another 0. */
preczero++;
reslen++;
}
}
}
if (signchar) reslen++; /* increment reslen for the sign character */
if (prefix)
{
/* since the length can be truncated for different type sizes,
* don't pass in a very long prefix. */
pflen = (int)qse_mbslen(prefix);
reslen += pflen;
}
else pflen = 0;
/* get the required buffer size for lossless formatting */
reqlen = (base_and_flags & QSE_FMTINTMAXTOMBS_NONULL)? reslen: (reslen + 1);
if (size <= 0 ||
((base_and_flags & QSE_FMTINTMAXTOMBS_NOTRUNC) && size < reqlen))
{
return -reqlen;
}
/* get the size to fill with fill characters */
fillsize = (base_and_flags & QSE_FMTINTMAXTOMBS_NONULL)? size: (size - 1);
bp = buf;
be = buf + fillsize;
/* fill space */
if (fillchar != QSE_MT('\0'))
{
if (base_and_flags & QSE_FMTINTMAXTOMBS_FILLRIGHT)
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = QSE_MT('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
/* fill the right side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
}
else if (base_and_flags & QSE_FMTINTMAXTOMBS_FILLCENTER)
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* fill the left side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = QSE_MT('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
else
{
/* fill the left side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = QSE_MT('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
}
else
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = QSE_MT('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
if (!(base_and_flags & QSE_FMTINTMAXTOMBS_NONULL)) *bp = QSE_MT('\0');
return bp - buf;
}
int qse_fmtintmaxtombs ( int qse_fmtintmaxtombs (
qse_mchar_t* buf, int size, qse_mchar_t* buf, int size,
qse_intmax_t value, int base_and_flags, int prec, qse_intmax_t value, int base_and_flags, int prec,
@ -283,211 +103,8 @@ int qse_fmtuintmaxtombs (
buf, size, value, base_and_flags, prec, fillchar, signchar, prefix); buf, size, value, base_and_flags, prec, fillchar, signchar, prefix);
} }
/* ==================== wide-char ===================================== */ /* ==================== wide-char ===================================== */
static int fmt_unsigned_to_wcs (
qse_wchar_t* buf, int size,
qse_uintmax_t value, int base_and_flags, int prec,
qse_wchar_t fillchar, qse_wchar_t signchar, const qse_wchar_t* prefix)
{
qse_wchar_t tmp[(QSE_SIZEOF(qse_uintmax_t) * 8)];
int reslen, base, fillsize, reqlen, pflen, preczero;
qse_wchar_t* p, * bp, * be;
const qse_wchar_t* xbasestr;
base = base_and_flags & 0x3F;
if (base < 2 || base > 36) return -1;
xbasestr = (base_and_flags & QSE_FMTINTMAXTOWCS_UPPERCASE)?
QSE_WT("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
QSE_WT("0123456789abcdefghijklmnopqrstuvwxyz");
if ((base_and_flags & QSE_FMTINTMAXTOWCS_NOZERO) && value == 0)
{
p = tmp;
if (base_and_flags & QSE_FMTINTMAXTOWCS_ZEROLEAD)
{
/* NOZERO emits no digit, ZEROLEAD emits 1 digit.
* so it emits '0' */
reslen = 1;
preczero = 1;
}
else
{
/* since the value is zero, emit no digits */
reslen = 0;
preczero = 0;
}
}
else
{
qse_uintmax_t v = value;
/* store the resulting numeric string into 'tmp' first */
p = tmp;
do
{
*p++ = xbasestr[v % base];
v /= base;
}
while (v > 0);
/* reslen is the length of the resulting string without padding. */
reslen = (int)(p - tmp);
/* precision specified the minum number of digits to produce.
* so if the precision is larger that the digits produced,
* reslen should be adjusted to precision */
if (prec > reslen)
{
/* if the precision is greater than the actual digits
* made from the value, 0 is inserted in front.
* ZEROLEAD doesn't have to be handled explicitly
* since it's achieved effortlessly */
preczero = prec - reslen;
reslen = prec;
}
else
{
preczero = 0;
if ((base_and_flags & QSE_FMTINTMAXTOWCS_ZEROLEAD) && value != 0)
{
/* if value is zero, 0 is emitted from it.
* so ZEROLEAD don't need to add another 0. */
preczero++;
reslen++;
}
}
}
if (signchar) reslen++; /* increment reslen for the sign character */
if (prefix)
{
/* since the length can be truncated for different type sizes,
* don't pass in a very long prefix. */
pflen = (int)qse_wcslen(prefix);
reslen += pflen;
}
else pflen = 0;
/* get the required buffer size for lossless formatting */
reqlen = (base_and_flags & QSE_FMTINTMAXTOWCS_NONULL)? reslen: (reslen + 1);
if (size <= 0 ||
((base_and_flags & QSE_FMTINTMAXTOWCS_NOTRUNC) && size < reqlen))
{
return -reqlen;
}
/* get the size to fill with fill characters */
fillsize = (base_and_flags & QSE_FMTINTMAXTOWCS_NONULL)? size: (size - 1);
bp = buf;
be = buf + fillsize;
/* fill space */
if (fillchar != QSE_WT('\0'))
{
if (base_and_flags & QSE_FMTINTMAXTOWCS_FILLRIGHT)
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = QSE_WT('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
/* fill the right side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
}
else if (base_and_flags & QSE_FMTINTMAXTOWCS_FILLCENTER)
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* fill the left side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = QSE_WT('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
else
{
/* fill the left side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = QSE_WT('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
}
else
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = QSE_WT('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
if (!(base_and_flags & QSE_FMTINTMAXTOWCS_NONULL)) *bp = QSE_WT('\0');
return bp - buf;
}
int qse_fmtintmaxtowcs ( int qse_fmtintmaxtowcs (
qse_wchar_t* buf, int size, qse_wchar_t* buf, int size,
qse_intmax_t value, int base_and_flags, int prec, qse_intmax_t value, int base_and_flags, int prec,
@ -546,3 +163,42 @@ int qse_fmtuintmaxtowcs (
buf, size, value, base_and_flags, prec, fillchar, signchar, prefix); buf, size, value, base_and_flags, prec, fillchar, signchar, prefix);
} }
/* ==================== floating-point number =========================== */
/* TODO: finish this function */
int qse_fmtfltmaxtombs (qse_mchar_t* buf, qse_size_t bufsize, qse_fltmax_t f, qse_mchar_t point, int digits)
{
qse_size_t len;
qse_uintmax_t v;
/*if (bufsize <= 0) return -reqlen; TODO: */
if (f < 0)
{
f *= -1;
v = (qse_uintmax_t)f;
len = qse_fmtuintmaxtombs (buf, bufsize, v, 10, 0, QSE_MT('\0'), QSE_MT("-"));
}
else
{
v = (qse_uintmax_t)f;
len = qse_fmtuintmaxtombs (buf, bufsize, v, 10, 0, QSE_MT('\0'), QSE_NULL);
}
if (len + 1 < bufsize)
{
buf[len++] = point; // add decimal point to string
buf[len] = QSE_MT('\0');
}
while (len + 1 < bufsize && digits-- > 0)
{
f = (f - (qse_fltmax_t)v) * 10;
v = (qse_uintmax_t)f;
len += qse_fmtuintmaxtombs (&buf[len], bufsize - len, v, 10, 0, QSE_MT('\0'), QSE_NULL);
}
return (int)len;
}

220
qse/lib/cmn/fmt.h Normal file
View File

@ -0,0 +1,220 @@
/*
* $Id$
*
Copyright 2006-2012 Chung, Hyung-Hwan.
This file is part of QSE.
QSE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
QSE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
*/
static int fmt_uintmax (
char_t* buf, int size,
qse_uintmax_t value, int base_and_flags, int prec,
char_t fillchar, char_t signchar, const char_t* prefix)
{
char_t tmp[(QSE_SIZEOF(qse_uintmax_t) * 8)];
int reslen, base, fillsize, reqlen, pflen, preczero;
char_t* p, * bp, * be;
const char_t* xbasestr;
base = base_and_flags & 0x3F;
if (base < 2 || base > 36) return -1;
xbasestr = (base_and_flags & QSE_FMTINTMAX_UPPERCASE)?
T("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
T("0123456789abcdefghijklmnopqrstuvwxyz");
if ((base_and_flags & QSE_FMTINTMAX_NOZERO) && value == 0)
{
p = tmp;
if (base_and_flags & QSE_FMTINTMAX_ZEROLEAD)
{
/* NOZERO emits no digit, ZEROLEAD emits 1 digit.
* so it emits '0' */
reslen = 1;
preczero = 1;
}
else
{
/* since the value is zero, emit no digits */
reslen = 0;
preczero = 0;
}
}
else
{
qse_uintmax_t v = value;
/* store the resulting numeric string into 'tmp' first */
p = tmp;
do
{
*p++ = xbasestr[v % base];
v /= base;
}
while (v > 0);
/* reslen is the length of the resulting string without padding. */
reslen = (int)(p - tmp);
/* precision specified the minum number of digits to produce.
* so if the precision is larger that the digits produced,
* reslen should be adjusted to precision */
if (prec > reslen)
{
/* if the precision is greater than the actual digits
* made from the value, 0 is inserted in front.
* ZEROLEAD doesn't have to be handled explicitly
* since it's achieved effortlessly */
preczero = prec - reslen;
reslen = prec;
}
else
{
preczero = 0;
if ((base_and_flags & QSE_FMTINTMAX_ZEROLEAD) && value != 0)
{
/* if value is zero, 0 is emitted from it.
* so ZEROLEAD don't need to add another 0. */
preczero++;
reslen++;
}
}
}
if (signchar) reslen++; /* increment reslen for the sign character */
if (prefix)
{
/* since the length can be truncated for different type sizes,
* don't pass in a very long prefix. */
pflen = (int) strlen(prefix);
reslen += pflen;
}
else pflen = 0;
/* get the required buffer size for lossless formatting */
reqlen = (base_and_flags & QSE_FMTINTMAX_NONULL)? reslen: (reslen + 1);
if (size <= 0 ||
((base_and_flags & QSE_FMTINTMAX_NOTRUNC) && size < reqlen))
{
return -reqlen;
}
/* get the size to fill with fill characters */
fillsize = (base_and_flags & QSE_FMTINTMAX_NONULL)? size: (size - 1);
bp = buf;
be = buf + fillsize;
/* fill space */
if (fillchar != T('\0'))
{
if (base_and_flags & QSE_FMTINTMAX_FILLRIGHT)
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = T('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
/* fill the right side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
}
else if (base_and_flags & QSE_FMTINTMAX_FILLCENTER)
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* fill the left side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = T('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
else
{
/* fill the left side */
while (fillsize > reslen)
{
*bp++ = fillchar;
fillsize--;
}
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = T('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
}
else
{
/* emit sign */
if (signchar && bp < be) *bp++ = signchar;
/* copy prefix if necessary */
if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
/* add 0s for precision */
while (preczero > 0 && bp < be)
{
*bp++ = T('0');
preczero--;
}
/* copy the numeric string to the destination buffer */
while (p > tmp && bp < be) *bp++ = *--p;
}
if (!(base_and_flags & QSE_FMTINTMAX_NONULL)) *bp = T('\0');
return bp - buf;
}

View File

@ -23,6 +23,7 @@
#include <qse/cmn/str.h> #include <qse/cmn/str.h>
#include <qse/cmn/mbwc.h> #include <qse/cmn/mbwc.h>
#include <stdarg.h> #include <stdarg.h>
#include "mem.h"
/* number of bits in a byte */ /* number of bits in a byte */
#define NBBY 8 #define NBBY 8
@ -97,7 +98,7 @@ enum
#include <stdio.h> /* TODO: remove dependency on this */ #include <stdio.h> /* TODO: remove dependency on this */
static void put_wchar (qse_wchar_t c, void *arg) static int put_wchar (qse_wchar_t c, void *arg)
{ {
qse_cmgr_t* cmgr; qse_cmgr_t* cmgr;
qse_mchar_t mbsbuf[QSE_MBLEN_MAX + 1]; qse_mchar_t mbsbuf[QSE_MBLEN_MAX + 1];
@ -107,18 +108,22 @@ static void put_wchar (qse_wchar_t c, void *arg)
n = cmgr->wctomb (c, mbsbuf, QSE_COUNTOF(mbsbuf)); n = cmgr->wctomb (c, mbsbuf, QSE_COUNTOF(mbsbuf));
if (n <= 0 || n > QSE_COUNTOF(mbsbuf)) if (n <= 0 || n > QSE_COUNTOF(mbsbuf))
{ {
putchar ('?'); return (putchar ('?') == EOF)? -1: 0;
} }
else else
{ {
qse_size_t i; qse_size_t i;
for (i = 0; i < n; i++) putchar (mbsbuf[i]); for (i = 0; i < n; i++)
{
if (putchar (mbsbuf[i]) == EOF) return -1;
}
return 0;
} }
} }
static void put_mchar (qse_mchar_t c, void *arg) static int put_mchar (qse_mchar_t c, void *arg)
{ {
putchar (c); return (putchar (c) == EOF)? -1: 0;
} }
#undef char_t #undef char_t

View File

@ -86,16 +86,16 @@ 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 { \
put_char (c, arg); \ if (put_char (c, arg) <= -1) goto oops; \
retval++; \ retval++; \
} while (0) } while (0)
#define PUT_OCHAR(c) do { \ #define PUT_OCHAR(c) do { \
put_ochar (c, arg); \ if (put_ochar (c, arg) <= -1) goto oops; \
retval++; \ retval++; \
} while (0) } while (0)
int xprintf (char_t const *fmt, void (*put_char)(char_t, void*), void (*put_ochar) (ochar_t, void*), void *arg, va_list ap) int xprintf (char_t const *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;
@ -108,6 +108,10 @@ int xprintf (char_t const *fmt, void (*put_char)(char_t, void*), void (*put_ocha
int stop = 0, retval = 0; int stop = 0, retval = 0;
char_t fltbuf[100]; char_t fltbuf[100];
qse_mchar_t fltfmt[64];
qse_mchar_t* fltfmtp = QSE_NULL;
qse_size_t fltfmtc;
while (1) while (1)
{ {
while ((ch = (uchar_t)*fmt++) != T('%') || stop) while ((ch = (uchar_t)*fmt++) != T('%') || stop)
@ -397,7 +401,7 @@ reswitch:
if (((lm_flag & LF_H) && (QSE_SIZEOF(char_t) > QSE_SIZEOF(ochar_t))) || if (((lm_flag & LF_H) && (QSE_SIZEOF(char_t) > QSE_SIZEOF(ochar_t))) ||
((lm_flag & LF_L) && (QSE_SIZEOF(char_t) < QSE_SIZEOF(ochar_t)))) goto uppercase_s; ((lm_flag & LF_L) && (QSE_SIZEOF(char_t) < QSE_SIZEOF(ochar_t)))) goto uppercase_s;
lowercase_s: lowercase_s:
sp = va_arg (ap, char_t *); sp = va_arg (ap, char_t*);
if (sp == QSE_NULL) p = T("(null)"); if (sp == QSE_NULL) p = T("(null)");
print_lowercase_s: print_lowercase_s:
@ -467,7 +471,8 @@ reswitch:
*/ */
{ {
qse_mchar_t tmpbuf[100]; qse_mchar_t tmpbuf[100];
qse_mchar_t tmpfmt[100]; qse_mchar_t* tmpbufp;
const char_t* xx; const char_t* xx;
const qse_mchar_t* yy; const qse_mchar_t* yy;
int q; int q;
@ -475,12 +480,24 @@ reswitch:
#if defined(NO_MERCY) #if defined(NO_MERCY)
if (lm_flag & ~LF_LD) goto invalid_format; if (lm_flag & ~LF_LD) goto invalid_format;
#endif #endif
for (xx = percent, q = 0; xx < fmt; xx++) tmpfmt[q++] = *xx;
tmpfmt[q] = QSE_MT('\0'); if (fmt - percent < QSE_COUNTOF(fltfmt))
if (lm_flag & LF_LD) {
snprintf (tmpbuf, QSE_SIZEOF(tmpbuf), tmpfmt, va_arg (ap, long double)); fltfmtp = fltfmt;
}
else else
snprintf (tmpbuf, QSE_SIZEOF(tmpbuf), tmpfmt, va_arg (ap, double)); {
fltfmtp = QSE_MMGR_ALLOC (QSE_MMGR_GETDFL(), QSE_SIZEOF(*fltfmtp) * (fmt - percent + 1));
if (fltfmtp == QSE_NULL) goto oops;
}
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));
for (yy = tmpbuf, q = 0; *yy; ) fltbuf[q++] = *yy++; for (yy = tmpbuf, q = 0; *yy; ) fltbuf[q++] = *yy++;
fltbuf[q] = QSE_T('\0'); fltbuf[q] = QSE_T('\0');
sp = fltbuf; sp = fltbuf;
@ -488,7 +505,6 @@ reswitch:
width = 0; width = 0;
precision = 0; precision = 0;
goto print_lowercase_s; goto print_lowercase_s;
break;
} }
handle_nosign: handle_nosign:
@ -667,6 +683,13 @@ invalid_format:
break; break;
} }
} }
oops:
if (fltfmtp && fltfmtp != fltfmt)
{
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), fltfmtp);
}
return -1;
} }
#undef PUT_CHAR #undef PUT_CHAR
#undef PUT_OCHAR #undef PUT_OCHAR