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)
|
||||
#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
|
||||
}
|
||||
#endif
|
||||
|
@ -454,7 +454,7 @@ typedef qse_int_t qse_intptr_t;
|
||||
|
||||
/** @typedef qse_flt_t
|
||||
* The qse_flt_t type defines the largest floating-pointer number type
|
||||
* supported.
|
||||
* naturally supported.
|
||||
*/
|
||||
#if defined(__FreeBSD__)
|
||||
/* 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
|
||||
#endif
|
||||
|
||||
/* TODO: qse_fltmax_t to include the quadruple precision floating-point type.
|
||||
*
|
||||
#if QSE_SIZEOF___FLOAT128 > 0
|
||||
/** @typedef qse_fltmax_t
|
||||
* The qse_fltmax_t type defines the largest floating-pointer number type
|
||||
* ever supported.
|
||||
*/
|
||||
#if QSE_SIZEOF__FLOAT128 > QSE_SIZEOF_FLT_T
|
||||
typedef __float128 qse_fltmax_t;
|
||||
# define QSE_SIZEOF_FLTMAX_T QSE_SIZEOF___FLOAT128
|
||||
#else
|
||||
typedef qse_flt_t qse_fltmax_t;
|
||||
# define QSE_SIZEOF_FLTMAX_T QSE_SIZEOF_FLT_T
|
||||
#endif
|
||||
*/
|
||||
|
||||
/**
|
||||
* The qse_mchar_t type defines a multi-byte character type.
|
||||
|
@ -21,210 +21,30 @@
|
||||
#include <qse/cmn/fmt.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 ===================================== */
|
||||
|
||||
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 (
|
||||
qse_mchar_t* buf, int size,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* ==================== 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 (
|
||||
qse_wchar_t* buf, int size,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* ==================== 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/mbwc.h>
|
||||
#include <stdarg.h>
|
||||
#include "mem.h"
|
||||
|
||||
/* number of bits in a byte */
|
||||
#define NBBY 8
|
||||
@ -97,7 +98,7 @@ enum
|
||||
|
||||
#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_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));
|
||||
if (n <= 0 || n > QSE_COUNTOF(mbsbuf))
|
||||
{
|
||||
putchar ('?');
|
||||
return (putchar ('?') == EOF)? -1: 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
|
@ -86,16 +86,16 @@ static char_t* sprintn (char_t* nbuf, qse_uintmax_t num, int base, int *lenp, in
|
||||
|
||||
/* TODO: error check */
|
||||
#define PUT_CHAR(c) do { \
|
||||
put_char (c, arg); \
|
||||
if (put_char (c, arg) <= -1) goto oops; \
|
||||
retval++; \
|
||||
} while (0)
|
||||
|
||||
#define PUT_OCHAR(c) do { \
|
||||
put_ochar (c, arg); \
|
||||
if (put_ochar (c, arg) <= -1) goto oops; \
|
||||
retval++; \
|
||||
} 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];
|
||||
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;
|
||||
char_t fltbuf[100];
|
||||
|
||||
qse_mchar_t fltfmt[64];
|
||||
qse_mchar_t* fltfmtp = QSE_NULL;
|
||||
qse_size_t fltfmtc;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while ((ch = (uchar_t)*fmt++) != T('%') || stop)
|
||||
@ -467,7 +471,8 @@ reswitch:
|
||||
*/
|
||||
{
|
||||
qse_mchar_t tmpbuf[100];
|
||||
qse_mchar_t tmpfmt[100];
|
||||
qse_mchar_t* tmpbufp;
|
||||
|
||||
const char_t* xx;
|
||||
const qse_mchar_t* yy;
|
||||
int q;
|
||||
@ -475,12 +480,24 @@ reswitch:
|
||||
#if defined(NO_MERCY)
|
||||
if (lm_flag & ~LF_LD) goto invalid_format;
|
||||
#endif
|
||||
for (xx = percent, q = 0; xx < fmt; xx++) tmpfmt[q++] = *xx;
|
||||
tmpfmt[q] = QSE_MT('\0');
|
||||
if (lm_flag & LF_LD)
|
||||
snprintf (tmpbuf, QSE_SIZEOF(tmpbuf), tmpfmt, va_arg (ap, long double));
|
||||
|
||||
if (fmt - percent < QSE_COUNTOF(fltfmt))
|
||||
{
|
||||
fltfmtp = fltfmt;
|
||||
}
|
||||
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++;
|
||||
fltbuf[q] = QSE_T('\0');
|
||||
sp = fltbuf;
|
||||
@ -488,7 +505,6 @@ reswitch:
|
||||
width = 0;
|
||||
precision = 0;
|
||||
goto print_lowercase_s;
|
||||
break;
|
||||
}
|
||||
|
||||
handle_nosign:
|
||||
@ -667,6 +683,13 @@ invalid_format:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
oops:
|
||||
if (fltfmtp && fltfmtp != fltfmt)
|
||||
{
|
||||
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), fltfmtp);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#undef PUT_CHAR
|
||||
#undef PUT_OCHAR
|
||||
|
Loading…
Reference in New Issue
Block a user