added some code to format floating-point numbers
This commit is contained in:
parent
99ac89fc57
commit
b70e378041
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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
220
qse/lib/cmn/fmt.h
Normal 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;
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user