diff --git a/mio/lib/Makefile.am b/mio/lib/Makefile.am index 5dc82f1..17b7543 100644 --- a/mio/lib/Makefile.am +++ b/mio/lib/Makefile.am @@ -23,6 +23,7 @@ include_HEADERS = \ mio-cfg.h \ mio-cmn.h \ mio-dns.h \ + mio-fmt.h \ mio-nwif.h \ mio-pac1.h \ mio-pro.h \ @@ -37,6 +38,7 @@ libmio_la_SOURCES = \ dns.c \ err.c \ fmt.c \ + fmt-imp.h \ mio-prv.h \ mio-sys.h \ mio.c \ diff --git a/mio/lib/Makefile.in b/mio/lib/Makefile.in index 5630500..3637f9b 100644 --- a/mio/lib/Makefile.in +++ b/mio/lib/Makefile.in @@ -398,6 +398,7 @@ include_HEADERS = \ mio-cfg.h \ mio-cmn.h \ mio-dns.h \ + mio-fmt.h \ mio-nwif.h \ mio-pac1.h \ mio-pro.h \ @@ -412,6 +413,7 @@ libmio_la_SOURCES = \ dns.c \ err.c \ fmt.c \ + fmt-imp.h \ mio-prv.h \ mio-sys.h \ mio.c \ diff --git a/mio/lib/err.c b/mio/lib/err.c index 61c9803..773dfbe 100644 --- a/mio/lib/err.c +++ b/mio/lib/err.c @@ -25,6 +25,7 @@ */ #include "mio-prv.h" +#include "mio-fmt.h" static mio_ooch_t errstr_0[] = {'n', 'o', ' ', 'e', 'r', 'r', 'o', 'r', '\0' }; static mio_ooch_t errstr_1[] = {'g', 'e', 'n', 'e', 'r', 'i', 'c', ' ', 'e', 'r', 'r', 'o', 'r', '\0' }; diff --git a/mio/lib/fmt-imp.h b/mio/lib/fmt-imp.h new file mode 100644 index 0000000..3a94dc1 --- /dev/null +++ b/mio/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, + mio_uintmax_t value, int base_and_flags, int prec, + char_t fillchar, char_t signchar, const char_t* prefix) +{ + char_t tmp[(MIO_SIZEOF(mio_uintmax_t) * 8)]; + int reslen, base, fillsize, reqlen, pflen, preczero; + char_t* p, * bp, * be; + const mio_bch_t* xbasestr; + + base = base_and_flags & 0x3F; + if (base < 2 || base > 36) return -1; + + xbasestr = (base_and_flags & MIO_FMT_INTMAX_UPPERCASE)? + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ": + "0123456789abcdefghijklmnopqrstuvwxyz"; + + if ((base_and_flags & MIO_FMT_INTMAX_NOZERO) && value == 0) + { + p = tmp; + if (base_and_flags & MIO_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 + { + mio_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 & MIO_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 & MIO_FMT_INTMAX_NONULL)? reslen: (reslen + 1); + + if (size <= 0 || + ((base_and_flags & MIO_FMT_INTMAX_NOTRUNC) && size < reqlen)) + { + return -reqlen; + } + + /* get the size to fill with fill characters */ + fillsize = (base_and_flags & MIO_FMT_INTMAX_NONULL)? size: (size - 1); + bp = buf; + be = buf + fillsize; + + /* fill space */ + if (fillchar != '\0') + { + if (base_and_flags & MIO_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 & MIO_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 & MIO_FMT_INTMAX_NONULL)) *bp = '\0'; + return bp - buf; +} diff --git a/mio/lib/fmt.c b/mio/lib/fmt.c index 70dfcea..7211ff1 100644 --- a/mio/lib/fmt.c +++ b/mio/lib/fmt.c @@ -64,7 +64,7 @@ * */ - +#include "mio-fmt.h" #include "mio-prv.h" @@ -1615,3 +1615,136 @@ mio_ooi_t mio_logufmt (mio_t* mio, mio_bitmask_t mask, const mio_uch_t* fmt, ... return x; } + +/* ------------------------------------------------------------------------------------- */ + +/*define static int fmt_uintmax_to_bcstr(...)*/ +#undef char_t +#undef fmt_uintmax +#define char_t mio_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 mio_uch_t +#define fmt_uintmax fmt_uintmax_to_ucstr +#include "fmt-imp.h" + +/* ------------------------------------------------------------------------------------- */ + +int mio_fmt_intmax_to_bcstr ( + mio_bch_t* buf, int size, + mio_intmax_t value, int base_and_flags, int prec, + mio_bch_t fillchar, const mio_bch_t* prefix) +{ + mio_bch_t signchar; + mio_uintmax_t absvalue; + + if (value < 0) + { + signchar = '-'; + absvalue = -value; + } + else if (base_and_flags & MIO_FMT_INTMAX_TO_BCSTR_PLUSSIGN) + { + signchar = '+'; + absvalue = value; + } + else if (base_and_flags & MIO_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 mio_fmt_uintmax_to_bcstr ( + mio_bch_t* buf, int size, + mio_uintmax_t value, int base_and_flags, int prec, + mio_bch_t fillchar, const mio_bch_t* prefix) +{ + mio_bch_t signchar; + + /* determine if a sign character is needed */ + if (base_and_flags & MIO_FMT_INTMAX_TO_BCSTR_PLUSSIGN) + { + signchar = '+'; + } + else if (base_and_flags & MIO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN) + { + signchar = ' '; + } + else + { + signchar = '\0'; + } + + return fmt_uintmax_to_bcstr(buf, size, value, base_and_flags, prec, fillchar, signchar, prefix); +} + +/* ------------------------------------------------------------------------------------- */ + +int mio_fmt_intmax_to_ucstr ( + mio_uch_t* buf, int size, + mio_intmax_t value, int base_and_flags, int prec, + mio_uch_t fillchar, const mio_uch_t* prefix) +{ + mio_uch_t signchar; + mio_uintmax_t absvalue; + + if (value < 0) + { + signchar = '-'; + absvalue = -value; + } + else if (base_and_flags & MIO_FMT_INTMAX_TO_UCSTR_PLUSSIGN) + { + signchar = '+'; + absvalue = value; + } + else if (base_and_flags & MIO_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 mio_fmt_uintmax_to_ucstr ( + mio_uch_t* buf, int size, + mio_uintmax_t value, int base_and_flags, int prec, + mio_uch_t fillchar, const mio_uch_t* prefix) +{ + mio_uch_t signchar; + + /* determine if a sign character is needed */ + if (base_and_flags & MIO_FMT_INTMAX_TO_UCSTR_PLUSSIGN) + { + signchar = '+'; + } + else if (base_and_flags & MIO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN) + { + signchar = ' '; + } + else + { + signchar = '\0'; + } + + return fmt_uintmax_to_ucstr(buf, size, value, base_and_flags, prec, fillchar, signchar, prefix); +} + diff --git a/mio/lib/mio-cmn.h b/mio/lib/mio-cmn.h index 141ad53..debe95b 100644 --- a/mio/lib/mio-cmn.h +++ b/mio/lib/mio-cmn.h @@ -428,6 +428,8 @@ typedef struct mio_bcs_t mio_bcs_t; /* the maximum number of bch charaters to represent a single uch character */ #define MIO_BCSIZE_MAX 6 +typedef unsigned int mio_bitmask_t; + /* ========================================================================= * TIME-RELATED TYPES * =========================================================================*/ diff --git a/mio/lib/mio-fmt.h b/mio/lib/mio-fmt.h new file mode 100644 index 0000000..8c8c7e7 --- /dev/null +++ b/mio/lib/mio-fmt.h @@ -0,0 +1,389 @@ +/* + * $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 _MIO_FMT_H_ +#define _MIO_FMT_H_ + +#include +#include + +/** \file + * This file defines various formatting functions. + */ + +/* ========================================================================= + * FORMATTED OUTPUT + * ========================================================================= */ +typedef struct mio_fmtout_t mio_fmtout_t; + +typedef int (*mio_fmtout_putbcs_t) ( + mio_fmtout_t* fmtout, + const mio_bch_t* ptr, + mio_oow_t len +); + +typedef int (*mio_fmtout_putucs_t) ( + mio_fmtout_t* fmtout, + const mio_uch_t* ptr, + mio_oow_t len +); + +enum mio_fmtout_fmt_type_t +{ + MIO_FMTOUT_FMT_TYPE_BCH = 0, + MIO_FMTOUT_FMT_TYPE_UCH +}; +typedef enum mio_fmtout_fmt_type_t mio_fmtout_fmt_type_t; + + +struct mio_fmtout_t +{ + mio_oow_t count; /* out */ + + mio_fmtout_putbcs_t putbcs; /* in */ + mio_fmtout_putucs_t putucs; /* in */ + mio_bitmask_t mask; /* in */ + void* ctx; /* in */ + + mio_fmtout_fmt_type_t fmt_type; + const void* fmt_str; +}; + +/* ========================================================================= + * INTMAX FORMATTING + * ========================================================================= */ +/** + * The mio_fmt_intmax_flag_t type defines enumerators to change the + * behavior of mio_fmt_intmax() and mio_fmt_uintmax(). + */ +enum mio_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 */ + MIO_FMT_INTMAX_NOTRUNC = (0x40 << 0), +#define MIO_FMT_INTMAX_NOTRUNC MIO_FMT_INTMAX_NOTRUNC +#define MIO_FMT_UINTMAX_NOTRUNC MIO_FMT_INTMAX_NOTRUNC +#define MIO_FMT_INTMAX_TO_BCSTR_NOTRUNC MIO_FMT_INTMAX_NOTRUNC +#define MIO_FMT_UINTMAX_TO_BCSTR_NOTRUNC MIO_FMT_INTMAX_NOTRUNC +#define MIO_FMT_INTMAX_TO_UCSTR_NOTRUNC MIO_FMT_INTMAX_NOTRUNC +#define MIO_FMT_UINTMAX_TO_UCSTR_NOTRUNC MIO_FMT_INTMAX_NOTRUNC +#define MIO_FMT_INTMAX_TO_OOCSTR_NOTRUNC MIO_FMT_INTMAX_NOTRUNC +#define MIO_FMT_UINTMAX_TO_OOCSTR_NOTRUNC MIO_FMT_INTMAX_NOTRUNC + + /** Don't append a terminating null */ + MIO_FMT_INTMAX_NONULL = (0x40 << 1), +#define MIO_FMT_INTMAX_NONULL MIO_FMT_INTMAX_NONULL +#define MIO_FMT_UINTMAX_NONULL MIO_FMT_INTMAX_NONULL +#define MIO_FMT_INTMAX_TO_BCSTR_NONULL MIO_FMT_INTMAX_NONULL +#define MIO_FMT_UINTMAX_TO_BCSTR_NONULL MIO_FMT_INTMAX_NONULL +#define MIO_FMT_INTMAX_TO_UCSTR_NONULL MIO_FMT_INTMAX_NONULL +#define MIO_FMT_UINTMAX_TO_UCSTR_NONULL MIO_FMT_INTMAX_NONULL +#define MIO_FMT_INTMAX_TO_OOCSTR_NONULL MIO_FMT_INTMAX_NONULL +#define MIO_FMT_UINTMAX_TO_OOCSTR_NONULL MIO_FMT_INTMAX_NONULL + + /** Produce no digit for a value of zero */ + MIO_FMT_INTMAX_NOZERO = (0x40 << 2), +#define MIO_FMT_INTMAX_NOZERO MIO_FMT_INTMAX_NOZERO +#define MIO_FMT_UINTMAX_NOZERO MIO_FMT_INTMAX_NOZERO +#define MIO_FMT_INTMAX_TO_BCSTR_NOZERO MIO_FMT_INTMAX_NOZERO +#define MIO_FMT_UINTMAX_TO_BCSTR_NOZERO MIO_FMT_INTMAX_NOZERO +#define MIO_FMT_INTMAX_TO_UCSTR_NOZERO MIO_FMT_INTMAX_NOZERO +#define MIO_FMT_UINTMAX_TO_UCSTR_NOZERO MIO_FMT_INTMAX_NOZERO +#define MIO_FMT_INTMAX_TO_OOCSTR_NOZERO MIO_FMT_INTMAX_NOZERO +#define MIO_FMT_UINTMAX_TO_OOCSTR_NOZERO MIO_FMT_INTMAX_NOZERO + + /** Produce a leading zero for a non-zero value */ + MIO_FMT_INTMAX_ZEROLEAD = (0x40 << 3), +#define MIO_FMT_INTMAX_ZEROLEAD MIO_FMT_INTMAX_ZEROLEAD +#define MIO_FMT_UINTMAX_ZEROLEAD MIO_FMT_INTMAX_ZEROLEAD +#define MIO_FMT_INTMAX_TO_BCSTR_ZEROLEAD MIO_FMT_INTMAX_ZEROLEAD +#define MIO_FMT_UINTMAX_TO_BCSTR_ZEROLEAD MIO_FMT_INTMAX_ZEROLEAD +#define MIO_FMT_INTMAX_TO_UCSTR_ZEROLEAD MIO_FMT_INTMAX_ZEROLEAD +#define MIO_FMT_UINTMAX_TO_UCSTR_ZEROLEAD MIO_FMT_INTMAX_ZEROLEAD +#define MIO_FMT_INTMAX_TO_OOCSTR_ZEROLEAD MIO_FMT_INTMAX_ZEROLEAD +#define MIO_FMT_UINTMAX_TO_OOCSTR_ZEROLEAD MIO_FMT_INTMAX_ZEROLEAD + + /** Use uppercase letters for alphabetic digits */ + MIO_FMT_INTMAX_UPPERCASE = (0x40 << 4), +#define MIO_FMT_INTMAX_UPPERCASE MIO_FMT_INTMAX_UPPERCASE +#define MIO_FMT_UINTMAX_UPPERCASE MIO_FMT_INTMAX_UPPERCASE +#define MIO_FMT_INTMAX_TO_BCSTR_UPPERCASE MIO_FMT_INTMAX_UPPERCASE +#define MIO_FMT_UINTMAX_TO_BCSTR_UPPERCASE MIO_FMT_INTMAX_UPPERCASE +#define MIO_FMT_INTMAX_TO_UCSTR_UPPERCASE MIO_FMT_INTMAX_UPPERCASE +#define MIO_FMT_UINTMAX_TO_UCSTR_UPPERCASE MIO_FMT_INTMAX_UPPERCASE +#define MIO_FMT_INTMAX_TO_OOCSTR_UPPERCASE MIO_FMT_INTMAX_UPPERCASE +#define MIO_FMT_UINTMAX_TO_OOCSTR_UPPERCASE MIO_FMT_INTMAX_UPPERCASE + + /** Insert a plus sign for a positive integer including 0 */ + MIO_FMT_INTMAX_PLUSSIGN = (0x40 << 5), +#define MIO_FMT_INTMAX_PLUSSIGN MIO_FMT_INTMAX_PLUSSIGN +#define MIO_FMT_UINTMAX_PLUSSIGN MIO_FMT_INTMAX_PLUSSIGN +#define MIO_FMT_INTMAX_TO_BCSTR_PLUSSIGN MIO_FMT_INTMAX_PLUSSIGN +#define MIO_FMT_UINTMAX_TO_BCSTR_PLUSSIGN MIO_FMT_INTMAX_PLUSSIGN +#define MIO_FMT_INTMAX_TO_UCSTR_PLUSSIGN MIO_FMT_INTMAX_PLUSSIGN +#define MIO_FMT_UINTMAX_TO_UCSTR_PLUSSIGN MIO_FMT_INTMAX_PLUSSIGN +#define MIO_FMT_INTMAX_TO_OOCSTR_PLUSSIGN MIO_FMT_INTMAX_PLUSSIGN +#define MIO_FMT_UINTMAX_TO_OOCSTR_PLUSSIGN MIO_FMT_INTMAX_PLUSSIGN + + /** Insert a space for a positive integer including 0 */ + MIO_FMT_INTMAX_EMPTYSIGN = (0x40 << 6), +#define MIO_FMT_INTMAX_EMPTYSIGN MIO_FMT_INTMAX_EMPTYSIGN +#define MIO_FMT_UINTMAX_EMPTYSIGN MIO_FMT_INTMAX_EMPTYSIGN +#define MIO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN MIO_FMT_INTMAX_EMPTYSIGN +#define MIO_FMT_UINTMAX_TO_BCSTR_EMPTYSIGN MIO_FMT_INTMAX_EMPTYSIGN +#define MIO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN MIO_FMT_INTMAX_EMPTYSIGN +#define MIO_FMT_UINTMAX_TO_UCSTR_EMPTYSIGN MIO_FMT_INTMAX_EMPTYSIGN + + /** Fill the right part of the string */ + MIO_FMT_INTMAX_FILLRIGHT = (0x40 << 7), +#define MIO_FMT_INTMAX_FILLRIGHT MIO_FMT_INTMAX_FILLRIGHT +#define MIO_FMT_UINTMAX_FILLRIGHT MIO_FMT_INTMAX_FILLRIGHT +#define MIO_FMT_INTMAX_TO_BCSTR_FILLRIGHT MIO_FMT_INTMAX_FILLRIGHT +#define MIO_FMT_UINTMAX_TO_BCSTR_FILLRIGHT MIO_FMT_INTMAX_FILLRIGHT +#define MIO_FMT_INTMAX_TO_UCSTR_FILLRIGHT MIO_FMT_INTMAX_FILLRIGHT +#define MIO_FMT_UINTMAX_TO_UCSTR_FILLRIGHT MIO_FMT_INTMAX_FILLRIGHT +#define MIO_FMT_INTMAX_TO_OOCSTR_FILLRIGHT MIO_FMT_INTMAX_FILLRIGHT +#define MIO_FMT_UINTMAX_TO_OOCSTR_FILLRIGHT MIO_FMT_INTMAX_FILLRIGHT + + /** Fill between the sign chacter and the digit part */ + MIO_FMT_INTMAX_FILLCENTER = (0x40 << 8) +#define MIO_FMT_INTMAX_FILLCENTER MIO_FMT_INTMAX_FILLCENTER +#define MIO_FMT_UINTMAX_FILLCENTER MIO_FMT_INTMAX_FILLCENTER +#define MIO_FMT_INTMAX_TO_BCSTR_FILLCENTER MIO_FMT_INTMAX_FILLCENTER +#define MIO_FMT_UINTMAX_TO_BCSTR_FILLCENTER MIO_FMT_INTMAX_FILLCENTER +#define MIO_FMT_INTMAX_TO_UCSTR_FILLCENTER MIO_FMT_INTMAX_FILLCENTER +#define MIO_FMT_UINTMAX_TO_UCSTR_FILLCENTER MIO_FMT_INTMAX_FILLCENTER +#define MIO_FMT_INTMAX_TO_OOCSTR_FILLCENTER MIO_FMT_INTMAX_FILLCENTER +#define MIO_FMT_UINTMAX_TO_OOCSTR_FILLCENTER MIO_FMT_INTMAX_FILLCENTER +}; + +#if defined(__cplusplus) +extern "C" { +#endif + +/* ========================================================================= + * FORMATTED OUTPUT + * ========================================================================= */ + +MIO_EXPORT int mio_bfmt_outv ( + mio_fmtout_t* fmtout, + const mio_bch_t* fmt, + va_list ap +); + +MIO_EXPORT int mio_ufmt_outv ( + mio_fmtout_t* fmtout, + const mio_uch_t* fmt, + va_list ap +); + + +MIO_EXPORT int mio_bfmt_out ( + mio_fmtout_t* fmtout, + const mio_bch_t* fmt, + ... +); + +MIO_EXPORT int mio_ufmt_out ( + mio_fmtout_t* fmtout, + const mio_uch_t* fmt, + ... +); + + + +/* ========================================================================= + * INTMAX FORMATTING + * ========================================================================= */ + +/** + * The mio_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 #mio_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 #MIO_FMT_INTMAX_TO_BCSTR_FILLRIGHT is set in \a base_and_flags, slots + * after the formatting string are filled. + * - If #MIO_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 #MIO_FMT_INTMAX_TO_BCSTR_FILLRIGHT nor #MIO_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 #MIO_FMT_INTMAX_TO_BCSTR_NONULL is set; + * The #MIO_FMT_INTMAX_TO_BCSTR_UPPERCASE flag indicates that the function should + * use the uppercase letter for a alphabetic digit; + * You can set #MIO_FMT_INTMAX_TO_BCSTR_NOTRUNC if you require lossless formatting. + * The #MIO_FMT_INTMAX_TO_BCSTR_PLUSSIGN flag and #MIO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN + * ensures that the plus sign and a space is added for a positive integer + * including 0 respectively. + * The #MIO_FMT_INTMAX_TO_BCSTR_ZEROLEAD flag ensures that the numeric string + * begins with '0' before applying the prefix. + * You can set the #MIO_FMT_INTMAX_TO_BCSTR_NOZERO flag if you want the value of + * 0 to produce nothing. If both #MIO_FMT_INTMAX_TO_BCSTR_NOZERO and + * #MIO_FMT_INTMAX_TO_BCSTR_ZEROLEAD are specified, '0' is still produced. + * + * If \a prefix is not #MIO_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 #MIO_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. + */ +MIO_EXPORT int mio_fmt_intmax_to_bcstr ( + mio_bch_t* buf, /**< buffer pointer */ + int bufsize, /**< buffer size */ + mio_intmax_t value, /**< integer to format */ + int base_and_flags, /**< base ORed with flags */ + int precision, /**< precision */ + mio_bch_t fillchar, /**< fill character */ + const mio_bch_t* prefix /**< prefix */ +); + +/** + * The mio_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 #mio_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 #MIO_FMT_INTMAX_TO_UCSTR_FILLRIGHT is set in \a base_and_flags, slots + * after the formatting string are filled. + * - If #MIO_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 #MIO_FMT_INTMAX_TO_UCSTR_FILLRIGHT nor #MIO_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 #MIO_FMT_INTMAX_TO_UCSTR_NONULL is set; + * The #MIO_FMT_INTMAX_TO_UCSTR_UPPERCASE flag indicates that the function should + * use the uppercase letter for a alphabetic digit; + * You can set #MIO_FMT_INTMAX_TO_UCSTR_NOTRUNC if you require lossless formatting. + * The #MIO_FMT_INTMAX_TO_UCSTR_PLUSSIGN flag and #MIO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN + * ensures that the plus sign and a space is added for a positive integer + * including 0 respectively. + * The #MIO_FMT_INTMAX_TO_UCSTR_ZEROLEAD flag ensures that the numeric string + * begins with 0 before applying the prefix. + * You can set the #MIO_FMT_INTMAX_TO_UCSTR_NOZERO flag if you want the value of + * 0 to produce nothing. If both #MIO_FMT_INTMAX_TO_UCSTR_NOZERO and + * #MIO_FMT_INTMAX_TO_UCSTR_ZEROLEAD are specified, '0' is still produced. + * + * If \a prefix is not #MIO_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 #MIO_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. + */ +MIO_EXPORT int mio_fmt_intmax_to_ucstr ( + mio_uch_t* buf, /**< buffer pointer */ + int bufsize, /**< buffer size */ + mio_intmax_t value, /**< integer to format */ + int base_and_flags, /**< base ORed with flags */ + int precision, /**< precision */ + mio_uch_t fillchar, /**< fill character */ + const mio_uch_t* prefix /**< prefix */ +); + + +/** + * The mio_fmt_uintmax_to_bcstr() function formats an unsigned integer \a value + * to a multibyte string buffer. It behaves the same as mio_fmt_intmax_to_bcstr() + * except that it handles an unsigned integer. + */ +MIO_EXPORT int mio_fmt_uintmax_to_bcstr ( + mio_bch_t* buf, /**< buffer pointer */ + int bufsize, /**< buffer size */ + mio_uintmax_t value, /**< integer to format */ + int base_and_flags, /**< base ORed with flags */ + int precision, /**< precision */ + mio_bch_t fillchar, /**< fill character */ + const mio_bch_t* prefix /**< prefix */ +); + +/** + * The mio_fmt_uintmax_to_ucstr() function formats an unsigned integer \a value + * to a unicode string buffer. It behaves the same as mio_fmt_intmax_to_ucstr() + * except that it handles an unsigned integer. + */ +MIO_EXPORT int mio_fmt_uintmax_to_ucstr ( + mio_uch_t* buf, /**< buffer pointer */ + int bufsize, /**< buffer size */ + mio_uintmax_t value, /**< integer to format */ + int base_and_flags, /**< base ORed with flags */ + int precision, /**< precision */ + mio_uch_t fillchar, /**< fill character */ + const mio_uch_t* prefix /**< prefix */ +); + +#if defined(MIO_OOCH_IS_BCH) +# define mio_fmt_intmax_to_oocstr mio_fmt_intmax_to_bcstr +# define mio_fmt_uintmax_to_oocstr mio_fmt_uintmax_to_bcstr +#else +# define mio_fmt_intmax_to_oocstr mio_fmt_intmax_to_ucstr +# define mio_fmt_uintmax_to_oocstr mio_fmt_uintmax_to_ucstr +#endif + +/* TODO: mio_fmt_fltmax_to_bcstr()... mio_fmt_fltmax_to_ucstr() */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/mio/lib/mio-utl.h b/mio/lib/mio-utl.h index 2155735..ad22bf6 100644 --- a/mio/lib/mio-utl.h +++ b/mio/lib/mio-utl.h @@ -155,45 +155,6 @@ # error UNKNOWN ENDIAN #endif -/* ========================================================================= - * FORMATTED OUTPUT - * ========================================================================= */ -typedef struct mio_fmtout_t mio_fmtout_t; - -typedef int (*mio_fmtout_putbcs_t) ( - mio_fmtout_t* fmtout, - const mio_bch_t* ptr, - mio_oow_t len -); - -typedef int (*mio_fmtout_putucs_t) ( - mio_fmtout_t* fmtout, - const mio_uch_t* ptr, - mio_oow_t len -); - -enum mio_fmtout_fmt_type_t -{ - MIO_FMTOUT_FMT_TYPE_BCH = 0, - MIO_FMTOUT_FMT_TYPE_UCH -}; -typedef enum mio_fmtout_fmt_type_t mio_fmtout_fmt_type_t; - - -struct mio_fmtout_t -{ - mio_oow_t count; /* out */ - - mio_fmtout_putbcs_t putbcs; /* in */ - mio_fmtout_putucs_t putucs; /* in */ - mio_bitmask_t mask; /* in */ - void* ctx; /* in */ - - mio_fmtout_fmt_type_t fmt_type; - const void* fmt_str; -}; - - #ifdef __cplusplus extern "C" { #endif @@ -609,35 +570,6 @@ MIO_EXPORT mio_oow_t mio_utf8_to_uc ( mio_uch_t* uc ); - -/* ========================================================================= - * FORMATTED OUTPUT - * ========================================================================= */ -MIO_EXPORT int mio_bfmt_outv ( - mio_fmtout_t* fmtout, - const mio_bch_t* fmt, - va_list ap -); - -MIO_EXPORT int mio_ufmt_outv ( - mio_fmtout_t* fmtout, - const mio_uch_t* fmt, - va_list ap -); - - -MIO_EXPORT int mio_bfmt_out ( - mio_fmtout_t* fmtout, - const mio_bch_t* fmt, - ... -); - -MIO_EXPORT int mio_ufmt_out ( - mio_fmtout_t* fmtout, - const mio_uch_t* fmt, - ... -); - /* ========================================================================= * BIT SWAP * ========================================================================= */ diff --git a/mio/lib/mio.h b/mio/lib/mio.h index 36bfcbe..523e257 100644 --- a/mio/lib/mio.h +++ b/mio/lib/mio.h @@ -63,8 +63,6 @@ typedef struct mio_wq_t mio_wq_t; typedef struct mio_cwq_t mio_cwq_t; typedef mio_intptr_t mio_iolen_t; /* NOTE: this is a signed type */ -typedef unsigned int mio_bitmask_t; - enum mio_errnum_t { MIO_ENOERR, /**< no error */ diff --git a/mio/lib/skad.c b/mio/lib/skad.c index 59ec117..b601087 100644 --- a/mio/lib/skad.c +++ b/mio/lib/skad.c @@ -26,6 +26,7 @@ #include "mio-skad.h" #include "mio-nwif.h" +#include "mio-fmt.h" #include "mio-prv.h" #include @@ -945,7 +946,7 @@ static mio_oow_t ip6addr_to_ucstr (const struct in6_addr* ipad, mio_uch_t* buf, break; } -/* TODO tp += mio_fmt_uintmax_to_ucstr(tp, MIO_COUNTOF(tmp) - (tp - tmp), words[i], 16, 0, '\0', MIO_NULL); */ + tp += mio_fmt_uintmax_to_ucstr(tp, MIO_COUNTOF(tmp) - (tp - tmp), words[i], 16, 0, '\0', MIO_NULL); } /* Was it a trailing run of 0x00's? */ @@ -985,7 +986,7 @@ mio_oow_t mio_skadtoucstr (mio_t* mio, const mio_skad_t* _skad, mio_uch_t* buf, } if (xlen + 1 >= len) goto done; -/* TODO xlen += mio_fmt_uintmax_to_ucstr(&buf[xlen], len - xlen, mio_ntoh16(skad->in4.sin_port), 10, 0, '\0', MIO_NULL); */ + xlen += mio_fmt_uintmax_to_ucstr(&buf[xlen], len - xlen, mio_ntoh16(skad->in4.sin_port), 10, 0, '\0', MIO_NULL); } } break; @@ -1020,7 +1021,7 @@ mio_oow_t mio_skadtoucstr (mio_t* mio, const mio_skad_t* _skad, mio_uch_t* buf, tmp = mio_ifindextoucstr(mio, skad->in6.sin6_scope_id, &buf[xlen], len - xlen); if (tmp <= -1) { -/* TODO xlen += mio_fmt_uintmax_to_ucstr(&buf[xlen], len - xlen, skad->in6.sin6_scope_id, 10, 0, '\0', MIO_NULL); */ + xlen += mio_fmt_uintmax_to_ucstr(&buf[xlen], len - xlen, skad->in6.sin6_scope_id, 10, 0, '\0', MIO_NULL); } else xlen += tmp; } @@ -1040,7 +1041,7 @@ mio_oow_t mio_skadtoucstr (mio_t* mio, const mio_skad_t* _skad, mio_uch_t* buf, } if (xlen + 1 >= len) goto done; -/* TODO xlen += mio_fmt_uintmax_to_ucstr(&buf[xlen], len - xlen, mio_ntoh16(skad->in6.sin6_port), 10, 0, '\0', MIO_NULL); */ + xlen += mio_fmt_uintmax_to_ucstr(&buf[xlen], len - xlen, mio_ntoh16(skad->in6.sin6_port), 10, 0, '\0', MIO_NULL); } } @@ -1191,7 +1192,7 @@ static mio_oow_t ip6addr_to_bcstr (const struct in6_addr* ipad, mio_bch_t* buf, break; } -/* TODO: tp += mio_fmt_uintmax_to_bcstr(tp, MIO_COUNTOF(tmp) - (tp - tmp), words[i], 16, 0, '\0', MIO_NULL); */ + tp += mio_fmt_uintmax_to_bcstr(tp, MIO_COUNTOF(tmp) - (tp - tmp), words[i], 16, 0, '\0', MIO_NULL); } /* Was it a trailing run of 0x00's? */ @@ -1231,7 +1232,7 @@ mio_oow_t mio_skadtobcstr (mio_t* mio, const mio_skad_t* _skad, mio_bch_t* buf, } if (xlen + 1 >= len) goto done; -/* xlen += mio_fmt_uintmax_to_bcstr(&buf[xlen], len - xlen, mio_ntoh16(skad->in4.sin_port), 10, 0, '\0', MIO_NULL);*/ + xlen += mio_fmt_uintmax_to_bcstr(&buf[xlen], len - xlen, mio_ntoh16(skad->in4.sin_port), 10, 0, '\0', MIO_NULL); } } break; @@ -1267,7 +1268,7 @@ mio_oow_t mio_skadtobcstr (mio_t* mio, const mio_skad_t* _skad, mio_bch_t* buf, tmp = mio_ifindextobcstr(mio, skad->in6.sin6_scope_id, &buf[xlen], len - xlen); if (tmp <= -1) { -/* TODO xlen += mio_fmt_uintmax_to_bcstr(&buf[xlen], len - xlen, skad->in6.sin6_scope_id, 10, 0, '\0', MIO_NULL); */ + xlen += mio_fmt_uintmax_to_bcstr(&buf[xlen], len - xlen, skad->in6.sin6_scope_id, 10, 0, '\0', MIO_NULL); } else xlen += tmp; } @@ -1287,7 +1288,7 @@ mio_oow_t mio_skadtobcstr (mio_t* mio, const mio_skad_t* _skad, mio_bch_t* buf, } if (xlen + 1 >= len) goto done; -/* xlen += mio_fmt_uintmax_to_bcstr(&buf[xlen], len - xlen, mio_ntoh16(skad->in6.sin6_port), 10, 0, '\0', MIO_NULL); */ + xlen += mio_fmt_uintmax_to_bcstr(&buf[xlen], len - xlen, mio_ntoh16(skad->in6.sin6_port), 10, 0, '\0', MIO_NULL); } } @@ -1301,16 +1302,6 @@ mio_oow_t mio_skadtobcstr (mio_t* mio, const mio_skad_t* _skad, mio_bch_t* buf, if (xlen + 1 >= len) goto done; xlen += mio_copy_bcstr(&buf[xlen], len - xlen, skad->un.sun_path); -#if 0 - if (xlen + 1 >= len) goto done; - else - { - mio_oow_t wcslen, mbslen = len - xlen; - mio_convutobcstr (mio, skad->un.sun_path, &wcslen, &buf[xlen], &mbslen); - /* i don't care about conversion errors */ - xlen += mbslen; - } -#endif } break;