From aaa5a50e8c4cd800dac25080aceb79bd262361c3 Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Thu, 21 Nov 2019 09:04:53 +0000 Subject: [PATCH] added moo_fmt_intmax_to_ucstr() and similar functions --- moo/lib/Makefile.am | 5 + moo/lib/Makefile.in | 11 +- moo/lib/fmt-imp.h | 228 +++++++++++++++++++++++++++ moo/lib/fmt.c | 145 +++++++++++++++-- moo/lib/moo-fmt.h | 371 ++++++++++++++++++++++++++++++++++++++++++++ moo/lib/moo-prv.h | 1 + moo/lib/moo-utl.h | 74 --------- 7 files changed, 749 insertions(+), 86 deletions(-) create mode 100644 moo/lib/fmt-imp.h create mode 100644 moo/lib/moo-fmt.h diff --git a/moo/lib/Makefile.am b/moo/lib/Makefile.am index 7f0413a..e4db126 100644 --- a/moo/lib/Makefile.am +++ b/moo/lib/Makefile.am @@ -39,6 +39,7 @@ pkginclude_HEADERS = \ moo.h \ moo-chr.h \ moo-cmn.h \ + moo-fmt.h \ moo-opt.h \ moo-rbt.h \ moo-utl.h \ @@ -57,7 +58,9 @@ libmoo_la_SOURCES = \ bct-lab.h \ chr.c \ moo.h \ + moo-chr.h \ moo-cmn.h \ + moo-fmt.h \ moo-rbt.h \ moo-utl.h \ moo-prv.h \ @@ -70,6 +73,7 @@ libmoo_la_SOURCES = \ dic.c \ err.c \ exec.c \ + fmt-imp.h \ fmt.c \ gc.c \ heap.c \ @@ -125,6 +129,7 @@ endif # libmoox ############################################################## libmoox_la_SOURCES = \ + moo-opt.h \ moo-std.h \ opt-imp.h \ opt.c \ diff --git a/moo/lib/Makefile.in b/moo/lib/Makefile.in index 9a01e32..4891998 100644 --- a/moo/lib/Makefile.in +++ b/moo/lib/Makefile.in @@ -173,8 +173,8 @@ libmoo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @ENABLE_LIBLTDL_FALSE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) @ENABLE_LIBUNWIND_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) @WIN32_TRUE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1) -am__libmoox_la_SOURCES_DIST = moo-std.h opt-imp.h opt.c std.c \ - poll-msw.c poll-msw.h +am__libmoox_la_SOURCES_DIST = moo-opt.h moo-std.h opt-imp.h opt.c \ + std.c poll-msw.c poll-msw.h @WIN32_TRUE@am__objects_1 = libmoox_la-poll-msw.lo am_libmoox_la_OBJECTS = libmoox_la-opt.lo libmoox_la-std.lo \ $(am__objects_1) @@ -453,6 +453,7 @@ pkginclude_HEADERS = \ moo.h \ moo-chr.h \ moo-cmn.h \ + moo-fmt.h \ moo-opt.h \ moo-rbt.h \ moo-utl.h \ @@ -467,7 +468,9 @@ libmoo_la_SOURCES = \ bct-lab.h \ chr.c \ moo.h \ + moo-chr.h \ moo-cmn.h \ + moo-fmt.h \ moo-rbt.h \ moo-utl.h \ moo-prv.h \ @@ -480,6 +483,7 @@ libmoo_la_SOURCES = \ dic.c \ err.c \ exec.c \ + fmt-imp.h \ fmt.c \ gc.c \ heap.c \ @@ -510,7 +514,8 @@ libmoo_la_DEPENDENCIES = $(am__append_4) $(am__append_6) \ ############################################################## # libmoox ############################################################## -libmoox_la_SOURCES = moo-std.h opt-imp.h opt.c std.c $(am__append_15) +libmoox_la_SOURCES = moo-opt.h moo-std.h opt-imp.h opt.c std.c \ + $(am__append_15) libmoox_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON) $(CPPFLAGS_PFMOD) libmoox_la_LDFLAGS = $(LDFLAGS_LIB_COMMON) libmoox_la_LIBADD = $(LIBADD_LIB_COMMON) -lmoo $(LIBM) $(PTHREAD_LIBS) \ diff --git a/moo/lib/fmt-imp.h b/moo/lib/fmt-imp.h new file mode 100644 index 0000000..eeda707 --- /dev/null +++ b/moo/lib/fmt-imp.h @@ -0,0 +1,228 @@ +/* + * $Id$ + * + Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +static int fmt_uintmax ( + char_t* buf, int size, + moo_uintmax_t value, int base_and_flags, int prec, + char_t fillchar, char_t signchar, const char_t* prefix) +{ + char_t tmp[(MOO_SIZEOF(moo_uintmax_t) * 8)]; + int reslen, base, fillsize, reqlen, pflen, preczero; + char_t* p, * bp, * be; + const moo_bch_t* xbasestr; + + base = base_and_flags & 0x3F; + if (base < 2 || base > 36) return -1; + + xbasestr = (base_and_flags & MOO_FMT_INTMAX_UPPERCASE)? + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ": + "0123456789abcdefghijklmnopqrstuvwxyz"; + + if ((base_and_flags & MOO_FMT_INTMAX_NOZERO) && value == 0) + { + p = tmp; + if (base_and_flags & MOO_FMT_INTMAX_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 + { + moo_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 & MOO_FMT_INTMAX_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. */ + const char_t* pp; + for (pp = prefix; *pp != '\0'; pp++) ; + pflen = pp - prefix; + reslen += pflen; + } + else pflen = 0; + + /* get the required buffer size for lossless formatting */ + reqlen = (base_and_flags & MOO_FMT_INTMAX_NONULL)? reslen: (reslen + 1); + + if (size <= 0 || + ((base_and_flags & MOO_FMT_INTMAX_NOTRUNC) && size < reqlen)) + { + return -reqlen; + } + + /* get the size to fill with fill characters */ + fillsize = (base_and_flags & MOO_FMT_INTMAX_NONULL)? size: (size - 1); + bp = buf; + be = buf + fillsize; + + /* fill space */ + if (fillchar != '\0') + { + if (base_and_flags & MOO_FMT_INTMAX_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++ = '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 & MOO_FMT_INTMAX_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++ = '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++ = '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++ = '0'; + preczero--; + } + + /* copy the numeric string to the destination buffer */ + while (p > tmp && bp < be) *bp++ = *--p; + } + + if (!(base_and_flags & MOO_FMT_INTMAX_NONULL)) *bp = '\0'; + return bp - buf; +} diff --git a/moo/lib/fmt.c b/moo/lib/fmt.c index 614520d..bf5f753 100644 --- a/moo/lib/fmt.c +++ b/moo/lib/fmt.c @@ -169,6 +169,135 @@ static const moo_bch_t hex2ascii_upper[] = static moo_uch_t uch_nullstr[] = { '(','n','u','l','l', ')','\0' }; static moo_bch_t bch_nullstr[] = { '(','n','u','l','l', ')','\0' }; +/* ------------------------------------------------------------------------- */ + +/*define static int fmt_uintmax_to_bcstr(...)*/ +#undef char_t +#undef fmt_uintmax +#define char_t moo_bch_t +#define fmt_uintmax fmt_uintmax_to_bcstr +#include "fmt-imp.h" + +/*define static int fmt_uintmax_to_ucstr(...)*/ +#undef char_t +#undef fmt_uintmax +#define char_t moo_uch_t +#define fmt_uintmax fmt_uintmax_to_ucstr +#include "fmt-imp.h" + +int moo_fmt_intmax_to_bcstr ( + moo_bch_t* buf, int size, + moo_intmax_t value, int base_and_flags, int prec, + moo_bch_t fillchar, const moo_bch_t* prefix) +{ + moo_bch_t signchar; + moo_uintmax_t absvalue; + + if (value < 0) + { + signchar = '-'; + absvalue = -value; + } + else if (base_and_flags & MOO_FMT_INTMAX_TO_BCSTR_PLUSSIGN) + { + signchar = '+'; + absvalue = value; + } + else if (base_and_flags & MOO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN) + { + signchar = ' '; + absvalue = value; + } + else + { + signchar = '\0'; + absvalue = value; + } + + return fmt_uintmax_to_bcstr(buf, size, absvalue, base_and_flags, prec, fillchar, signchar, prefix); +} + +int moo_fmt_uintmax_to_bcstr ( + moo_bch_t* buf, int size, + moo_uintmax_t value, int base_and_flags, int prec, + moo_bch_t fillchar, const moo_bch_t* prefix) +{ + moo_bch_t signchar; + + /* determine if a sign character is needed */ + if (base_and_flags & MOO_FMT_INTMAX_TO_BCSTR_PLUSSIGN) + { + signchar = '+'; + } + else if (base_and_flags & MOO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN) + { + signchar = ' '; + } + else + { + signchar = '\0'; + } + + return fmt_uintmax_to_bcstr(buf, size, value, base_and_flags, prec, fillchar, signchar, prefix); +} + +/* ==================== wide-char ===================================== */ + +int moo_fmt_intmax_to_ucstr ( + moo_uch_t* buf, int size, + moo_intmax_t value, int base_and_flags, int prec, + moo_uch_t fillchar, const moo_uch_t* prefix) +{ + moo_uch_t signchar; + moo_uintmax_t absvalue; + + if (value < 0) + { + signchar = '-'; + absvalue = -value; + } + else if (base_and_flags & MOO_FMT_INTMAX_TO_UCSTR_PLUSSIGN) + { + signchar = '+'; + absvalue = value; + } + else if (base_and_flags & MOO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN) + { + signchar = ' '; + absvalue = value; + } + else + { + signchar = '\0'; + absvalue = value; + } + + return fmt_uintmax_to_ucstr(buf, size, absvalue, base_and_flags, prec, fillchar, signchar, prefix); +} + +int moo_fmt_uintmax_to_ucstr ( + moo_uch_t* buf, int size, + moo_uintmax_t value, int base_and_flags, int prec, + moo_uch_t fillchar, const moo_uch_t* prefix) +{ + moo_uch_t signchar; + + /* determine if a sign character is needed */ + if (base_and_flags & MOO_FMT_INTMAX_TO_UCSTR_PLUSSIGN) + { + signchar = '+'; + } + else if (base_and_flags & MOO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN) + { + signchar = ' '; + } + else + { + signchar = '\0'; + } + + return fmt_uintmax_to_ucstr(buf, size, value, base_and_flags, prec, fillchar, signchar, prefix); +} /* ------------------------------------------------------------------------- */ /* @@ -515,7 +644,7 @@ static int fmt_outv (moo_fmtout_t* fmtout, va_list ap) case 'q': /* long long int */ case 'j': /* moo_intmax_t/moo_uintmax_t */ case 'z': /* moo_ooi_t/moo_oow_t */ - case 't': /* ptrdiff_t */ + case 't': /* ptrdiff_t - usually moo_intptr_t */ if (lm_flag & (LF_LD | LF_QD)) goto invalid_format; flagc |= FLAGC_LENMOD; @@ -987,7 +1116,7 @@ static int fmt_outv (moo_fmtout_t* fmtout, va_list ap) if (flagc & FLAGC_STAR1) fltfmt->ptr[fmtlen++] = '*'; else if (flagc & FLAGC_WIDTH) { - fmtlen += moo_fmtuintmaxtombs ( + fmtlen += moo_fmt_uintmax_to_bcs ( &fltfmt->ptr[fmtlen], fltfmt->capa - fmtlen, width, 10, -1, '\0', MOO_NULL); } @@ -995,7 +1124,7 @@ static int fmt_outv (moo_fmtout_t* fmtout, va_list ap) if (flagc & FLAGC_STAR2) fltfmt->ptr[fmtlen++] = '*'; else if (flagc & FLAGC_PRECISION) { - fmtlen += moo_fmtuintmaxtombs ( + fmtlen += moo_fmt_uintmax_to_bcs ( &fltfmt->ptr[fmtlen], fltfmt->capa - fmtlen, precision, 10, -1, '\0', MOO_NULL); } @@ -1116,10 +1245,8 @@ static int fmt_outv (moo_fmtout_t* fmtout, va_list ap) num = va_arg (ap, moo_uintmax_t); #endif } -#if 0 else if (lm_flag & LF_T) - num = va_arg(ap, moo_ptrdiff_t); -#endif + num = va_arg(ap, moo_intptr_t/*moo_ptrdiff_t*/); else if (lm_flag & LF_Z) num = va_arg(ap, moo_oow_t); #if (MOO_SIZEOF_LONG_LONG > 0) @@ -1161,10 +1288,8 @@ static int fmt_outv (moo_fmtout_t* fmtout, va_list ap) #endif } -#if 0 else if (lm_flag & LF_T) - num = va_arg(ap, moo_ptrdiff_t); -#endif + num = va_arg(ap, moo_intptr_t/*moo_ptrdiff_t*/); else if (lm_flag & LF_Z) num = va_arg (ap, moo_ooi_t); #if (MOO_SIZEOF_LONG_LONG > 0) @@ -2806,3 +2931,5 @@ int moo_strfmtcallstack (moo_t* moo, moo_ooi_t nargs, int rcv_is_fmtstr) moo->sprintf.xbuf.len = 0; return format_stack_args(&fo, nargs, rcv_is_fmtstr); } + + diff --git a/moo/lib/moo-fmt.h b/moo/lib/moo-fmt.h new file mode 100644 index 0000000..43c9b71 --- /dev/null +++ b/moo/lib/moo-fmt.h @@ -0,0 +1,371 @@ +/* + * $Id$ + * + Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MOO_FMT_H_ +#define _MOO_FMT_H_ + +#include + +/** \file + * This file defines various formatting functions. + */ + +/** + * The moo_fmt_intmax_flag_t type defines enumerators to change the + * behavior of moo_fmt_intmax() and moo_fmt_uintmax(). + */ +enum moo_fmt_intmax_flag_t +{ + /* Use lower 6 bits to represent base between 2 and 36 inclusive. + * Upper bits are used for these flag options */ + + /** Don't truncate if the buffer is not large enough */ + MOO_FMT_INTMAX_NOTRUNC = (0x40 << 0), +#define MOO_FMT_INTMAX_NOTRUNC MOO_FMT_INTMAX_NOTRUNC +#define MOO_FMT_UINTMAX_NOTRUNC MOO_FMT_INTMAX_NOTRUNC +#define MOO_FMT_INTMAX_TO_BCSTR_NOTRUNC MOO_FMT_INTMAX_NOTRUNC +#define MOO_FMT_UINTMAX_TO_BCSTR_NOTRUNC MOO_FMT_INTMAX_NOTRUNC +#define MOO_FMT_INTMAX_TO_UCSTR_NOTRUNC MOO_FMT_INTMAX_NOTRUNC +#define MOO_FMT_UINTMAX_TO_UCSTR_NOTRUNC MOO_FMT_INTMAX_NOTRUNC +#define MOO_FMT_INTMAX_TO_OOCSTR_NOTRUNC MOO_FMT_INTMAX_NOTRUNC +#define MOO_FMT_UINTMAX_TO_OOCSTR_NOTRUNC MOO_FMT_INTMAX_NOTRUNC + + /** Don't append a terminating null */ + MOO_FMT_INTMAX_NONULL = (0x40 << 1), +#define MOO_FMT_INTMAX_NONULL MOO_FMT_INTMAX_NONULL +#define MOO_FMT_UINTMAX_NONULL MOO_FMT_INTMAX_NONULL +#define MOO_FMT_INTMAX_TO_BCSTR_NONULL MOO_FMT_INTMAX_NONULL +#define MOO_FMT_UINTMAX_TO_BCSTR_NONULL MOO_FMT_INTMAX_NONULL +#define MOO_FMT_INTMAX_TO_UCSTR_NONULL MOO_FMT_INTMAX_NONULL +#define MOO_FMT_UINTMAX_TO_UCSTR_NONULL MOO_FMT_INTMAX_NONULL +#define MOO_FMT_INTMAX_TO_OOCSTR_NONULL MOO_FMT_INTMAX_NONULL +#define MOO_FMT_UINTMAX_TO_OOCSTR_NONULL MOO_FMT_INTMAX_NONULL + + /** Produce no digit for a value of zero */ + MOO_FMT_INTMAX_NOZERO = (0x40 << 2), +#define MOO_FMT_INTMAX_NOZERO MOO_FMT_INTMAX_NOZERO +#define MOO_FMT_UINTMAX_NOZERO MOO_FMT_INTMAX_NOZERO +#define MOO_FMT_INTMAX_TO_BCSTR_NOZERO MOO_FMT_INTMAX_NOZERO +#define MOO_FMT_UINTMAX_TO_BCSTR_NOZERO MOO_FMT_INTMAX_NOZERO +#define MOO_FMT_INTMAX_TO_UCSTR_NOZERO MOO_FMT_INTMAX_NOZERO +#define MOO_FMT_UINTMAX_TO_UCSTR_NOZERO MOO_FMT_INTMAX_NOZERO +#define MOO_FMT_INTMAX_TO_OOCSTR_NOZERO MOO_FMT_INTMAX_NOZERO +#define MOO_FMT_UINTMAX_TO_OOCSTR_NOZERO MOO_FMT_INTMAX_NOZERO + + /** Produce a leading zero for a non-zero value */ + MOO_FMT_INTMAX_ZEROLEAD = (0x40 << 3), +#define MOO_FMT_INTMAX_ZEROLEAD MOO_FMT_INTMAX_ZEROLEAD +#define MOO_FMT_UINTMAX_ZEROLEAD MOO_FMT_INTMAX_ZEROLEAD +#define MOO_FMT_INTMAX_TO_BCSTR_ZEROLEAD MOO_FMT_INTMAX_ZEROLEAD +#define MOO_FMT_UINTMAX_TO_BCSTR_ZEROLEAD MOO_FMT_INTMAX_ZEROLEAD +#define MOO_FMT_INTMAX_TO_UCSTR_ZEROLEAD MOO_FMT_INTMAX_ZEROLEAD +#define MOO_FMT_UINTMAX_TO_UCSTR_ZEROLEAD MOO_FMT_INTMAX_ZEROLEAD +#define MOO_FMT_INTMAX_TO_OOCSTR_ZEROLEAD MOO_FMT_INTMAX_ZEROLEAD +#define MOO_FMT_UINTMAX_TO_OOCSTR_ZEROLEAD MOO_FMT_INTMAX_ZEROLEAD + + /** Use uppercase letters for alphabetic digits */ + MOO_FMT_INTMAX_UPPERCASE = (0x40 << 4), +#define MOO_FMT_INTMAX_UPPERCASE MOO_FMT_INTMAX_UPPERCASE +#define MOO_FMT_UINTMAX_UPPERCASE MOO_FMT_INTMAX_UPPERCASE +#define MOO_FMT_INTMAX_TO_BCSTR_UPPERCASE MOO_FMT_INTMAX_UPPERCASE +#define MOO_FMT_UINTMAX_TO_BCSTR_UPPERCASE MOO_FMT_INTMAX_UPPERCASE +#define MOO_FMT_INTMAX_TO_UCSTR_UPPERCASE MOO_FMT_INTMAX_UPPERCASE +#define MOO_FMT_UINTMAX_TO_UCSTR_UPPERCASE MOO_FMT_INTMAX_UPPERCASE +#define MOO_FMT_INTMAX_TO_OOCSTR_UPPERCASE MOO_FMT_INTMAX_UPPERCASE +#define MOO_FMT_UINTMAX_TO_OOCSTR_UPPERCASE MOO_FMT_INTMAX_UPPERCASE + + /** Insert a plus sign for a positive integer including 0 */ + MOO_FMT_INTMAX_PLUSSIGN = (0x40 << 5), +#define MOO_FMT_INTMAX_PLUSSIGN MOO_FMT_INTMAX_PLUSSIGN +#define MOO_FMT_UINTMAX_PLUSSIGN MOO_FMT_INTMAX_PLUSSIGN +#define MOO_FMT_INTMAX_TO_BCSTR_PLUSSIGN MOO_FMT_INTMAX_PLUSSIGN +#define MOO_FMT_UINTMAX_TO_BCSTR_PLUSSIGN MOO_FMT_INTMAX_PLUSSIGN +#define MOO_FMT_INTMAX_TO_UCSTR_PLUSSIGN MOO_FMT_INTMAX_PLUSSIGN +#define MOO_FMT_UINTMAX_TO_UCSTR_PLUSSIGN MOO_FMT_INTMAX_PLUSSIGN +#define MOO_FMT_INTMAX_TO_OOCSTR_PLUSSIGN MOO_FMT_INTMAX_PLUSSIGN +#define MOO_FMT_UINTMAX_TO_OOCSTR_PLUSSIGN MOO_FMT_INTMAX_PLUSSIGN + + /** Insert a space for a positive integer including 0 */ + MOO_FMT_INTMAX_EMPTYSIGN = (0x40 << 6), +#define MOO_FMT_INTMAX_EMPTYSIGN MOO_FMT_INTMAX_EMPTYSIGN +#define MOO_FMT_UINTMAX_EMPTYSIGN MOO_FMT_INTMAX_EMPTYSIGN +#define MOO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN MOO_FMT_INTMAX_EMPTYSIGN +#define MOO_FMT_UINTMAX_TO_BCSTR_EMPTYSIGN MOO_FMT_INTMAX_EMPTYSIGN +#define MOO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN MOO_FMT_INTMAX_EMPTYSIGN +#define MOO_FMT_UINTMAX_TO_UCSTR_EMPTYSIGN MOO_FMT_INTMAX_EMPTYSIGN + + /** Fill the right part of the string */ + MOO_FMT_INTMAX_FILLRIGHT = (0x40 << 7), +#define MOO_FMT_INTMAX_FILLRIGHT MOO_FMT_INTMAX_FILLRIGHT +#define MOO_FMT_UINTMAX_FILLRIGHT MOO_FMT_INTMAX_FILLRIGHT +#define MOO_FMT_INTMAX_TO_BCSTR_FILLRIGHT MOO_FMT_INTMAX_FILLRIGHT +#define MOO_FMT_UINTMAX_TO_BCSTR_FILLRIGHT MOO_FMT_INTMAX_FILLRIGHT +#define MOO_FMT_INTMAX_TO_UCSTR_FILLRIGHT MOO_FMT_INTMAX_FILLRIGHT +#define MOO_FMT_UINTMAX_TO_UCSTR_FILLRIGHT MOO_FMT_INTMAX_FILLRIGHT +#define MOO_FMT_INTMAX_TO_OOCSTR_FILLRIGHT MOO_FMT_INTMAX_FILLRIGHT +#define MOO_FMT_UINTMAX_TO_OOCSTR_FILLRIGHT MOO_FMT_INTMAX_FILLRIGHT + + /** Fill between the sign chacter and the digit part */ + MOO_FMT_INTMAX_FILLCENTER = (0x40 << 8) +#define MOO_FMT_INTMAX_FILLCENTER MOO_FMT_INTMAX_FILLCENTER +#define MOO_FMT_UINTMAX_FILLCENTER MOO_FMT_INTMAX_FILLCENTER +#define MOO_FMT_INTMAX_TO_BCSTR_FILLCENTER MOO_FMT_INTMAX_FILLCENTER +#define MOO_FMT_UINTMAX_TO_BCSTR_FILLCENTER MOO_FMT_INTMAX_FILLCENTER +#define MOO_FMT_INTMAX_TO_UCSTR_FILLCENTER MOO_FMT_INTMAX_FILLCENTER +#define MOO_FMT_UINTMAX_TO_UCSTR_FILLCENTER MOO_FMT_INTMAX_FILLCENTER +#define MOO_FMT_INTMAX_TO_OOCSTR_FILLCENTER MOO_FMT_INTMAX_FILLCENTER +#define MOO_FMT_UINTMAX_TO_OOCSTR_FILLCENTER MOO_FMT_INTMAX_FILLCENTER +}; + +/* ========================================================================= + * FORMATTED OUTPUT + * ========================================================================= */ +typedef struct moo_fmtout_t moo_fmtout_t; + +typedef int (*moo_fmtout_putbchars_t) ( + moo_fmtout_t* fmtout, + const moo_bch_t* ptr, + moo_oow_t len +); + +typedef int (*moo_fmtout_putuchars_t) ( + moo_fmtout_t* fmtout, + const moo_uch_t* ptr, + moo_oow_t len +); + +typedef int (*moo_fmtout_putobj_t) ( + moo_fmtout_t* fmtout, + moo_oop_t obj +); + +enum moo_fmtout_fmt_type_t +{ + MOO_FMTOUT_FMT_TYPE_BCH = 0, + MOO_FMTOUT_FMT_TYPE_UCH +}; +typedef enum moo_fmtout_fmt_type_t moo_fmtout_fmt_type_t; + + +struct moo_fmtout_t +{ + moo_oow_t count; /* out */ + + moo_fmtout_putbchars_t putbchars; /* in */ + moo_fmtout_putuchars_t putuchars; /* in */ + moo_fmtout_putobj_t putobj; /* in - %O is not handled if it's not set. */ + moo_bitmask_t mask; /* in */ + void* ctx; /* in */ + + moo_fmtout_fmt_type_t fmt_type; + const void* fmt_str; +}; + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * The moo_fmt_intmax_to_bcstr() function formats an integer \a value to a + * multibyte string according to the given base and writes it to a buffer + * pointed to by \a buf. It writes to the buffer at most \a size characters + * including the terminating null. The base must be between 2 and 36 inclusive + * and can be ORed with zero or more #moo_fmt_intmax_to_bcstr_flag_t enumerators. + * This ORed value is passed to the function via the \a base_and_flags + * parameter. If the formatted string is shorter than \a bufsize, the redundant + * slots are filled with the fill character \a fillchar if it is not a null + * character. The filling behavior is determined by the flags shown below: + * + * - If #MOO_FMT_INTMAX_TO_BCSTR_FILLRIGHT is set in \a base_and_flags, slots + * after the formatting string are filled. + * - If #MOO_FMT_INTMAX_TO_BCSTR_FILLCENTER is set in \a base_and_flags, slots + * before the formatting string are filled. However, if it contains the + * sign character, the slots between the sign character and the digit part + * are filled. + * - If neither #MOO_FMT_INTMAX_TO_BCSTR_FILLRIGHT nor #MOO_FMT_INTMAX_TO_BCSTR_FILLCENTER + * , slots before the formatting string are filled. + * + * The \a precision parameter specified the minimum number of digits to + * produce from the \a value. If \a value produces fewer digits than + * \a precision, the actual digits are padded with '0' to meet the precision + * requirement. You can pass a negative number if you don't wish to specify + * precision. + * + * The terminating null is not added if #MOO_FMT_INTMAX_TO_BCSTR_NONULL is set; + * The #MOO_FMT_INTMAX_TO_BCSTR_UPPERCASE flag indicates that the function should + * use the uppercase letter for a alphabetic digit; + * You can set #MOO_FMT_INTMAX_TO_BCSTR_NOTRUNC if you require lossless formatting. + * The #MOO_FMT_INTMAX_TO_BCSTR_PLUSSIGN flag and #MOO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN + * ensures that the plus sign and a space is added for a positive integer + * including 0 respectively. + * The #MOO_FMT_INTMAX_TO_BCSTR_ZEROLEAD flag ensures that the numeric string + * begins with '0' before applying the prefix. + * You can set the #MOO_FMT_INTMAX_TO_BCSTR_NOZERO flag if you want the value of + * 0 to produce nothing. If both #MOO_FMT_INTMAX_TO_BCSTR_NOZERO and + * #MOO_FMT_INTMAX_TO_BCSTR_ZEROLEAD are specified, '0' is still produced. + * + * If \a prefix is not #MOO_NULL, it is inserted before the digits. + * + * \return + * - -1 if the base is not between 2 and 36 inclusive. + * - negated number of characters required for lossless formatting + * - if \a bufsize is 0. + * - if #MOO_FMT_INTMAX_TO_BCSTR_NOTRUNC is set and \a bufsize is less than + * the minimum required for lossless formatting. + * - number of characters written to the buffer excluding a terminating + * null in all other cases. + */ +MOO_EXPORT int moo_fmt_intmax_to_bcstr ( + moo_bch_t* buf, /**< buffer pointer */ + int bufsize, /**< buffer size */ + moo_intmax_t value, /**< integer to format */ + int base_and_flags, /**< base ORed with flags */ + int precision, /**< precision */ + moo_bch_t fillchar, /**< fill character */ + const moo_bch_t* prefix /**< prefix */ +); + +/** + * The moo_fmt_intmax_to_ucstr() function formats an integer \a value to a + * wide-character string according to the given base and writes it to a buffer + * pointed to by \a buf. It writes to the buffer at most \a size characters + * including the terminating null. The base must be between 2 and 36 inclusive + * and can be ORed with zero or more #moo_fmt_intmax_to_ucstr_flag_t enumerators. + * This ORed value is passed to the function via the \a base_and_flags + * parameter. If the formatted string is shorter than \a bufsize, the redundant + * slots are filled with the fill character \a fillchar if it is not a null + * character. The filling behavior is determined by the flags shown below: + * + * - If #MOO_FMT_INTMAX_TO_UCSTR_FILLRIGHT is set in \a base_and_flags, slots + * after the formatting string are filled. + * - If #MOO_FMT_INTMAX_TO_UCSTR_FILLCENTER is set in \a base_and_flags, slots + * before the formatting string are filled. However, if it contains the + * sign character, the slots between the sign character and the digit part + * are filled. + * - If neither #MOO_FMT_INTMAX_TO_UCSTR_FILLRIGHT nor #MOO_FMT_INTMAX_TO_UCSTR_FILLCENTER + * , slots before the formatting string are filled. + * + * The \a precision parameter specified the minimum number of digits to + * produce from the \ value. If \a value produces fewer digits than + * \a precision, the actual digits are padded with '0' to meet the precision + * requirement. You can pass a negative number if don't wish to specify + * precision. + * + * The terminating null is not added if #MOO_FMT_INTMAX_TO_UCSTR_NONULL is set; + * The #MOO_FMT_INTMAX_TO_UCSTR_UPPERCASE flag indicates that the function should + * use the uppercase letter for a alphabetic digit; + * You can set #MOO_FMT_INTMAX_TO_UCSTR_NOTRUNC if you require lossless formatting. + * The #MOO_FMT_INTMAX_TO_UCSTR_PLUSSIGN flag and #MOO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN + * ensures that the plus sign and a space is added for a positive integer + * including 0 respectively. + * The #MOO_FMT_INTMAX_TO_UCSTR_ZEROLEAD flag ensures that the numeric string + * begins with 0 before applying the prefix. + * You can set the #MOO_FMT_INTMAX_TO_UCSTR_NOZERO flag if you want the value of + * 0 to produce nothing. If both #MOO_FMT_INTMAX_TO_UCSTR_NOZERO and + * #MOO_FMT_INTMAX_TO_UCSTR_ZEROLEAD are specified, '0' is still produced. + * + * If \a prefix is not #MOO_NULL, it is inserted before the digits. + * + * \return + * - -1 if the base is not between 2 and 36 inclusive. + * - negated number of characters required for lossless formatting + * - if \a bufsize is 0. + * - if #MOO_FMT_INTMAX_TO_UCSTR_NOTRUNC is set and \a bufsize is less than + * the minimum required for lossless formatting. + * - number of characters written to the buffer excluding a terminating + * null in all other cases. + */ +MOO_EXPORT int moo_fmt_intmax_to_ucstr ( + moo_uch_t* buf, /**< buffer pointer */ + int bufsize, /**< buffer size */ + moo_intmax_t value, /**< integer to format */ + int base_and_flags, /**< base ORed with flags */ + int precision, /**< precision */ + moo_uch_t fillchar, /**< fill character */ + const moo_uch_t* prefix /**< prefix */ +); + +/** \def moo_fmt_intmax + * The moo_fmt_intmax() macro maps to moo_fmt_intmax_to_bcstr() if + * #MOO_OOCH_IS_BCH, and moo_fmt_intmax_to_ucstr() if #MOO_CHAR_IS_WCHAR. + */ +#ifdef MOO_OOCH_IS_BCH +# define moo_fmt_intmax(b,sz,v,bf,pr,fc,pf) moo_fmt_intmax_to_bcstr(b,sz,v,bf,pr,fc,pf) +#else +# define moo_fmt_intmax(b,sz,v,bf,pr,fc,pf) moo_fmt_intmax_to_ucstr(b,sz,v,bf,pr,fc,pf) +#endif + +/** + * The moo_fmt_uintmax_to_bcstr() function formats an unsigned integer \a value + * to a multibyte string buffer. It behaves the same as moo_fmt_uintmax_to_bcstr() + * except that it handles an unsigned integer. + */ +MOO_EXPORT int moo_fmt_uintmax_to_bcstr ( + moo_bch_t* buf, /**< buffer pointer */ + int bufsize, /**< buffer size */ + moo_uintmax_t value, /**< integer to format */ + int base_and_flags, /**< base ORed with flags */ + int precision, /**< precision */ + moo_bch_t fillchar, /**< fill character */ + const moo_bch_t* prefix /**< prefix */ +); + +/* TODO: moo_fmt_fltmax_to_bcstr()... moo_fmt_fltmax_to_ucstr() */ + + +/* ========================================================================= + * FORMATTED OUTPUT + * ========================================================================= */ +MOO_EXPORT int moo_bfmt_outv ( + moo_fmtout_t* fmtout, + const moo_bch_t* fmt, + va_list ap +); + +MOO_EXPORT int moo_ufmt_outv ( + moo_fmtout_t* fmtout, + const moo_uch_t* fmt, + va_list ap +); + + +MOO_EXPORT int moo_bfmt_out ( + moo_fmtout_t* fmtout, + const moo_bch_t* fmt, + ... +); + +MOO_EXPORT int moo_ufmt_out ( + moo_fmtout_t* fmtout, + const moo_uch_t* fmt, + ... +); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index cb8f6ef..0dc6cbb 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -28,6 +28,7 @@ #define _MOO_PRV_H_ #include +#include #include /* you can define this to either 1 or 2 */ diff --git a/moo/lib/moo-utl.h b/moo/lib/moo-utl.h index 918e431..9e2abca 100644 --- a/moo/lib/moo-utl.h +++ b/moo/lib/moo-utl.h @@ -295,52 +295,6 @@ enum moo_cmgr_id_t }; typedef enum moo_cmgr_id_t moo_cmgr_id_t; - -/* ========================================================================= - * FORMATTED OUTPUT - * ========================================================================= */ -typedef struct moo_fmtout_t moo_fmtout_t; - -typedef int (*moo_fmtout_putbchars_t) ( - moo_fmtout_t* fmtout, - const moo_bch_t* ptr, - moo_oow_t len -); - -typedef int (*moo_fmtout_putuchars_t) ( - moo_fmtout_t* fmtout, - const moo_uch_t* ptr, - moo_oow_t len -); - -typedef int (*moo_fmtout_putobj_t) ( - moo_fmtout_t* fmtout, - moo_oop_t obj -); - -enum moo_fmtout_fmt_type_t -{ - MOO_FMTOUT_FMT_TYPE_BCH = 0, - MOO_FMTOUT_FMT_TYPE_UCH -}; -typedef enum moo_fmtout_fmt_type_t moo_fmtout_fmt_type_t; - - -struct moo_fmtout_t -{ - moo_oow_t count; /* out */ - - moo_fmtout_putbchars_t putbchars; /* in */ - moo_fmtout_putuchars_t putuchars; /* in */ - moo_fmtout_putobj_t putobj; /* in - %O is not handled if it's not set. */ - moo_bitmask_t mask; /* in */ - void* ctx; /* in */ - - moo_fmtout_fmt_type_t fmt_type; - const void* fmt_str; -}; - - #if defined(__cplusplus) extern "C" { #endif @@ -898,34 +852,6 @@ MOO_EXPORT moo_oow_t moo_mb8_to_uc ( moo_uch_t* uc ); -/* ========================================================================= - * FORMATTED OUTPUT - * ========================================================================= */ -MOO_EXPORT int moo_bfmt_outv ( - moo_fmtout_t* fmtout, - const moo_bch_t* fmt, - va_list ap -); - -MOO_EXPORT int moo_ufmt_outv ( - moo_fmtout_t* fmtout, - const moo_uch_t* fmt, - va_list ap -); - - -MOO_EXPORT int moo_bfmt_out ( - moo_fmtout_t* fmtout, - const moo_bch_t* fmt, - ... -); - -MOO_EXPORT int moo_ufmt_out ( - moo_fmtout_t* fmtout, - const moo_uch_t* fmt, - ... -); - /* ========================================================================= * BIT SWAP * ========================================================================= */