diff --git a/mio/configure b/mio/configure index 227626c..8934747 100755 --- a/mio/configure +++ b/mio/configure @@ -17716,7 +17716,7 @@ fi done -for ac_header in ifaddrs.h tiuser.h linux/netfilter_ipv4.h netinet/sctp.h +for ac_header in ifaddrs.h tiuser.h linux/netfilter_ipv4.h netinet/in.h netinet/sctp.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff --git a/mio/configure.ac b/mio/configure.ac index 5bd094a..b821c07 100644 --- a/mio/configure.ac +++ b/mio/configure.ac @@ -131,7 +131,7 @@ AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h ucontext.h]) AC_CHECK_HEADERS([sys/resource.h sys/wait.h sys/syscall.h sys/ioctl.h]) AC_CHECK_HEADERS([sys/sendfile.h sys/epoll.h sys/event.h sys/poll.h]) AC_CHECK_HEADERS([sys/sysctl.h sys/socket.h sys/sockio.h sys/un.h]) -AC_CHECK_HEADERS([ifaddrs.h tiuser.h linux/netfilter_ipv4.h netinet/sctp.h]) +AC_CHECK_HEADERS([ifaddrs.h tiuser.h linux/netfilter_ipv4.h netinet/in.h netinet/sctp.h]) AC_CHECK_HEADERS([net/if.h net/if_dl.h netpacket/packet.h], [], [], [ #include #include ]) diff --git a/mio/lib/Makefile.am b/mio/lib/Makefile.am index d3267a9..8feddf8 100644 --- a/mio/lib/Makefile.am +++ b/mio/lib/Makefile.am @@ -24,18 +24,24 @@ include_HEADERS = \ mio-cmn.h \ mio-pro.h \ mio-sck.h \ + mio-utl.h \ mio.h lib_LTLIBRARIES = libmio.la libmio_la_SOURCES = \ + err.c \ + logfmt.c \ + logfmtv.h \ mio-prv.h \ mio.c \ mio-pro.c \ mio-sck.c \ mio-tim.c \ mio-tmr.c \ - mio-utl.c \ - utf8.c + sck-addr.c \ + sck-addr.h \ + utf8.c \ + utl.c libmio_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON) libmio_la_LDFLAGS = $(LDFLAGS_LIB_COMMON) libmio_la_LIBADD = $(LIBADD_LIB_COMMON) $(SSL_LIBS) diff --git a/mio/lib/Makefile.in b/mio/lib/Makefile.in index ea7cfa4..42e2053 100644 --- a/mio/lib/Makefile.in +++ b/mio/lib/Makefile.in @@ -140,9 +140,10 @@ LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) libmio_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) -am_libmio_la_OBJECTS = libmio_la-mio.lo libmio_la-mio-pro.lo \ - libmio_la-mio-sck.lo libmio_la-mio-tim.lo libmio_la-mio-tmr.lo \ - libmio_la-mio-utl.lo libmio_la-utf8.lo +am_libmio_la_OBJECTS = libmio_la-err.lo libmio_la-logfmt.lo \ + libmio_la-mio.lo libmio_la-mio-pro.lo libmio_la-mio-sck.lo \ + libmio_la-mio-tim.lo libmio_la-mio-tmr.lo \ + libmio_la-sck-addr.lo libmio_la-utf8.lo libmio_la-utl.lo libmio_la_OBJECTS = $(am_libmio_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -392,18 +393,24 @@ include_HEADERS = \ mio-cmn.h \ mio-pro.h \ mio-sck.h \ + mio-utl.h \ mio.h lib_LTLIBRARIES = libmio.la libmio_la_SOURCES = \ + err.c \ + logfmt.c \ + logfmtv.h \ mio-prv.h \ mio.c \ mio-pro.c \ mio-sck.c \ mio-tim.c \ mio-tmr.c \ - mio-utl.c \ - utf8.c + sck-addr.c \ + sck-addr.h \ + utf8.c \ + utl.c libmio_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON) libmio_la_LDFLAGS = $(LDFLAGS_LIB_COMMON) @@ -559,13 +566,16 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-err.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-logfmt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio-pro.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio-sck.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio-tim.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio-tmr.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio-utl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-sck-addr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-utf8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-utl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mio-main.Po@am__quote@ .c.o: @@ -592,6 +602,20 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< +libmio_la-err.lo: err.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-err.lo -MD -MP -MF $(DEPDIR)/libmio_la-err.Tpo -c -o libmio_la-err.lo `test -f 'err.c' || echo '$(srcdir)/'`err.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-err.Tpo $(DEPDIR)/libmio_la-err.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='err.c' object='libmio_la-err.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-err.lo `test -f 'err.c' || echo '$(srcdir)/'`err.c + +libmio_la-logfmt.lo: logfmt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-logfmt.lo -MD -MP -MF $(DEPDIR)/libmio_la-logfmt.Tpo -c -o libmio_la-logfmt.lo `test -f 'logfmt.c' || echo '$(srcdir)/'`logfmt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-logfmt.Tpo $(DEPDIR)/libmio_la-logfmt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='logfmt.c' object='libmio_la-logfmt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-logfmt.lo `test -f 'logfmt.c' || echo '$(srcdir)/'`logfmt.c + libmio_la-mio.lo: mio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-mio.lo -MD -MP -MF $(DEPDIR)/libmio_la-mio.Tpo -c -o libmio_la-mio.lo `test -f 'mio.c' || echo '$(srcdir)/'`mio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-mio.Tpo $(DEPDIR)/libmio_la-mio.Plo @@ -627,12 +651,12 @@ libmio_la-mio-tmr.lo: mio-tmr.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-mio-tmr.lo `test -f 'mio-tmr.c' || echo '$(srcdir)/'`mio-tmr.c -libmio_la-mio-utl.lo: mio-utl.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-mio-utl.lo -MD -MP -MF $(DEPDIR)/libmio_la-mio-utl.Tpo -c -o libmio_la-mio-utl.lo `test -f 'mio-utl.c' || echo '$(srcdir)/'`mio-utl.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-mio-utl.Tpo $(DEPDIR)/libmio_la-mio-utl.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mio-utl.c' object='libmio_la-mio-utl.lo' libtool=yes @AMDEPBACKSLASH@ +libmio_la-sck-addr.lo: sck-addr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-sck-addr.lo -MD -MP -MF $(DEPDIR)/libmio_la-sck-addr.Tpo -c -o libmio_la-sck-addr.lo `test -f 'sck-addr.c' || echo '$(srcdir)/'`sck-addr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-sck-addr.Tpo $(DEPDIR)/libmio_la-sck-addr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sck-addr.c' object='libmio_la-sck-addr.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-mio-utl.lo `test -f 'mio-utl.c' || echo '$(srcdir)/'`mio-utl.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-sck-addr.lo `test -f 'sck-addr.c' || echo '$(srcdir)/'`sck-addr.c libmio_la-utf8.lo: utf8.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-utf8.lo -MD -MP -MF $(DEPDIR)/libmio_la-utf8.Tpo -c -o libmio_la-utf8.lo `test -f 'utf8.c' || echo '$(srcdir)/'`utf8.c @@ -641,6 +665,13 @@ libmio_la-utf8.lo: utf8.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-utf8.lo `test -f 'utf8.c' || echo '$(srcdir)/'`utf8.c +libmio_la-utl.lo: utl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-utl.lo -MD -MP -MF $(DEPDIR)/libmio_la-utl.Tpo -c -o libmio_la-utl.lo `test -f 'utl.c' || echo '$(srcdir)/'`utl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-utl.Tpo $(DEPDIR)/libmio_la-utl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utl.c' object='libmio_la-utl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-utl.lo `test -f 'utl.c' || echo '$(srcdir)/'`utl.c + mio-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mio_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mio-main.o -MD -MP -MF $(DEPDIR)/mio-main.Tpo -c -o mio-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mio-main.Tpo $(DEPDIR)/mio-main.Po diff --git a/mio/lib/err.c b/mio/lib/err.c new file mode 100644 index 0000000..d1c7e35 --- /dev/null +++ b/mio/lib/err.c @@ -0,0 +1,449 @@ +/* + * $Id$ + * + Copyright (c) 2015-2016 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 WAfRRANTIES + 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. + */ + +#include "mio-prv.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'}; +static mio_ooch_t errstr_2[] = {'n','o','t',' ','i','m','p','l','e','m','e','n','t','e','d','\0'}; +static mio_ooch_t errstr_3[] = {'s','u','b','s','y','s','t','e','m',' ','e','r','r','o','r','\0'}; +static mio_ooch_t errstr_4[] = {'i','n','t','e','r','n','a','l',' ','e','r','r','o','r',' ','t','h','a','t',' ','s','h','o','u','l','d',' ','n','e','v','e','r',' ','h','a','v','e',' ','h','a','p','p','e','n','e','d','\0'}; +static mio_ooch_t errstr_5[] = {'i','n','s','u','f','f','i','c','i','e','n','t',' ','s','y','s','t','e','m',' ','m','e','m','o','r','y','\0'}; +static mio_ooch_t errstr_6[] = {'i','n','s','u','f','f','i','c','i','e','n','t',' ','o','b','j','e','c','t',' ','m','e','m','o','r','y','\0'}; +static mio_ooch_t errstr_7[] = {'i','n','v','a','l','i','d',' ','c','l','a','s','s','/','t','y','p','e','\0'}; +static mio_ooch_t errstr_8[] = {'i','n','v','a','l','i','d',' ','p','a','r','a','m','e','t','e','r',' ','o','r',' ','a','r','g','u','m','e','n','t','\0'}; +static mio_ooch_t errstr_9[] = {'d','a','t','a',' ','n','o','t',' ','f','o','u','n','d','\0'}; +static mio_ooch_t errstr_10[] = {'e','x','i','s','t','i','n','g','/','d','u','p','l','i','c','a','t','e',' ','d','a','t','a','\0'}; +static mio_ooch_t errstr_11[] = {'b','u','s','y','\0'}; +static mio_ooch_t errstr_12[] = {'a','c','c','e','s','s',' ','d','e','n','i','e','d','\0'}; +static mio_ooch_t errstr_13[] = {'o','p','e','r','a','t','i','o','n',' ','n','o','t',' ','p','e','r','m','i','t','t','e','d','\0'}; +static mio_ooch_t errstr_14[] = {'n','o','t',' ','a',' ','d','i','r','e','c','t','o','r','y','\0'}; +static mio_ooch_t errstr_15[] = {'i','n','t','e','r','r','u','p','t','e','d','\0'}; +static mio_ooch_t errstr_16[] = {'p','i','p','e',' ','e','r','r','o','r','\0'}; +static mio_ooch_t errstr_17[] = {'r','e','s','o','u','r','c','e',' ','t','e','m','p','o','r','a','r','i','l','y',' ','u','n','a','v','a','i','l','a','b','l','e','\0'}; +static mio_ooch_t errstr_18[] = {'b','a','d',' ','s','y','s','t','e','m',' ','h','a','n','d','l','e','\0'}; +static mio_ooch_t errstr_19[] = {'*','*','*',' ','u','n','d','e','f','i','n','e','d',' ','e','r','r','o','r',' ','*','*','*','\0'}; +static mio_ooch_t errstr_20[] = {'m','e','s','s','a','g','e',' ','r','e','c','e','i','v','e','r',' ','e','r','r','o','r','\0'}; +static mio_ooch_t errstr_21[] = {'m','e','s','s','a','g','e',' ','s','e','n','d','i','n','g',' ','e','r','r','o','r','\0'}; +static mio_ooch_t errstr_22[] = {'w','r','o','n','g',' ','n','u','m','b','e','r',' ','o','f',' ','a','r','g','u','m','e','n','t','s','\0'}; +static mio_ooch_t errstr_23[] = {'r','a','n','g','e',' ','e','r','r','o','r','\0'}; +static mio_ooch_t errstr_24[] = {'b','y','t','e','-','c','o','d','e',' ','f','u','l','l','\0'}; +static mio_ooch_t errstr_25[] = {'d','i','c','t','i','o','n','a','r','y',' ','f','u','l','l','\0'}; +static mio_ooch_t errstr_26[] = {'p','r','o','c','e','s','s','o','r',' ','f','u','l','l','\0'}; +static mio_ooch_t errstr_27[] = {'t','o','o',' ','m','a','n','y',' ','s','e','m','a','p','h','o','r','e','s','\0'}; +static mio_ooch_t errstr_28[] = {'*','*','*',' ','u','n','d','e','f','i','n','e','d',' ','e','r','r','o','r',' ','*','*','*','\0'}; +static mio_ooch_t errstr_29[] = {'d','i','v','i','d','e',' ','b','y',' ','z','e','r','o','\0'}; +static mio_ooch_t errstr_30[] = {'I','/','O',' ','e','r','r','o','r','\0'}; +static mio_ooch_t errstr_31[] = {'e','n','c','o','d','i','n','g',' ','c','o','n','v','e','r','s','i','o','n',' ','e','r','r','o','r','\0'}; +static mio_ooch_t errstr_32[] = {'i','n','s','u','f','f','i','c','i','e','n','t',' ','d','a','t','a',' ','f','o','r',' ','e','n','c','o','d','i','n','g',' ','c','o','n','v','e','r','s','i','o','n','\0'}; +static mio_ooch_t errstr_33[] = {'b','u','f','f','e','r',' ','f','u','l','l','\0'}; +static mio_ooch_t* errstr[] = +{ + errstr_0, errstr_1, errstr_2, errstr_3, errstr_4, errstr_5, errstr_6, errstr_7, + errstr_8, errstr_9, errstr_10, errstr_11, errstr_12, errstr_13, errstr_14, errstr_15, + errstr_16, errstr_17, errstr_18, errstr_19, errstr_20, errstr_21, errstr_22, errstr_23, + errstr_24, errstr_25, errstr_26, errstr_27, errstr_28, errstr_29, errstr_30, errstr_31, + errstr_32, errstr_33 +}; + +/* -------------------------------------------------------------------------- + * ERROR NUMBER TO STRING CONVERSION + * -------------------------------------------------------------------------- */ +const mio_ooch_t* mio_errnum_to_errstr (mio_errnum_t errnum) +{ + static mio_ooch_t e_unknown[] = {'u','n','k','n','o','w','n',' ','e','r','r','o','r','\0'}; + return (errnum >= 0 && errnum < MIO_COUNTOF(errstr))? errstr[errnum]: e_unknown; +} + +/* -------------------------------------------------------------------------- + * ERROR MESSAGE CONVERSION + * -------------------------------------------------------------------------- */ +#include + +static mio_errnum_t errno_to_errnum (int errcode) +{ + switch (errcode) + { + case ENOMEM: return MIO_ESYSMEM; + case EINVAL: return MIO_EINVAL; + + #if defined(EBUSY) + case EBUSY: return MIO_EBUSY; + #endif + case EACCES: return MIO_EACCES; + #if defined(EPERM) + case EPERM: return MIO_EPERM; + #endif + #if defined(ENOTDIR) + case ENOTDIR: return MIO_ENOTDIR; + #endif + case ENOENT: return MIO_ENOENT; + #if defined(EEXIST) + case EEXIST: return MIO_EEXIST; + #endif + #if defined(EINTR) + case EINTR: return MIO_EINTR; + #endif + + #if defined(EPIPE) + case EPIPE: return MIO_EPIPE; + #endif + + #if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN != EWOULDBLOCK) + case EAGAIN: + case EWOULDBLOCK: return MIO_EAGAIN; + #elif defined(EAGAIN) + case EAGAIN: return MIO_EAGAIN; + #elif defined(EWOULDBLOCK) + case EWOULDBLOCK: return MIO_EAGAIN; + #endif + + #if defined(EBADF) + case EBADF: return MIO_EBADHND; + #endif + + #if defined(EIO) + case EIO: return MIO_EIOERR; + #endif + + default: return MIO_ESYSERR; + } +} + +#if defined(_WIN32) +static mio_errnum_t winerr_to_errnum (DWORD errcode) +{ + switch (errcode) + { + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_OUTOFMEMORY: + return MIO_ESYSMEM; + + case ERROR_INVALID_PARAMETER: + case ERROR_INVALID_NAME: + return MIO_EINVAL; + + case ERROR_INVALID_HANDLE: + return MIO_EBADHND; + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + return MIO_EACCES; + + #if defined(ERROR_IO_PRIVILEGE_FAILED) + case ERROR_IO_PRIVILEGE_FAILED: + #endif + case ERROR_PRIVILEGE_NOT_HELD: + return MIO_EPERM; + + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return MIO_ENOENT; + + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + return MIO_EEXIST; + + case ERROR_BROKEN_PIPE: + return MIO_EPIPE; + + default: + return MIO_ESYSERR; + } +} +#endif + +#if defined(__OS2__) +static mio_errnum_t os2err_to_errnum (APIRET errcode) +{ + /* APIRET e */ + switch (errcode) + { + case ERROR_NOT_ENOUGH_MEMORY: + return MIO_ESYSMEM; + + case ERROR_INVALID_PARAMETER: + case ERROR_INVALID_NAME: + return MIO_EINVAL; + + case ERROR_INVALID_HANDLE: + return MIO_EBADHND; + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + return MIO_EACCES; + + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return MIO_ENOENT; + + case ERROR_ALREADY_EXISTS: + return MIO_EEXIST; + + /*TODO: add more mappings */ + default: + return MIO_ESYSERR; + } +} +#endif + +#if defined(macintosh) +static mio_errnum_t macerr_to_errnum (int errcode) +{ + switch (e) + { + case notEnoughMemoryErr: + return MIO_ESYSMEM; + case paramErr: + return MIO_EINVAL; + + case qErr: /* queue element not found during deletion */ + case fnfErr: /* file not found */ + case dirNFErr: /* direcotry not found */ + case resNotFound: /* resource not found */ + case resFNotFound: /* resource file not found */ + case nbpNotFound: /* name not found on remove */ + return MIO_ENOENT; + + /*TODO: add more mappings */ + default: + return MIO_ESYSERR; + } +} +#endif + +static mio_errnum_t syserrstrb (mio_t* mio, int syserr_type, int syserr_code, mio_bch_t* buf, mio_oow_t len) +{ + switch (syserr_type) + { + case 1: + #if defined(_WIN32) + if (buf) + { + DWORD rc; + rc = FormatMessageA ( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, syserr_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, len, MIO_NULL + ); + while (rc > 0 && buf[rc - 1] == '\r' || buf[rc - 1] == '\n') buf[--rc] = '\0'; + } + return winerr_to_errnum(syserr_code); + #elif defined(__OS2__) + /* TODO: convert code to string */ + if (buf) mio_copy_bcstr (buf, len, "system error"); + return os2err_to_errnum(syserr_code); + #elif defined(macintosh) + /* TODO: convert code to string */ + if (buf) mio_copy_bcstr (buf, len, "system error"); + return os2err_to_errnum(syserr_code); + #else + /* in other systems, errno is still the native system error code. + * fall thru */ + #endif + + case 0: + #if defined(HAVE_STRERROR_R) + if (buf) strerror_r (syserr_code, buf, len); + #else + /* this is not thread safe */ + if (buf) mio_copy_bcstr (buf, len, strerror(syserr_code)); + #endif + return errno_to_errnum(syserr_code); + } + + if (buf) mio_copy_bcstr (buf, len, "system error"); + return MIO_ESYSERR; +} + + +/* -------------------------------------------------------------------------- + * ERROR NUMBER/MESSAGE HANDLING + * -------------------------------------------------------------------------- */ +const mio_ooch_t* mio_geterrstr (mio_t* mio) +{ + return mio_errnum_to_errstr(mio->errnum); +} + +const mio_ooch_t* mio_geterrmsg (mio_t* mio) +{ + if (mio->errmsg.len <= 0) return mio_errnum_to_errstr(mio->errnum); + return mio->errmsg.buf; +} + +void mio_geterrinf (mio_t* mio, mio_errinf_t* info) +{ + info->num = mio_geterrnum(mio); + mio_copy_oocstr (info->msg, MIO_COUNTOF(info->msg), mio_geterrmsg(mio)); +} + +const mio_ooch_t* mio_backuperrmsg (mio_t* mio) +{ + mio_copy_oocstr (mio->errmsg.tmpbuf.ooch, MIO_COUNTOF(mio->errmsg.tmpbuf.ooch), mio_geterrmsg(mio)); + return mio->errmsg.tmpbuf.ooch; +} + +void mio_seterrnum (mio_t* mio, mio_errnum_t errnum) +{ + if (mio->shuterr) return; + mio->errnum = errnum; + mio->errmsg.len = 0; +} + +void mio_seterrwithsyserr (mio_t* mio, int syserr_type, int syserr_code) +{ + mio_errnum_t errnum; + + if (mio->shuterr) return; + + /*if (mio->vmprim.syserrstrb) + {*/ + errnum = /*mio->vmprim.*/syserrstrb(mio, syserr_type, syserr_code, mio->errmsg.tmpbuf.bch, MIO_COUNTOF(mio->errmsg.tmpbuf.bch)); + mio_seterrbfmt (mio, errnum, "%hs", mio->errmsg.tmpbuf.bch); + /* + } + else + { + MIO_ASSERT (mio, mio->vmprim.syserrstru != MIO_NULL); + errnum = mio->vmprim.syserrstru(mio, syserr_type, syserr_code, mio->errmsg.tmpbuf.uch, MIO_COUNTOF(mio->errmsg.tmpbuf.uch)); + mio_seterrbfmt (mio, errnum, "%ls", mio->errmsg.tmpbuf.uch); + }*/ +} + +void mio_seterrbfmtwithsyserr (mio_t* mio, int syserr_type, int syserr_code, const mio_bch_t* fmt, ...) +{ + mio_errnum_t errnum; + mio_oow_t ucslen, bcslen; + va_list ap; + + if (mio->shuterr) return; + + /* + if (mio->vmprim.syserrstrb) + {*/ + errnum = /*mio->vmprim.*/syserrstrb(mio, syserr_type, syserr_code, mio->errmsg.tmpbuf.bch, MIO_COUNTOF(mio->errmsg.tmpbuf.bch)); + + va_start (ap, fmt); + mio_seterrbfmtv (mio, errnum, fmt, ap); + va_end (ap); + + if (MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len >= 5) + { + mio->errmsg.buf[mio->errmsg.len++] = ' '; + mio->errmsg.buf[mio->errmsg.len++] = '-'; + mio->errmsg.buf[mio->errmsg.len++] = ' '; + + #if defined(MIO_OOCH_IS_BCH) + mio->errmsg.len += mio_copy_bcstr(&mio->errmsg.buf[mio->errmsg.len], MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len, mio->errmsg.tmpbuf.bch); + #else + ucslen = MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len; + mio_convbtoucstr (mio, mio->errmsg.tmpbuf.bch, &bcslen, &mio->errmsg.buf[mio->errmsg.len], &ucslen); + mio->errmsg.len += ucslen; + #endif + } + /*} + else + { + MIO_ASSERT (mio, mio->vmprim.syserrstru != MIO_NULL); + errnum = mio->vmprim.syserrstru(mio, syserr_type, syserr_code, mio->errmsg.tmpbuf.uch, MIO_COUNTOF(mio->errmsg.tmpbuf.uch)); + + va_start (ap, fmt); + mio_seterrbfmtv (mio, errnum, fmt, ap); + va_end (ap); + + if (MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len >= 5) + { + mio->errmsg.buf[mio->errmsg.len++] = ' '; + mio->errmsg.buf[mio->errmsg.len++] = '-'; + mio->errmsg.buf[mio->errmsg.len++] = ' '; + + #if defined(MIO_OOCH_IS_BCH) + bcslen = MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len; + mio_convutobcstr (mio, mio->errmsg.tmpbuf.uch, &ucslen, &mio->errmsg.buf[mio->errmsg.len], &bcslen); + mio->errmsg.len += bcslen; + #else + mio->errmsg.len += mio_copy_ucstr(&mio->errmsg.buf[mio->errmsg.len], MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len, mio->errmsg.tmpbuf.uch); + #endif + } + }*/ +} + +void mio_seterrufmtwithsyserr (mio_t* mio, int syserr_type, int syserr_code, const mio_uch_t* fmt, ...) +{ + mio_errnum_t errnum; + mio_oow_t ucslen, bcslen; + va_list ap; + + if (mio->shuterr) return; + + /*if (mio->vmprim.syserrstrb) + {*/ + errnum = /*mio->vmprim.*/syserrstrb(mio, syserr_type, syserr_code, mio->errmsg.tmpbuf.bch, MIO_COUNTOF(mio->errmsg.tmpbuf.bch)); + + va_start (ap, fmt); + mio_seterrufmtv (mio, errnum, fmt, ap); + va_end (ap); + + if (MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len >= 5) + { + mio->errmsg.buf[mio->errmsg.len++] = ' '; + mio->errmsg.buf[mio->errmsg.len++] = '-'; + mio->errmsg.buf[mio->errmsg.len++] = ' '; + + #if defined(MIO_OOCH_IS_BCH) + mio->errmsg.len += mio_copy_bcstr(&mio->errmsg.buf[mio->errmsg.len], MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len, mio->errmsg.tmpbuf.bch); + #else + ucslen = MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len; + mio_convbtoucstr (mio, mio->errmsg.tmpbuf.bch, &bcslen, &mio->errmsg.buf[mio->errmsg.len], &ucslen); + mio->errmsg.len += ucslen; + #endif + } + /*} + else + { + MIO_ASSERT (mio, mio->vmprim.syserrstru != MIO_NULL); + errnum = mio->vmprim.syserrstru(mio, syserr_type, syserr_code, mio->errmsg.tmpbuf.uch, MIO_COUNTOF(mio->errmsg.tmpbuf.uch)); + + va_start (ap, fmt); + mio_seterrufmtv (mio, errnum, fmt, ap); + va_end (ap); + + if (MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len >= 5) + { + mio->errmsg.buf[mio->errmsg.len++] = ' '; + mio->errmsg.buf[mio->errmsg.len++] = '-'; + mio->errmsg.buf[mio->errmsg.len++] = ' '; + + #if defined(MIO_OOCH_IS_BCH) + bcslen = MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len; + mio_convutobcstr (mio, mio->errmsg.tmpbuf.uch, &ucslen, &mio->errmsg.buf[mio->errmsg.len], &bcslen); + mio->errmsg.len += bcslen; + #else + mio->errmsg.len += mio_copy_ucstr(&mio->errmsg.buf[mio->errmsg.len], MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len, mio->errmsg.tmpbuf.uch); + #endif + } + }*/ +} diff --git a/mio/lib/logfmt.c b/mio/lib/logfmt.c new file mode 100644 index 0000000..d572ecf --- /dev/null +++ b/mio/lib/logfmt.c @@ -0,0 +1,733 @@ +/* + * $Id$ + * + Copyright (c) 2015-2016 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. + */ + +#include "mio-prv.h" + +/*#include */ /* for snprintf(). used for floating-point number formatting */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1200)) +# define snprintf _snprintf +# if !defined(HAVE_SNPRINTF) +# define HAVE_SNPRINTF +# endif +#endif +#if defined(HAVE_QUADMATH_H) +# include /* for quadmath_snprintf() */ +#endif +/* TODO: remove stdio.h and quadmath.h once snprintf gets replaced by own +floting-point conversion implementation*/ + +/* Max number conversion buffer length: + * mio_intmax_t in base 2, plus NUL byte. */ +#define MAXNBUF (MIO_SIZEOF(mio_intmax_t) * 8 + 1) + +enum +{ + /* integer */ + LF_C = (1 << 0), + LF_H = (1 << 1), + LF_J = (1 << 2), + LF_L = (1 << 3), + LF_Q = (1 << 4), + LF_T = (1 << 5), + LF_Z = (1 << 6), + + /* long double */ + LF_LD = (1 << 7), + /* __float128 */ + LF_QD = (1 << 8) +}; + +static struct +{ + mio_uint8_t flag; /* for single occurrence */ + mio_uint8_t dflag; /* for double occurrence */ +} lm_tab[26] = +{ + { 0, 0 }, /* a */ + { 0, 0 }, /* b */ + { 0, 0 }, /* c */ + { 0, 0 }, /* d */ + { 0, 0 }, /* e */ + { 0, 0 }, /* f */ + { 0, 0 }, /* g */ + { LF_H, LF_C }, /* h */ + { 0, 0 }, /* i */ + { LF_J, 0 }, /* j */ + { 0, 0 }, /* k */ + { LF_L, LF_Q }, /* l */ + { 0, 0 }, /* m */ + { 0, 0 }, /* n */ + { 0, 0 }, /* o */ + { 0, 0 }, /* p */ + { LF_Q, 0 }, /* q */ + { 0, 0 }, /* r */ + { 0, 0 }, /* s */ + { LF_T, 0 }, /* t */ + { 0, 0 }, /* u */ + { 0, 0 }, /* v */ + { 0, 0 }, /* w */ + { 0, 0 }, /* z */ + { 0, 0 }, /* y */ + { LF_Z, 0 }, /* z */ +}; + + +enum +{ + FLAGC_DOT = (1 << 0), + FLAGC_SPACE = (1 << 1), + FLAGC_SHARP = (1 << 2), + FLAGC_SIGN = (1 << 3), + FLAGC_LEFTADJ = (1 << 4), + FLAGC_ZEROPAD = (1 << 5), + FLAGC_WIDTH = (1 << 6), + FLAGC_PRECISION = (1 << 7), + FLAGC_STAR1 = (1 << 8), + FLAGC_STAR2 = (1 << 9), + FLAGC_LENMOD = (1 << 10) /* length modifier */ +}; + +static const mio_bch_t hex2ascii_lower[] = +{ + '0','1','2','3','4','5','6','7','8','9', + 'a','b','c','d','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w','x','y','z' +}; + +static const mio_bch_t hex2ascii_upper[] = +{ + '0','1','2','3','4','5','6','7','8','9', + 'A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','H','Z' +}; + +static mio_uch_t uch_nullstr[] = { '(','n','u','l','l', ')','\0' }; +static mio_bch_t bch_nullstr[] = { '(','n','u','l','l', ')','\0' }; + +typedef int (*mio_fmtout_putch_t) ( + mio_t* mio, + mio_bitmask_t mask, + mio_ooch_t c, + mio_oow_t len +); + +typedef int (*mio_fmtout_putcs_t) ( + mio_t* mio, + mio_bitmask_t mask, + const mio_ooch_t* ptr, + mio_oow_t len +); + +typedef struct mio_fmtout_t mio_fmtout_t; +struct mio_fmtout_t +{ + mio_oow_t count; /* out */ + mio_bitmask_t mask; /* in */ + mio_fmtout_putch_t putch; /* in */ + mio_fmtout_putcs_t putcs; /* in */ +}; + +/* ------------------------------------------------------------------------- */ +/* + * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse + * order; return an optional length and a pointer to the last character + * written in the buffer (i.e., the first character of the string). + * The buffer pointed to by `nbuf' must have length >= MAXNBUF. + */ + +static mio_bch_t* sprintn_lower (mio_bch_t* nbuf, mio_uintmax_t num, int base, mio_ooi_t* lenp) +{ + mio_bch_t* p; + + p = nbuf; + *p = '\0'; + do { *++p = hex2ascii_lower[num % base]; } while (num /= base); + + if (lenp) *lenp = p - nbuf; + return p; /* returns the end */ +} + +static mio_bch_t* sprintn_upper (mio_bch_t* nbuf, mio_uintmax_t num, int base, mio_ooi_t* lenp) +{ + mio_bch_t* p; + + p = nbuf; + *p = '\0'; + do { *++p = hex2ascii_upper[num % base]; } while (num /= base); + + if (lenp) *lenp = p - nbuf; + return p; /* returns the end */ +} + +/* ------------------------------------------------------------------------- */ +static int put_ooch (mio_t* mio, mio_bitmask_t mask, mio_ooch_t ch, mio_oow_t len) +{ + /* this is not equivalent to put_oocs(mio,mask,&ch, 1); + * this function is to emit a single character multiple times */ + mio_oow_t rem; + + if (len <= 0) return 1; + + if (mio->log.len > 0 && mio->log.last_mask != mask) + { + /* the mask has changed. commit the buffered text */ + +/* TODO: HANDLE LINE ENDING CONVENTION BETTER... */ + if (mio->log.ptr[mio->log.len - 1] != '\n') + { + /* no line ending - append a line terminator */ + mio->log.ptr[mio->log.len++] = '\n'; + } + vmprim_log_write (mio, mio->log.last_mask, mio->log.ptr, mio->log.len); + mio->log.len = 0; + } + +redo: + rem = 0; + if (len > mio->log.capa - mio->log.len) + { + mio_oow_t newcapa, max; + mio_ooch_t* tmp; + + max = MIO_TYPE_MAX(mio_oow_t) - mio->log.len; + if (len > max) + { + /* data too big. */ + rem += len - max; + len = max; + } + + newcapa = MIO_ALIGN_POW2(mio->log.len + len, MIO_LOG_CAPA_ALIGN); /* TODO: adjust this capacity */ + if (newcapa > mio->option.log_maxcapa) + { + /* [NOTE] + * it doesn't adjust newcapa to mio->option.log_maxcapa. + * nor does it cut the input to fit it into the adjusted capacity. + * if maxcapa set is not aligned to MIO_LOG_CAPA_ALIGN, + * the largest buffer capacity may be suboptimal */ + goto make_do; + } + + /* +1 to handle line ending injection more easily */ + tmp = mio_reallocmem(mio, mio->log.ptr, (newcapa + 1) * MIO_SIZEOF(*tmp)); + if (!tmp) + { + make_do: + if (mio->log.len > 0) + { + /* can't expand the buffer. just flush the existing contents */ + /* TODO: HANDLE LINE ENDING CONVENTION BETTER... */ + if (mio->log.ptr[mio->log.len - 1] != '\n') + { + /* no line ending - append a line terminator */ + mio->log.ptr[mio->log.len++] = '\n'; + } + vmprim_log_write (mio, mio->log.last_mask, mio->log.ptr, mio->log.len); + mio->log.len = 0; + } + + if (len > mio->log.capa) + { + rem += len - mio->log.capa; + len = mio->log.capa; + } + + } + else + { + mio->log.ptr = tmp; + mio->log.capa = newcapa; + } + } + + while (len > 0) + { + mio->log.ptr[mio->log.len++] = ch; + len--; + } + mio->log.last_mask = mask; + + if (rem > 0) + { + len = rem; + goto redo; + } + + + return 1; /* success */ +} + +static int put_oocs (mio_t* mio, mio_bitmask_t mask, const mio_ooch_t* ptr, mio_oow_t len) +{ + mio_oow_t rem; + + if (len <= 0) return 1; + + if (mio->log.len > 0 && mio->log.last_mask != mask) + { + /* the mask has changed. commit the buffered text */ +/* TODO: HANDLE LINE ENDING CONVENTION BETTER... */ + if (mio->log.ptr[mio->log.len - 1] != '\n') + { + /* no line ending - append a line terminator */ + mio->log.ptr[mio->log.len++] = '\n'; + } + + vmprim_log_write (mio, mio->log.last_mask, mio->log.ptr, mio->log.len); + mio->log.len = 0; + } + +redo: + rem = 0; + if (len > mio->log.capa - mio->log.len) + { + mio_oow_t newcapa, max; + mio_ooch_t* tmp; + + max = MIO_TYPE_MAX(mio_oow_t) - mio->log.len; + if (len > max) + { + /* data too big. */ + rem += len - max; + len = max; + } + + newcapa = MIO_ALIGN_POW2(mio->log.len + len, 512); /* TODO: adjust this capacity */ + if (newcapa > mio->option.log_maxcapa) + { + /* [NOTE] + * it doesn't adjust newcapa to mio->option.log_maxcapa. + * nor does it cut the input to fit it into the adjusted capacity. + * if maxcapa set is not aligned to MIO_LOG_CAPA_ALIGN, + * the largest buffer capacity may be suboptimal */ + goto make_do; + } + + /* +1 to handle line ending injection more easily */ + tmp = mio_reallocmem(mio, mio->log.ptr, (newcapa + 1) * MIO_SIZEOF(*tmp)); + if (!tmp) + { + make_do: + if (mio->log.len > 0) + { + /* can't expand the buffer. just flush the existing contents */ + /* TODO: HANDLE LINE ENDING CONVENTION BETTER... */ + if (mio->log.ptr[mio->log.len - 1] != '\n') + { + /* no line ending - append a line terminator */ + mio->log.ptr[mio->log.len++] = '\n'; + } + vmprim_log_write (mio, mio->log.last_mask, mio->log.ptr, mio->log.len); + mio->log.len = 0; + } + + if (len > mio->log.capa) + { + rem += len - mio->log.capa; + len = mio->log.capa; + } + } + else + { + mio->log.ptr = tmp; + mio->log.capa = newcapa; + } + } + + MIO_MEMCPY (&mio->log.ptr[mio->log.len], ptr, len * MIO_SIZEOF(*ptr)); + mio->log.len += len; + mio->log.last_mask = mask; + + if (rem > 0) + { + ptr += len; + len = rem; + goto redo; + } + + return 1; /* success */ +} + +/* ------------------------------------------------------------------------- */ + + +/* ------------------------------------------------------------------------- */ + +#undef FMTCHAR_IS_BCH +#undef FMTCHAR_IS_UCH +#undef FMTCHAR_IS_OOCH +#undef fmtchar_t +#undef logfmtv +#define fmtchar_t mio_bch_t +#define logfmtv __logbfmtv +#define FMTCHAR_IS_BCH +#if defined(MIO_OOCH_IS_BCH) +# define FMTCHAR_IS_OOCH +#endif +#include "logfmtv.h" + +#undef FMTCHAR_IS_BCH +#undef FMTCHAR_IS_UCH +#undef FMTCHAR_IS_OOCH +#undef fmtchar_t +#undef logfmtv +#define fmtchar_t mio_uch_t +#define logfmtv __logufmtv +#define FMTCHAR_IS_UCH +#if defined(MIO_OOCH_IS_UCH) +# define FMTCHAR_IS_OOCH +#endif +#include "logfmtv.h" + + +static int _logbfmtv (mio_t* mio, const mio_bch_t* fmt, mio_fmtout_t* data, va_list ap) +{ + return __logbfmtv (mio, fmt, data, ap, mio_logbfmt); +} + +static int _logufmtv (mio_t* mio, const mio_uch_t* fmt, mio_fmtout_t* data, va_list ap) +{ + return __logufmtv (mio, fmt, data, ap, mio_logbfmt); +} + +mio_ooi_t mio_logbfmt (mio_t* mio, mio_bitmask_t mask, const mio_bch_t* fmt, ...) +{ + int x; + va_list ap; + mio_fmtout_t fo; + + if (mio->log.default_type_mask & MIO_LOG_ALL_TYPES) + { + /* if a type is given, it's not untyped any more. + * mask off the UNTYPED bit */ + mask &= ~MIO_LOG_UNTYPED; + + /* if the default_type_mask has the UNTYPED bit on, + * it'll get turned back on */ + mask |= (mio->log.default_type_mask & MIO_LOG_ALL_TYPES); + } + + fo.mask = mask; + fo.putch = put_ooch; + fo.putcs = put_oocs; + + va_start (ap, fmt); + x = _logbfmtv(mio, fmt, &fo, ap); + va_end (ap); + + if (mio->log.len > 0 && mio->log.ptr[mio->log.len - 1] == '\n') + { + vmprim_log_write (mio, mio->log.last_mask, mio->log.ptr, mio->log.len); + mio->log.len = 0; + } + return (x <= -1)? -1: fo.count; +} + +mio_ooi_t mio_logufmt (mio_t* mio, mio_bitmask_t mask, const mio_uch_t* fmt, ...) +{ + int x; + va_list ap; + mio_fmtout_t fo; + + if (mio->log.default_type_mask & MIO_LOG_ALL_TYPES) + { + mask &= ~MIO_LOG_UNTYPED; + mask |= (mio->log.default_type_mask & MIO_LOG_ALL_TYPES); + } + + fo.mask = mask; + fo.putch = put_ooch; + fo.putcs = put_oocs; + + va_start (ap, fmt); + x = _logufmtv(mio, fmt, &fo, ap); + va_end (ap); + + if (mio->log.len > 0 && mio->log.ptr[mio->log.len - 1] == '\n') + { + vmprim_log_write (mio, mio->log.last_mask, mio->log.ptr, mio->log.len); + mio->log.len = 0; + } + + return (x <= -1)? -1: fo.count; +} + + +/* -------------------------------------------------------------------------- + * ERROR MESSAGE FORMATTING + * -------------------------------------------------------------------------- */ + +static int put_errch (mio_t* mio, mio_bitmask_t mask, mio_ooch_t ch, mio_oow_t len) +{ + mio_oow_t max; + + max = MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len - 1; + if (len > max) len = max; + + if (len <= 0) return 1; + + while (len > 0) + { + mio->errmsg.buf[mio->errmsg.len++] = ch; + len--; + } + mio->errmsg.buf[mio->errmsg.len] = '\0'; + + return 1; /* success */ +} + +static int put_errcs (mio_t* mio, mio_bitmask_t mask, const mio_ooch_t* ptr, mio_oow_t len) +{ + mio_oow_t max; + + max = MIO_COUNTOF(mio->errmsg.buf) - mio->errmsg.len - 1; + if (len > max) len = max; + + if (len <= 0) return 1; + + MIO_MEMCPY (&mio->errmsg.buf[mio->errmsg.len], ptr, len * MIO_SIZEOF(*ptr)); + mio->errmsg.len += len; + mio->errmsg.buf[mio->errmsg.len] = '\0'; + + return 1; /* success */ +} + + +static mio_ooi_t __errbfmtv (mio_t* mio, mio_bitmask_t mask, const mio_bch_t* fmt, ...); + +static int _errbfmtv (mio_t* mio, const mio_bch_t* fmt, mio_fmtout_t* data, va_list ap) +{ + return __logbfmtv (mio, fmt, data, ap, __errbfmtv); +} + +static int _errufmtv (mio_t* mio, const mio_uch_t* fmt, mio_fmtout_t* data, va_list ap) +{ + return __logufmtv (mio, fmt, data, ap, __errbfmtv); +} + +static mio_ooi_t __errbfmtv (mio_t* mio, mio_bitmask_t mask, const mio_bch_t* fmt, ...) +{ + va_list ap; + mio_fmtout_t fo; + + fo.mask = 0; /* not used */ + fo.putch = put_errch; + fo.putcs = put_errcs; + + va_start (ap, fmt); + _errbfmtv (mio, fmt, &fo, ap); + va_end (ap); + + return fo.count; +} + +void mio_seterrbfmt (mio_t* mio, mio_errnum_t errnum, const mio_bch_t* fmt, ...) +{ + va_list ap; + mio_fmtout_t fo; + + if (mio->shuterr) return; + mio->errmsg.len = 0; + + fo.mask = 0; /* not used */ + fo.putch = put_errch; + fo.putcs = put_errcs; + + va_start (ap, fmt); + _errbfmtv (mio, fmt, &fo, ap); + va_end (ap); + + mio->errnum = errnum; +} + +void mio_seterrufmt (mio_t* mio, mio_errnum_t errnum, const mio_uch_t* fmt, ...) +{ + va_list ap; + mio_fmtout_t fo; + + if (mio->shuterr) return; + mio->errmsg.len = 0; + + fo.mask = 0; /* not used */ + fo.putch = put_errch; + fo.putcs = put_errcs; + + va_start (ap, fmt); + _errufmtv (mio, fmt, &fo, ap); + va_end (ap); + + mio->errnum = errnum; +} + + +void mio_seterrbfmtv (mio_t* mio, mio_errnum_t errnum, const mio_bch_t* fmt, va_list ap) +{ + mio_fmtout_t fo; + + if (mio->shuterr) return; + + mio->errmsg.len = 0; + + fo.mask = 0; /* not used */ + fo.putch = put_errch; + fo.putcs = put_errcs; + + _errbfmtv (mio, fmt, &fo, ap); + mio->errnum = errnum; +} + +void mio_seterrufmtv (mio_t* mio, mio_errnum_t errnum, const mio_uch_t* fmt, va_list ap) +{ + mio_fmtout_t fo; + + if (mio->shuterr) return; + + mio->errmsg.len = 0; + + fo.mask = 0; /* not used */ + fo.putch = put_errch; + fo.putcs = put_errcs; + + _errufmtv (mio, fmt, &fo, ap); + mio->errnum = errnum; +} + +/* -------------------------------------------------------------------------- + * SUPPORT FOR THE BUILTIN SPRINTF PRIMITIVE FUNCTION + * -------------------------------------------------------------------------- */ +static int put_sprcs (mio_t* mio, mio_bitmask_t mask, const mio_ooch_t* ptr, mio_oow_t len) +{ + if (len > mio->sprintf.xbuf.capa - mio->sprintf.xbuf.len) + { + mio_ooch_t* tmp; + mio_oow_t newcapa; + + newcapa = mio->sprintf.xbuf.len + len + 1; + newcapa = MIO_ALIGN_POW2(newcapa, 256); + + tmp = (mio_ooch_t*)mio_reallocmem(mio, mio->sprintf.xbuf.ptr, newcapa * MIO_SIZEOF(*tmp)); + if (!tmp) return -1; + + mio->sprintf.xbuf.ptr = tmp; + mio->sprintf.xbuf.capa = newcapa; + } + + MIO_MEMCPY (&mio->sprintf.xbuf.ptr[mio->sprintf.xbuf.len], ptr, len * MIO_SIZEOF(*ptr)); + mio->sprintf.xbuf.len += len; + return 1; /* success */ +} + +static int put_sprch (mio_t* mio, mio_bitmask_t mask, mio_ooch_t ch, mio_oow_t len) +{ + if (len > mio->sprintf.xbuf.capa - mio->sprintf.xbuf.len) + { + mio_ooch_t* tmp; + mio_oow_t newcapa; + + newcapa = mio->sprintf.xbuf.len + len + 1; + newcapa = MIO_ALIGN_POW2(newcapa, 256); + + tmp = (mio_ooch_t*)mio_reallocmem(mio, mio->sprintf.xbuf.ptr, newcapa * MIO_SIZEOF(*tmp)); + if (!tmp) return -1; + + mio->sprintf.xbuf.ptr = tmp; + mio->sprintf.xbuf.capa = newcapa; + } + + while (len > 0) + { + --len; + mio->sprintf.xbuf.ptr[mio->sprintf.xbuf.len++] = ch; + } + + return 1; /* success */ +} + +static mio_ooi_t __sprbfmtv (mio_t* mio, mio_bitmask_t mask, const mio_bch_t* fmt, ...); + +static int _sprbfmtv (mio_t* mio, const mio_bch_t* fmt, mio_fmtout_t* data, va_list ap) +{ + return __logbfmtv (mio, fmt, data, ap, __sprbfmtv); +} + +/* +static int _sprufmtv (mio_t* mio, const mio_uch_t* fmt, mio_fmtout_t* data, va_list ap) +{ + return __logufmtv (mio, fmt, data, ap, __sprbfmtv); +}*/ + +static mio_ooi_t __sprbfmtv (mio_t* mio, mio_bitmask_t mask, const mio_bch_t* fmt, ...) +{ + va_list ap; + mio_fmtout_t fo; + + fo.mask = mask; /* not used */ + fo.putch = put_sprch; + fo.putcs = put_sprcs; + + va_start (ap, fmt); + _sprbfmtv (mio, fmt, &fo, ap); + va_end (ap); + + return fo.count; +} + +mio_ooi_t mio_sproutbfmt (mio_t* mio, mio_bitmask_t mask, const mio_bch_t* fmt, ...) +{ + int x; + va_list ap; + mio_fmtout_t fo; + + fo.mask = mask; + fo.putch = put_sprch; + fo.putcs = put_sprcs; + + va_start (ap, fmt); + x = _sprbfmtv(mio, fmt, &fo, ap); + va_end (ap); + + return (x <= -1)? -1: fo.count; +} + +/* +mio_ooi_t mio_sproutufmt (mio_t* mio, mio_bitmask_t mask, const mio_uch_t* fmt, ...) +{ + int x; + va_list ap; + mio_fmtout_t fo; + + fo.mask = mask; + fo.putch = put_sprch; + fo.putcs = put_sprcs; + + va_start (ap, fmt); + x = _sprufmtv (mio, fmt, &fo, ap); + va_end (ap); + + return (x <= -1)? -1: fo.count; +}*/ + diff --git a/mio/lib/logfmtv.h b/mio/lib/logfmtv.h new file mode 100644 index 0000000..c432f0b --- /dev/null +++ b/mio/lib/logfmtv.h @@ -0,0 +1,996 @@ +/* + * $Id$ + * + Copyright (c) 2015-2016 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. + */ + +/* + * This file contains a formatted output routine derived from kvprintf() + * of FreeBSD. It has been heavily modified and bug-fixed. + */ + +/* + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + */ + + +/* NOTE: data output is aborted if the data limit is reached or + * I/O error occurs */ + +#undef PUT_OOCH +#undef PUT_OOCS + +#define PUT_OOCH(c,n) do { \ + if (n > 0) { \ + int xx; \ + if ((xx = data->putch (mio, data->mask, c, n)) <= -1) goto oops; \ + if (xx == 0) goto done; \ + data->count += n; \ + } \ +} while (0) + +#define PUT_OOCS(ptr,len) do { \ + if (len > 0) { \ + int xx; \ + if ((xx = data->putcs (mio, data->mask, ptr, len)) <= -1) goto oops; \ + if (xx == 0) goto done; \ + data->count += len; \ + } \ +} while (0) + +static int logfmtv (mio_t* mio, const fmtchar_t* fmt, mio_fmtout_t* data, va_list ap, outbfmt_t outbfmt) +{ + const fmtchar_t* percent; + const fmtchar_t* checkpoint; + mio_bch_t nbuf[MAXNBUF], bch; + const mio_bch_t* nbufp; + int n, base, neg, sign; + mio_ooi_t tmp, width, precision; + mio_ooch_t ch, padc; +#if !defined(FMTCHAR_IS_OOCH) + fmtchar_t fch; +#endif + int lm_flag, lm_dflag, flagc, numlen; + mio_uintmax_t num = 0; + int stop = 0; + +#if 0 + mio_bchbuf_t* fltfmt; + mio_oochbuf_t* fltout; +#endif + mio_bch_t* (*sprintn) (mio_bch_t* nbuf, mio_uintmax_t num, int base, mio_ooi_t* lenp); + + data->count = 0; + +#if 0 + fltfmt = &mio->d->fltfmt; + fltout = &mio->d->fltout; + + fltfmt->ptr = fltfmt->buf; + fltfmt->capa = MIO_COUNTOF(fltfmt->buf) - 1; + + fltout->ptr = fltout->buf; + fltout->capa = MIO_COUNTOF(fltout->buf) - 1; +#endif + + while (1) + { + #if defined(FMTCHAR_IS_OOCH) + checkpoint = fmt; + while ((ch = *fmt++) != '%' || stop) + { + if (ch == '\0') + { + PUT_OOCS (checkpoint, fmt - checkpoint - 1); + goto done; + } + } + PUT_OOCS (checkpoint, fmt - checkpoint - 1); + #else + #if defined(MIO_OOCH_IS_UCH) + /* fmtchar is bch. ooch is uch. convert bch to uch */ + checkpoint = fmt; + while ((fch = *fmt++) != '%' || stop) + { + if (fch == '\0') break; + } + while (checkpoint < fmt - 1) + { + mio_oow_t cvlen, bclen; + bclen = fmt - checkpoint - 1; + cvlen = mio->cmgr->bctouc(checkpoint, bclen, &ch); + if (cvlen == 0 || cvlen > bclen) goto oops; + checkpoint += cvlen; + PUT_OOCH (ch, 1); + } + if (fch == '\0') goto done; + #else + while ((fch = *fmt++) != '%' || stop) + { + mio_bch_t bcsbuf[MIO_MBLEN_MAX + 1]; + mio_oow_t ucslen, bcslen; + + if (fch == '\0') goto done; + + /* fmtchar is uch. ooch is bch. convert uch to bch */ + ucslen = 1; + bcslen = MIO_COUNTOF(bcsbuf); + if (mio_conv_uchars_to_bchars_with_cmgr(&fch, &ucslen, bcsbuf, &bcslen, mio->cmgr) <= -1) goto oops; + PUT_OOCS (bcsbuf, bcslen); + } + #endif + #endif + percent = fmt - 1; + + padc = ' '; + width = 0; precision = 0; + neg = 0; sign = 0; + + lm_flag = 0; lm_dflag = 0; flagc = 0; + sprintn = sprintn_lower; + + reswitch: + switch (ch = *fmt++) + { + case '%': /* %% */ + bch = ch; + goto print_lowercase_c; + + /* flag characters */ + case '.': + if (flagc & FLAGC_DOT) goto invalid_format; + flagc |= FLAGC_DOT; + goto reswitch; + + case '#': + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SHARP; + goto reswitch; + + case ' ': + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SPACE; + goto reswitch; + + case '+': /* place sign for signed conversion */ + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SIGN; + goto reswitch; + + case '-': /* left adjusted */ + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + if (flagc & FLAGC_DOT) + { + goto invalid_format; + } + else + { + flagc |= FLAGC_LEFTADJ; + if (flagc & FLAGC_ZEROPAD) + { + padc = ' '; + flagc &= ~FLAGC_ZEROPAD; + } + } + + goto reswitch; + + case '*': /* take the length from the parameter */ + if (flagc & FLAGC_DOT) + { + if (flagc & (FLAGC_STAR2 | FLAGC_PRECISION)) goto invalid_format; + flagc |= FLAGC_STAR2; + + precision = va_arg(ap, mio_ooi_t); /* this deviates from the standard printf that accepts 'int' */ + if (precision < 0) + { + /* if precision is less than 0, + * treat it as if no .precision is specified */ + flagc &= ~FLAGC_DOT; + precision = 0; + } + } + else + { + if (flagc & (FLAGC_STAR1 | FLAGC_WIDTH)) goto invalid_format; + flagc |= FLAGC_STAR1; + + width = va_arg(ap, mio_ooi_t); /* it deviates from the standard printf that accepts 'int' */ + if (width < 0) + { + /* + if (flagc & FLAGC_LEFTADJ) + flagc &= ~FLAGC_LEFTADJ; + else + */ + flagc |= FLAGC_LEFTADJ; + width = -width; + } + } + goto reswitch; + + case '0': /* zero pad */ + if (flagc & FLAGC_LENMOD) goto invalid_format; + if (!(flagc & (FLAGC_DOT | FLAGC_LEFTADJ))) + { + padc = '0'; + flagc |= FLAGC_ZEROPAD; + goto reswitch; + } + /* end of flags characters */ + + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (flagc & FLAGC_LENMOD) goto invalid_format; + for (n = 0;; ++fmt) + { + n = n * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') break; + } + if (flagc & FLAGC_DOT) + { + if (flagc & FLAGC_STAR2) goto invalid_format; + precision = n; + flagc |= FLAGC_PRECISION; + } + else + { + if (flagc & FLAGC_STAR1) goto invalid_format; + width = n; + flagc |= FLAGC_WIDTH; + } + goto reswitch; + + /* length modifiers */ + case 'h': /* short int */ + case 'l': /* long int */ + case 'q': /* long long int */ + case 'j': /* mio_intmax_t/mio_uintmax_t */ + case 'z': /* mio_ooi_t/mio_oow_t */ + case 't': /* ptrdiff_t */ + if (lm_flag & (LF_LD | LF_QD)) goto invalid_format; + + flagc |= FLAGC_LENMOD; + if (lm_dflag) + { + /* error */ + goto invalid_format; + } + else if (lm_flag) + { + if (lm_tab[ch - 'a'].dflag && lm_flag == lm_tab[ch - 'a'].flag) + { + lm_flag &= ~lm_tab[ch - 'a'].flag; + lm_flag |= lm_tab[ch - 'a'].dflag; + lm_dflag |= lm_flag; + goto reswitch; + } + else + { + /* error */ + goto invalid_format; + } + } + else + { + lm_flag |= lm_tab[ch - 'a'].flag; + goto reswitch; + } + break; + + case 'L': /* long double */ + if (flagc & FLAGC_LENMOD) + { + /* conflict with other length modifier */ + goto invalid_format; + } + flagc |= FLAGC_LENMOD; + lm_flag |= LF_LD; + goto reswitch; + + case 'Q': /* __float128 */ + if (flagc & FLAGC_LENMOD) + { + /* conflict with other length modifier */ + goto invalid_format; + } + flagc |= FLAGC_LENMOD; + lm_flag |= LF_QD; + goto reswitch; + /* end of length modifiers */ + + case 'n': /* number of characters printed so far */ + if (lm_flag & LF_J) /* j */ + *(va_arg(ap, mio_intmax_t*)) = data->count; + else if (lm_flag & LF_Z) /* z */ + *(va_arg(ap, mio_ooi_t*)) = data->count; + #if (MIO_SIZEOF_LONG_LONG > 0) + else if (lm_flag & LF_Q) /* ll */ + *(va_arg(ap, long long int*)) = data->count; + #endif + else if (lm_flag & LF_L) /* l */ + *(va_arg(ap, long int*)) = data->count; + else if (lm_flag & LF_H) /* h */ + *(va_arg(ap, short int*)) = data->count; + else if (lm_flag & LF_C) /* hh */ + *(va_arg(ap, char*)) = data->count; + else if (flagc & FLAGC_LENMOD) + goto invalid_format; + else + *(va_arg(ap, int*)) = data->count; + break; + + /* signed integer conversions */ + case 'd': + case 'i': /* signed conversion */ + base = 10; + sign = 1; + goto handle_sign; + /* end of signed integer conversions */ + + /* unsigned integer conversions */ + case 'o': + base = 8; + goto handle_nosign; + case 'u': + base = 10; + goto handle_nosign; + case 'X': + sprintn = sprintn_upper; + case 'x': + base = 16; + goto handle_nosign; + case 'b': + base = 2; + goto handle_nosign; + /* end of unsigned integer conversions */ + + case 'p': /* pointer */ + base = 16; + + if (width == 0) flagc |= FLAGC_SHARP; + else flagc &= ~FLAGC_SHARP; + + num = (mio_uintptr_t)va_arg(ap, void*); + goto number; + + case 'c': + { + /* zeropad must not take effect for 'c' */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + if (lm_flag & LF_L) goto uppercase_c; + #if defined(MIO_OOCH_IS_UCH) + if (lm_flag & LF_J) goto uppercase_c; + #endif + lowercase_c: + bch = MIO_SIZEOF(mio_bch_t) < MIO_SIZEOF(int)? va_arg(ap, int): va_arg(ap, mio_bch_t); + + print_lowercase_c: + /* precision 0 doesn't kill the letter */ + width--; + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + PUT_OOCH (bch, 1); + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + break; + } + + case 'C': + { + mio_uch_t ooch; + + /* zeropad must not take effect for 'C' */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + if (lm_flag & LF_H) goto lowercase_c; + #if defined(MIO_OOCH_IS_BCH) + if (lm_flag & LF_J) goto lowercase_c; + #endif + uppercase_c: + ooch = MIO_SIZEOF(mio_uch_t) < MIO_SIZEOF(int)? va_arg(ap, int): va_arg(ap, mio_uch_t); + + /* precision 0 doesn't kill the letter */ + width--; + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + PUT_OOCH (ooch, 1); + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + break; + } + + case 's': + { + const mio_bch_t* bsp; + mio_oow_t bslen, slen; + + /* zeropad must not take effect for 'S' */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + if (lm_flag & LF_L) goto uppercase_s; + #if defined(MIO_OOCH_IS_UCH) + if (lm_flag & LF_J) goto uppercase_s; + #endif + lowercase_s: + + bsp = va_arg (ap, mio_bch_t*); + if (bsp == MIO_NULL) bsp = bch_nullstr; + + #if defined(MIO_OOCH_IS_UCH) + /* get the length */ + for (bslen = 0; bsp[bslen]; bslen++); + + if (mio_conv_bchars_to_uchars_with_cmgr(bsp, &bslen, MIO_NULL, &slen, mio->cmgr, 0) <= -1) goto oops; + + /* slen holds the length after conversion */ + n = slen; + if ((flagc & FLAGC_DOT) && precision < slen) n = precision; + width -= n; + + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + + { + mio_ooch_t conv_buf[32]; + mio_oow_t conv_len, src_len, tot_len = 0; + while (n > 0) + { + MIO_ASSERT (mio, bslen > tot_len); + + src_len = bslen - tot_len; + conv_len = MIO_COUNTOF(conv_buf); + + /* this must not fail since the dry-run above was successful */ + mio_conv_bchars_to_uchars_with_cmgr(&bsp[tot_len], &src_len, conv_buf, &conv_len, mio->cmgr, 0); + tot_len += src_len; + + if (conv_len > n) conv_len = n; + PUT_OOCS (conv_buf, conv_len); + + n -= conv_len; + } + } + + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + #else + if (flagc & FLAGC_DOT) + { + for (n = 0; n < precision && bsp[n]; n++); + } + else + { + for (n = 0; bsp[n]; n++); + } + + width -= n; + + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + PUT_OOCS (bsp, n); + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + #endif + break; + } + + case 'S': + { + const mio_uch_t* usp; + mio_oow_t uslen, slen; + + /* zeropad must not take effect for 's' */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + if (lm_flag & LF_H) goto lowercase_s; + #if defined(MIO_OOCH_IS_UCH) + if (lm_flag & LF_J) goto lowercase_s; + #endif + uppercase_s: + usp = va_arg (ap, mio_uch_t*); + if (usp == MIO_NULL) usp = uch_nullstr; + + #if defined(MIO_OOCH_IS_BCH) + /* get the length */ + for (uslen = 0; usp[uslen]; uslen++); + + if (mio_conv_uchars_to_bchars_with_cmgr(usp, &uslen, MIO_NULL, &slen, mio->cmgr) <= -1) goto oops; + + /* slen holds the length after conversion */ + n = slen; + if ((flagc & FLAGC_DOT) && precision < slen) n = precision; + width -= n; + + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + { + mio_ooch_t conv_buf[32]; + mio_oow_t conv_len, src_len, tot_len = 0; + while (n > 0) + { + MIO_ASSERT (mio, uslen > tot_len); + + src_len = uslen - tot_len; + conv_len = MIO_COUNTOF(conv_buf); + + /* this must not fail since the dry-run above was successful */ + mio_conv_uchars_to_bchars_with_cmgr (&usp[tot_len], &src_len, conv_buf, &conv_len, mio->cmgr); + tot_len += src_len; + + if (conv_len > n) conv_len = n; + PUT_OOCS (conv_buf, conv_len); + + n -= conv_len; + } + } + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + #else + if (flagc & FLAGC_DOT) + { + for (n = 0; n < precision && usp[n]; n++); + } + else + { + for (n = 0; usp[n]; n++); + } + + width -= n; + + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + PUT_OOCS (usp, n); + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + #endif + break; + } + + case 'O': /* object - ignore precision, width, adjustment */ + if (print_object(mio, data->mask, va_arg(ap, mio_oop_t), outbfmt) <= -1) goto oops; + break; + +#if 0 + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + /* + case 'a': + case 'A': + */ + { + /* let me rely on snprintf until i implement float-point to string conversion */ + int q; + mio_oow_t fmtlen; + #if (MIO_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF) + __float128 v_qd; + #endif + long double v_ld; + double v_d; + int dtype = 0; + mio_oow_t newcapa; + + if (lm_flag & LF_J) + { + #if (MIO_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF) && (MIO_SIZEOF_FLTMAX_T == MIO_SIZEOF___FLOAT128) + v_qd = va_arg (ap, mio_fltmax_t); + dtype = LF_QD; + #elif MIO_SIZEOF_FLTMAX_T == MIO_SIZEOF_DOUBLE + v_d = va_arg (ap, mio_fltmax_t); + #elif MIO_SIZEOF_FLTMAX_T == MIO_SIZEOF_LONG_DOUBLE + v_ld = va_arg (ap, mio_fltmax_t); + dtype = LF_LD; + #else + #error Unsupported mio_flt_t + #endif + } + else if (lm_flag & LF_Z) + { + /* mio_flt_t is limited to double or long double */ + + /* precedence goes to double if sizeof(double) == sizeof(long double) + * for example, %Lf didn't work on some old platforms. + * so i prefer the format specifier with no modifier. + */ + #if MIO_SIZEOF_FLT_T == MIO_SIZEOF_DOUBLE + v_d = va_arg (ap, mio_flt_t); + #elif MIO_SIZEOF_FLT_T == MIO_SIZEOF_LONG_DOUBLE + v_ld = va_arg (ap, mio_flt_t); + dtype = LF_LD; + #else + #error Unsupported mio_flt_t + #endif + } + else if (lm_flag & (LF_LD | LF_L)) + { + v_ld = va_arg (ap, long double); + dtype = LF_LD; + } + #if (MIO_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF) + else if (lm_flag & (LF_QD | LF_Q)) + { + v_qd = va_arg (ap, __float128); + dtype = LF_QD; + } + #endif + else if (flagc & FLAGC_LENMOD) + { + goto invalid_format; + } + else + { + v_d = va_arg (ap, double); + } + + fmtlen = fmt - percent; + if (fmtlen > fltfmt->capa) + { + if (fltfmt->ptr == fltfmt->buf) + { + fltfmt->ptr = MIO_MMGR_ALLOC (MIO_MMGR_GETDFL(), MIO_SIZEOF(*fltfmt->ptr) * (fmtlen + 1)); + if (fltfmt->ptr == MIO_NULL) goto oops; + } + else + { + mio_mchar_t* tmpptr; + + tmpptr = MIO_MMGR_REALLOC (MIO_MMGR_GETDFL(), fltfmt->ptr, MIO_SIZEOF(*fltfmt->ptr) * (fmtlen + 1)); + if (tmpptr == MIO_NULL) goto oops; + fltfmt->ptr = tmpptr; + } + + fltfmt->capa = fmtlen; + } + + /* compose back the format specifier */ + fmtlen = 0; + fltfmt->ptr[fmtlen++] = '%'; + if (flagc & FLAGC_SPACE) fltfmt->ptr[fmtlen++] = ' '; + if (flagc & FLAGC_SHARP) fltfmt->ptr[fmtlen++] = '#'; + if (flagc & FLAGC_SIGN) fltfmt->ptr[fmtlen++] = '+'; + if (flagc & FLAGC_LEFTADJ) fltfmt->ptr[fmtlen++] = '-'; + if (flagc & FLAGC_ZEROPAD) fltfmt->ptr[fmtlen++] = '0'; + + if (flagc & FLAGC_STAR1) fltfmt->ptr[fmtlen++] = '*'; + else if (flagc & FLAGC_WIDTH) + { + fmtlen += mio_fmtuintmaxtombs ( + &fltfmt->ptr[fmtlen], fltfmt->capa - fmtlen, + width, 10, -1, '\0', MIO_NULL); + } + if (flagc & FLAGC_DOT) fltfmt->ptr[fmtlen++] = '.'; + if (flagc & FLAGC_STAR2) fltfmt->ptr[fmtlen++] = '*'; + else if (flagc & FLAGC_PRECISION) + { + fmtlen += mio_fmtuintmaxtombs ( + &fltfmt->ptr[fmtlen], fltfmt->capa - fmtlen, + precision, 10, -1, '\0', MIO_NULL); + } + + if (dtype == LF_LD) + fltfmt->ptr[fmtlen++] = 'L'; + #if (MIO_SIZEOF___FLOAT128 > 0) + else if (dtype == LF_QD) + fltfmt->ptr[fmtlen++] = 'Q'; + #endif + + fltfmt->ptr[fmtlen++] = ch; + fltfmt->ptr[fmtlen] = '\0'; + + #if defined(HAVE_SNPRINTF) + /* nothing special here */ + #else + /* best effort to avoid buffer overflow when no snprintf is available. + * i really can't do much if it happens. */ + newcapa = precision + width + 32; + if (fltout->capa < newcapa) + { + MIO_ASSERT (mio, fltout->ptr == fltout->buf); + + fltout->ptr = MIO_MMGR_ALLOC (MIO_MMGR_GETDFL(), MIO_SIZEOF(char_t) * (newcapa + 1)); + if (fltout->ptr == MIO_NULL) goto oops; + fltout->capa = newcapa; + } + #endif + + while (1) + { + + if (dtype == LF_LD) + { + #if defined(HAVE_SNPRINTF) + q = snprintf ((mio_mchar_t*)fltout->ptr, fltout->capa + 1, fltfmt->ptr, v_ld); + #else + q = sprintf ((mio_mchar_t*)fltout->ptr, fltfmt->ptr, v_ld); + #endif + } + #if (MIO_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF) + else if (dtype == LF_QD) + { + q = quadmath_snprintf ((mio_mchar_t*)fltout->ptr, fltout->capa + 1, fltfmt->ptr, v_qd); + } + #endif + else + { + #if defined(HAVE_SNPRINTF) + q = snprintf ((mio_mchar_t*)fltout->ptr, fltout->capa + 1, fltfmt->ptr, v_d); + #else + q = sprintf ((mio_mchar_t*)fltout->ptr, fltfmt->ptr, v_d); + #endif + } + if (q <= -1) goto oops; + if (q <= fltout->capa) break; + + newcapa = fltout->capa * 2; + if (newcapa < q) newcapa = q; + + if (fltout->ptr == fltout->sbuf) + { + fltout->ptr = MIO_MMGR_ALLOC (MIO_MMGR_GETDFL(), MIO_SIZEOF(char_t) * (newcapa + 1)); + if (fltout->ptr == MIO_NULL) goto oops; + } + else + { + char_t* tmpptr; + + tmpptr = MIO_MMGR_REALLOC (MIO_MMGR_GETDFL(), fltout->ptr, MIO_SIZEOF(char_t) * (newcapa + 1)); + if (tmpptr == MIO_NULL) goto oops; + fltout->ptr = tmpptr; + } + fltout->capa = newcapa; + } + + if (MIO_SIZEOF(char_t) != MIO_SIZEOF(mio_mchar_t)) + { + fltout->ptr[q] = '\0'; + while (q > 0) + { + q--; + fltout->ptr[q] = ((mio_mchar_t*)fltout->ptr)[q]; + } + } + + sp = fltout->ptr; + flagc &= ~FLAGC_DOT; + width = 0; + precision = 0; + goto print_lowercase_s; + } +#endif + + + handle_nosign: + sign = 0; + if (lm_flag & LF_J) + { + #if defined(__GNUC__) && \ + (MIO_SIZEOF_UINTMAX_T > MIO_SIZEOF_OOW_T) && \ + (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG_LONG) && \ + (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG) + /* GCC-compiled binaries crashed when getting mio_uintmax_t with va_arg. + * This is just a work-around for it */ + int i; + for (i = 0, num = 0; i < MIO_SIZEOF(mio_uintmax_t) / MIO_SIZEOF(mio_oow_t); i++) + { + #if defined(MIO_ENDIAN_BIG) + num = num << (8 * MIO_SIZEOF(mio_oow_t)) | (va_arg (ap, mio_oow_t)); + #else + register int shift = i * MIO_SIZEOF(mio_oow_t); + mio_oow_t x = va_arg (ap, mio_oow_t); + num |= (mio_uintmax_t)x << (shift * 8); + #endif + } + #else + num = va_arg (ap, mio_uintmax_t); + #endif + } +#if 0 + else if (lm_flag & LF_T) + num = va_arg (ap, mio_ptrdiff_t); +#endif + else if (lm_flag & LF_Z) + num = va_arg (ap, mio_oow_t); + #if (MIO_SIZEOF_LONG_LONG > 0) + else if (lm_flag & LF_Q) + num = va_arg (ap, unsigned long long int); + #endif + else if (lm_flag & (LF_L | LF_LD)) + num = va_arg (ap, unsigned long int); + else if (lm_flag & LF_H) + num = (unsigned short int)va_arg (ap, int); + else if (lm_flag & LF_C) + num = (unsigned char)va_arg (ap, int); + else + num = va_arg (ap, unsigned int); + goto number; + + handle_sign: + if (lm_flag & LF_J) + { + #if defined(__GNUC__) && \ + (MIO_SIZEOF_INTMAX_T > MIO_SIZEOF_OOI_T) && \ + (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG_LONG) && \ + (MIO_SIZEOF_UINTMAX_T != MIO_SIZEOF_LONG) + /* GCC-compiled binraries crashed when getting mio_uintmax_t with va_arg. + * This is just a work-around for it */ + int i; + for (i = 0, num = 0; i < MIO_SIZEOF(mio_intmax_t) / MIO_SIZEOF(mio_oow_t); i++) + { + #if defined(MIO_ENDIAN_BIG) + num = num << (8 * MIO_SIZEOF(mio_oow_t)) | (va_arg (ap, mio_oow_t)); + #else + register int shift = i * MIO_SIZEOF(mio_oow_t); + mio_oow_t x = va_arg (ap, mio_oow_t); + num |= (mio_uintmax_t)x << (shift * 8); + #endif + } + #else + num = va_arg (ap, mio_intmax_t); + #endif + } + +#if 0 + else if (lm_flag & LF_T) + num = va_arg(ap, mio_ptrdiff_t); +#endif + else if (lm_flag & LF_Z) + num = va_arg (ap, mio_ooi_t); + #if (MIO_SIZEOF_LONG_LONG > 0) + else if (lm_flag & LF_Q) + num = va_arg (ap, long long int); + #endif + else if (lm_flag & (LF_L | LF_LD)) + num = va_arg (ap, long int); + else if (lm_flag & LF_H) + num = (short int)va_arg (ap, int); + else if (lm_flag & LF_C) + num = (char)va_arg (ap, int); + else + num = va_arg (ap, int); + + number: + if (sign && (mio_intmax_t)num < 0) + { + neg = 1; + num = -(mio_intmax_t)num; + } + + nbufp = sprintn (nbuf, num, base, &tmp); + if ((flagc & FLAGC_SHARP) && num != 0) + { + if (base == 2 || base == 8) tmp += 2; + else if (base == 16) tmp += 3; + } + if (neg) tmp++; + else if (flagc & FLAGC_SIGN) tmp++; + else if (flagc & FLAGC_SPACE) tmp++; + + numlen = (int)((const mio_bch_t*)nbufp - (const mio_bch_t*)nbuf); + if ((flagc & FLAGC_DOT) && precision > numlen) + { + /* extra zeros for precision specified */ + tmp += (precision - numlen); + } + + if (!(flagc & FLAGC_LEFTADJ) && !(flagc & FLAGC_ZEROPAD) && width > 0 && (width -= tmp) > 0) + { + PUT_OOCH (padc, width); + width = 0; + } + + if (neg) PUT_OOCH ('-', 1); + else if (flagc & FLAGC_SIGN) PUT_OOCH ('+', 1); + else if (flagc & FLAGC_SPACE) PUT_OOCH (' ', 1); + + if ((flagc & FLAGC_SHARP) && num != 0) + { + if (base == 2) + { + PUT_OOCH ('2', 1); + PUT_OOCH ('r', 1); + } + if (base == 8) + { + PUT_OOCH ('8', 1); + PUT_OOCH ('r', 1); + } + else if (base == 16) + { + PUT_OOCH ('1', 1); + PUT_OOCH ('6', 1); + PUT_OOCH ('r', 1); + } + } + + if ((flagc & FLAGC_DOT) && precision > numlen) + { + /* extra zeros for precision specified */ + PUT_OOCH ('0', precision - numlen); + } + + if (!(flagc & FLAGC_LEFTADJ) && width > 0 && (width -= tmp) > 0) + { + PUT_OOCH (padc, width); + } + + while (*nbufp) PUT_OOCH (*nbufp--, 1); /* output actual digits */ + + if ((flagc & FLAGC_LEFTADJ) && width > 0 && (width -= tmp) > 0) + { + PUT_OOCH (padc, width); + } + break; + + invalid_format: + #if defined(FMTCHAR_IS_OOCH) + PUT_OOCS (percent, fmt - percent); + #else + while (percent < fmt) PUT_OOCH (*percent++, 1); + #endif + break; + + default: + #if defined(FMTCHAR_IS_OOCH) + PUT_OOCS (percent, fmt - percent); + #else + while (percent < fmt) PUT_OOCH (*percent++, 1); + #endif + /* + * Since we ignore an formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + stop = 1; + break; + } + } + +done: + return 0; + +oops: + return -1; +} +#undef PUT_OOCH diff --git a/mio/lib/main.c b/mio/lib/main.c index 020bd48..11a5ec0 100644 --- a/mio/lib/main.c +++ b/mio/lib/main.c @@ -26,6 +26,7 @@ #include +#include #include #include diff --git a/mio/lib/mio-cfg.h.in b/mio/lib/mio-cfg.h.in index ce57774..7e189e6 100644 --- a/mio/lib/mio-cfg.h.in +++ b/mio/lib/mio-cfg.h.in @@ -340,6 +340,9 @@ /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_SCTP_H diff --git a/mio/lib/mio-pro.c b/mio/lib/mio-pro.c index a8b737e..333d25f 100644 --- a/mio/lib/mio-pro.c +++ b/mio/lib/mio-pro.c @@ -107,7 +107,7 @@ static int make_param (mio_t* mio, const mio_bch_t* cmd, int flags, param_t* par param->argv = MIO_MMGR_ALLOC (mio->mmgr, (fcnt + 1) * MIO_SIZEOF(argv[0])); if (param->argv == MIO_NULL) { - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; goto oops; } } diff --git a/mio/lib/mio-prv.h b/mio/lib/mio-prv.h index c66a890..e38da16 100644 --- a/mio/lib/mio-prv.h +++ b/mio/lib/mio-prv.h @@ -28,6 +28,9 @@ #define _MIO_PRV_H_ #include "mio.h" +#include "mio-utl.h" +#include + /*TODO: redefine and remove these */ #include @@ -40,58 +43,6 @@ #define MIO_MEMCMP(dst,src,count) memcmp(dst,src,count) #define MIO_ASSERT assert -#define MIO_CWQFL_SIZE 16 -#define MIO_CWQFL_ALIGN 16 - -typedef struct mio_mux_t mio_mux_t; - -struct mio_t -{ - mio_mmgr_t* mmgr; - mio_errnum_t errnum; - mio_stopreq_t stopreq; /* stop request to abort mio_loop() */ - - struct - { - mio_dev_t* head; - mio_dev_t* tail; - } actdev; /* active devices */ - - struct - { - mio_dev_t* head; - mio_dev_t* tail; - } hltdev; /* halted devices */ - - struct - { - mio_dev_t* head; - mio_dev_t* tail; - } zmbdev; /* zombie devices */ - - mio_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */ - - unsigned int renew_watch: 1; - unsigned int in_exec: 1; - - struct - { - mio_oow_t capa; - mio_oow_t size; - mio_tmrjob_t* jobs; - } tmr; - - mio_cwq_t cwq; - mio_cwq_t* cwqfl[MIO_CWQFL_SIZE]; /* list of free cwq objects */ - - /* platform specific fields below */ -#if defined(_WIN32) - HANDLE iocp; -#else - mio_mux_t* mux; -#endif -}; - #define MIO_EPOCH_YEAR (1970) #define MIO_EPOCH_MON (1) diff --git a/mio/lib/mio-tmr.c b/mio/lib/mio-tmr.c index ca6c4c3..b940594 100644 --- a/mio/lib/mio-tmr.c +++ b/mio/lib/mio-tmr.c @@ -142,7 +142,7 @@ mio_tmridx_t mio_instmrjob (mio_t* mio, const mio_tmrjob_t* job) tmp = (mio_tmrjob_t*)MIO_MMGR_REALLOC (mio->mmgr, mio->tmr.jobs, new_capa * MIO_SIZEOF(*tmp)); if (tmp == MIO_NULL) { - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; return MIO_TMRIDX_INVALID; } diff --git a/mio/lib/mio-utl.c b/mio/lib/mio-utl.c deleted file mode 100644 index c55a49d..0000000 --- a/mio/lib/mio-utl.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2015-2016 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 WAfRRANTIES - 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. - */ - -#include "mio-prv.h" - - -/* ========================================================================= */ - -#if defined(MIO_HAVE_UINT16_T) - -mio_uint16_t mio_ntoh16 (mio_uint16_t x) -{ -#if defined(MIO_ENDIAN_BIG) - return x; -#elif defined(MIO_ENDIAN_LITTLE) - mio_uint8_t* c = (mio_uint8_t*)&x; - return (mio_uint16_t)( - ((mio_uint16_t)c[0] << 8) | - ((mio_uint16_t)c[1] << 0)); -#else -# error Unknown endian -#endif -} - -mio_uint16_t mio_hton16 (mio_uint16_t x) -{ -#if defined(MIO_ENDIAN_BIG) - return x; -#elif defined(MIO_ENDIAN_LITTLE) - mio_uint8_t* c = (mio_uint8_t*)&x; - return (mio_uint16_t)( - ((mio_uint16_t)c[0] << 8) | - ((mio_uint16_t)c[1] << 0)); -#else -# error Unknown endian -#endif -} - -#endif - -/* ========================================================================= */ - -#if defined(MIO_HAVE_UINT32_T) - -mio_uint32_t mio_ntoh32 (mio_uint32_t x) -{ -#if defined(MIO_ENDIAN_BIG) - return x; -#elif defined(MIO_ENDIAN_LITTLE) - mio_uint8_t* c = (mio_uint8_t*)&x; - return (mio_uint32_t)( - ((mio_uint32_t)c[0] << 24) | - ((mio_uint32_t)c[1] << 16) | - ((mio_uint32_t)c[2] << 8) | - ((mio_uint32_t)c[3] << 0)); -#else -# error Unknown endian -#endif -} - -mio_uint32_t mio_hton32 (mio_uint32_t x) -{ -#if defined(MIO_ENDIAN_BIG) - return x; -#elif defined(MIO_ENDIAN_LITTLE) - mio_uint8_t* c = (mio_uint8_t*)&x; - return (mio_uint32_t)( - ((mio_uint32_t)c[0] << 24) | - ((mio_uint32_t)c[1] << 16) | - ((mio_uint32_t)c[2] << 8) | - ((mio_uint32_t)c[3] << 0)); -#else -# error Unknown endian -#endif -} -#endif - -/* ========================================================================= */ - -#if defined(MIO_HAVE_UINT64_T) - -mio_uint64_t mio_ntoh64 (mio_uint64_t x) -{ -#if defined(MIO_ENDIAN_BIG) - return x; -#elif defined(MIO_ENDIAN_LITTLE) - mio_uint8_t* c = (mio_uint8_t*)&x; - return (mio_uint64_t)( - ((mio_uint64_t)c[0] << 56) | - ((mio_uint64_t)c[1] << 48) | - ((mio_uint64_t)c[2] << 40) | - ((mio_uint64_t)c[3] << 32) | - ((mio_uint64_t)c[4] << 24) | - ((mio_uint64_t)c[5] << 16) | - ((mio_uint64_t)c[6] << 8) | - ((mio_uint64_t)c[7] << 0)); -#else -# error Unknown endian -#endif -} - -mio_uint64_t mio_hton64 (mio_uint64_t x) -{ -#if defined(MIO_ENDIAN_BIG) - return x; -#elif defined(MIO_ENDIAN_LITTLE) - mio_uint8_t* c = (mio_uint8_t*)&x; - return (mio_uint64_t)( - ((mio_uint64_t)c[0] << 56) | - ((mio_uint64_t)c[1] << 48) | - ((mio_uint64_t)c[2] << 40) | - ((mio_uint64_t)c[3] << 32) | - ((mio_uint64_t)c[4] << 24) | - ((mio_uint64_t)c[5] << 16) | - ((mio_uint64_t)c[6] << 8) | - ((mio_uint64_t)c[7] << 0)); -#else -# error Unknown endian -#endif -} - -#endif - -/* ========================================================================= */ - -#if defined(MIO_HAVE_UINT128_T) - -mio_uint128_t mio_ntoh128 (mio_uint128_t x) -{ -#if defined(MIO_ENDIAN_BIG) - return x; -#elif defined(MIO_ENDIAN_LITTLE) - mio_uint8_t* c = (mio_uint8_t*)&x; - return (mio_uint128_t)( - ((mio_uint128_t)c[0] << 120) | - ((mio_uint128_t)c[1] << 112) | - ((mio_uint128_t)c[2] << 104) | - ((mio_uint128_t)c[3] << 96) | - ((mio_uint128_t)c[4] << 88) | - ((mio_uint128_t)c[5] << 80) | - ((mio_uint128_t)c[6] << 72) | - ((mio_uint128_t)c[7] << 64) | - ((mio_uint128_t)c[8] << 56) | - ((mio_uint128_t)c[9] << 48) | - ((mio_uint128_t)c[10] << 40) | - ((mio_uint128_t)c[11] << 32) | - ((mio_uint128_t)c[12] << 24) | - ((mio_uint128_t)c[13] << 16) | - ((mio_uint128_t)c[14] << 8) | - ((mio_uint128_t)c[15] << 0)); -#else -# error Unknown endian -#endif -} - -mio_uint128_t mio_hton128 (mio_uint128_t x) -{ -#if defined(MIO_ENDIAN_BIG) - return x; -#elif defined(MIO_ENDIAN_LITTLE) - mio_uint8_t* c = (mio_uint8_t*)&x; - return (mio_uint128_t)( - ((mio_uint128_t)c[0] << 120) | - ((mio_uint128_t)c[1] << 112) | - ((mio_uint128_t)c[2] << 104) | - ((mio_uint128_t)c[3] << 96) | - ((mio_uint128_t)c[4] << 88) | - ((mio_uint128_t)c[5] << 80) | - ((mio_uint128_t)c[6] << 72) | - ((mio_uint128_t)c[7] << 64) | - ((mio_uint128_t)c[8] << 56) | - ((mio_uint128_t)c[9] << 48) | - ((mio_uint128_t)c[10] << 40) | - ((mio_uint128_t)c[11] << 32) | - ((mio_uint128_t)c[12] << 24) | - ((mio_uint128_t)c[13] << 16) | - ((mio_uint128_t)c[14] << 8) | - ((mio_uint128_t)c[15] << 0)); -#else -# error Unknown endian -#endif -} - -#endif - -/* ========================================================================= */ - -#define MIO_MT(x) (x) -#define IS_MSPACE(x) ((x) == MIO_MT(' ') || (x) == MIO_MT('\t') || (x) == MIO_MT('\n') || (x) == MIO_MT('\r')) - -mio_bch_t* mio_mbsdup (mio_t* mio, const mio_bch_t* src) -{ - mio_bch_t* dst; - mio_oow_t len; - - dst = (mio_bch_t*)src; - while (*dst != MIO_MT('\0')) dst++; - len = dst - src; - - dst = MIO_MMGR_ALLOC (mio->mmgr, (len + 1) * MIO_SIZEOF(*src)); - if (!dst) - { - mio->errnum = MIO_ENOMEM; - return MIO_NULL; - } - - MIO_MEMCPY (dst, src, (len + 1) * MIO_SIZEOF(*src)); - return dst; -} - -mio_oow_t mio_mbscpy (mio_bch_t* buf, const mio_bch_t* str) -{ - mio_bch_t* org = buf; - while ((*buf++ = *str++) != MIO_MT('\0')); - return buf - org - 1; -} - -int mio_mbsspltrn ( - mio_bch_t* s, const mio_bch_t* delim, - mio_bch_t lquote, mio_bch_t rquote, - mio_bch_t escape, const mio_bch_t* trset) -{ - mio_bch_t* p = s, *d; - mio_bch_t* sp = MIO_NULL, * ep = MIO_NULL; - int delim_mode; - int cnt = 0; - - if (delim == MIO_NULL) delim_mode = 0; - else - { - delim_mode = 1; - for (d = (mio_bch_t*)delim; *d != MIO_MT('\0'); d++) - if (!IS_MSPACE(*d)) delim_mode = 2; - } - - if (delim_mode == 0) - { - /* skip preceding space characters */ - while (IS_MSPACE(*p)) p++; - - /* when 0 is given as "delim", it has an effect of cutting - preceding and trailing space characters off "s". */ - if (lquote != MIO_MT('\0') && *p == lquote) - { - mio_mbscpy (p, p + 1); - - for (;;) - { - if (*p == MIO_MT('\0')) return -1; - - if (escape != MIO_MT('\0') && *p == escape) - { - if (trset != MIO_NULL && p[1] != MIO_MT('\0')) - { - const mio_bch_t* ep = trset; - while (*ep != MIO_MT('\0')) - { - if (p[1] == *ep++) - { - p[1] = *ep; - break; - } - } - } - - mio_mbscpy (p, p + 1); - } - else - { - if (*p == rquote) - { - p++; - break; - } - } - - if (sp == 0) sp = p; - ep = p; - p++; - } - while (IS_MSPACE(*p)) p++; - if (*p != MIO_MT('\0')) return -1; - - if (sp == 0 && ep == 0) s[0] = MIO_MT('\0'); - else - { - ep[1] = MIO_MT('\0'); - if (s != (mio_bch_t*)sp) mio_mbscpy (s, sp); - cnt++; - } - } - else - { - while (*p) - { - if (!IS_MSPACE(*p)) - { - if (sp == 0) sp = p; - ep = p; - } - p++; - } - - if (sp == 0 && ep == 0) s[0] = MIO_MT('\0'); - else - { - ep[1] = MIO_MT('\0'); - if (s != (mio_bch_t*)sp) mio_mbscpy (s, sp); - cnt++; - } - } - } - else if (delim_mode == 1) - { - mio_bch_t* o; - - while (*p) - { - o = p; - while (IS_MSPACE(*p)) p++; - if (o != p) { mio_mbscpy (o, p); p = o; } - - if (lquote != MIO_MT('\0') && *p == lquote) - { - mio_mbscpy (p, p + 1); - - for (;;) - { - if (*p == MIO_MT('\0')) return -1; - - if (escape != MIO_MT('\0') && *p == escape) - { - if (trset != MIO_NULL && p[1] != MIO_MT('\0')) - { - const mio_bch_t* ep = trset; - while (*ep != MIO_MT('\0')) - { - if (p[1] == *ep++) - { - p[1] = *ep; - break; - } - } - } - mio_mbscpy (p, p + 1); - } - else - { - if (*p == rquote) - { - *p++ = MIO_MT('\0'); - cnt++; - break; - } - } - p++; - } - } - else - { - o = p; - for (;;) - { - if (*p == MIO_MT('\0')) - { - if (o != p) cnt++; - break; - } - if (IS_MSPACE (*p)) - { - *p++ = MIO_MT('\0'); - cnt++; - break; - } - p++; - } - } - } - } - else /* if (delim_mode == 2) */ - { - mio_bch_t* o; - int ok; - - while (*p != MIO_MT('\0')) - { - o = p; - while (IS_MSPACE(*p)) p++; - if (o != p) { mio_mbscpy (o, p); p = o; } - - if (lquote != MIO_MT('\0') && *p == lquote) - { - mio_mbscpy (p, p + 1); - - for (;;) - { - if (*p == MIO_MT('\0')) return -1; - - if (escape != MIO_MT('\0') && *p == escape) - { - if (trset != MIO_NULL && p[1] != MIO_MT('\0')) - { - const mio_bch_t* ep = trset; - while (*ep != MIO_MT('\0')) - { - if (p[1] == *ep++) - { - p[1] = *ep; - break; - } - } - } - - mio_mbscpy (p, p + 1); - } - else - { - if (*p == rquote) - { - *p++ = MIO_MT('\0'); - cnt++; - break; - } - } - p++; - } - - ok = 0; - while (IS_MSPACE(*p)) p++; - if (*p == MIO_MT('\0')) ok = 1; - for (d = (mio_bch_t*)delim; *d != MIO_MT('\0'); d++) - { - if (*p == *d) - { - ok = 1; - mio_mbscpy (p, p + 1); - break; - } - } - if (ok == 0) return -1; - } - else - { - o = p; sp = ep = 0; - - for (;;) - { - if (*p == MIO_MT('\0')) - { - if (ep) - { - ep[1] = MIO_MT('\0'); - p = &ep[1]; - } - cnt++; - break; - } - for (d = (mio_bch_t*)delim; *d != MIO_MT('\0'); d++) - { - if (*p == *d) - { - if (sp == MIO_NULL) - { - mio_mbscpy (o, p); p = o; - *p++ = MIO_MT('\0'); - } - else - { - mio_mbscpy (&ep[1], p); - mio_mbscpy (o, sp); - o[ep - sp + 1] = MIO_MT('\0'); - p = &o[ep - sp + 2]; - } - cnt++; - /* last empty field after delim */ - if (*p == MIO_MT('\0')) cnt++; - goto exit_point; - } - } - - if (!IS_MSPACE (*p)) - { - if (sp == MIO_NULL) sp = p; - ep = p; - } - p++; - } -exit_point: - ; - } - } - } - - return cnt; -} - -int mio_mbsspl ( - mio_bch_t* s, const mio_bch_t* delim, - mio_bch_t lquote, mio_bch_t rquote, mio_bch_t escape) -{ - return mio_mbsspltrn (s, delim, lquote, rquote, escape, MIO_NULL); -} - diff --git a/mio/lib/mio-utl.h b/mio/lib/mio-utl.h new file mode 100644 index 0000000..62eb87d --- /dev/null +++ b/mio/lib/mio-utl.h @@ -0,0 +1,412 @@ +/* + * $Id$ + * + Copyright (c) 2014-2018 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_UTL_H_ +#define _MIO_UTL_H_ + +#include "mio-cmn.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The mio_equal_uchars() function determines equality of two strings + * of the same length \a len. + */ +MIO_EXPORT int mio_equal_uchars ( + const mio_uch_t* str1, + const mio_uch_t* str2, + mio_oow_t len +); + +MIO_EXPORT int mio_equal_bchars ( + const mio_bch_t* str1, + const mio_bch_t* str2, + mio_oow_t len +); + +MIO_EXPORT int mio_comp_uchars ( + const mio_uch_t* str1, + mio_oow_t len1, + const mio_uch_t* str2, + mio_oow_t len2 +); + +MIO_EXPORT int mio_comp_bchars ( + const mio_bch_t* str1, + mio_oow_t len1, + const mio_bch_t* str2, + mio_oow_t len2 +); + +MIO_EXPORT int mio_comp_ucstr ( + const mio_uch_t* str1, + const mio_uch_t* str2 +); + +MIO_EXPORT int mio_comp_bcstr ( + const mio_bch_t* str1, + const mio_bch_t* str2 +); + +MIO_EXPORT int mio_comp_ucstr_bcstr ( + const mio_uch_t* str1, + const mio_bch_t* str2 +); + +MIO_EXPORT int mio_comp_uchars_ucstr ( + const mio_uch_t* str1, + mio_oow_t len, + const mio_uch_t* str2 +); + +MIO_EXPORT int mio_comp_uchars_bcstr ( + const mio_uch_t* str1, + mio_oow_t len, + const mio_bch_t* str2 +); + +MIO_EXPORT int mio_comp_bchars_bcstr ( + const mio_bch_t* str1, + mio_oow_t len, + const mio_bch_t* str2 +); + +MIO_EXPORT int mio_comp_bchars_ucstr ( + const mio_bch_t* str1, + mio_oow_t len, + const mio_uch_t* str2 +); + +MIO_EXPORT void mio_copy_uchars ( + mio_uch_t* dst, + const mio_uch_t* src, + mio_oow_t len +); + +MIO_EXPORT void mio_copy_bchars ( + mio_bch_t* dst, + const mio_bch_t* src, + mio_oow_t len +); + +MIO_EXPORT void mio_copy_bchars_to_uchars ( + mio_uch_t* dst, + const mio_bch_t* src, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_copy_ucstr ( + mio_uch_t* dst, + mio_oow_t len, + const mio_uch_t* src +); + +MIO_EXPORT mio_oow_t mio_copy_bcstr ( + mio_bch_t* dst, + mio_oow_t len, + const mio_bch_t* src +); + +MIO_EXPORT mio_uch_t* mio_find_uchar ( + const mio_uch_t* ptr, + mio_oow_t len, + mio_uch_t c +); + +MIO_EXPORT mio_bch_t* mio_find_bchar ( + const mio_bch_t* ptr, + mio_oow_t len, + mio_bch_t c +); + +MIO_EXPORT mio_uch_t* mio_rfind_uchar ( + const mio_uch_t* ptr, + mio_oow_t len, + mio_uch_t c +); + +MIO_EXPORT mio_bch_t* mio_rfind_bchar ( + const mio_bch_t* ptr, + mio_oow_t len, + mio_bch_t c +); + +MIO_EXPORT mio_uch_t* mio_find_uchar_in_ucstr ( + const mio_uch_t* ptr, + mio_uch_t c +); + +MIO_EXPORT mio_bch_t* mio_find_bchar_in_bcstr ( + const mio_bch_t* ptr, + mio_bch_t c +); + +MIO_EXPORT mio_oow_t mio_count_ucstr ( + const mio_uch_t* str +); + +MIO_EXPORT mio_oow_t mio_count_bcstr ( + const mio_bch_t* str +); + +#if defined(MIO_OOCH_IS_UCH) +# define mio_equal_oochars(str1,str2,len) mio_equal_uchars(str1,str2,len) +# define mio_comp_oochars(str1,len1,str2,len2) mio_comp_uchars(str1,len1,str2,len2) +# define mio_comp_oocstr_bcstr(str1,str2) mio_comp_ucstr_bcstr(str1,str2) +# define mio_comp_oochars_bcstr(str1,len1,str2) mio_comp_uchars_bcstr(str1,len1,str2) +# define mio_comp_oochars_ucstr(str1,len1,str2) mio_comp_uchars_ucstr(str1,len1,str2) +# define mio_comp_oochars_oocstr(str1,len1,str2) mio_comp_uchars_ucstr(str1,len1,str2) +# define mio_comp_oocstr(str1,str2) mio_comp_ucstr(str1,str2) +# define mio_copy_oochars(dst,src,len) mio_copy_uchars(dst,src,len) +# define mio_copy_bchars_to_oochars(dst,src,len) mio_copy_bchars_to_uchars(dst,src,len) +# define mio_copy_oocstr(dst,len,src) mio_copy_ucstr(dst,len,src) +# define mio_find_oochar(ptr,len,c) mio_find_uchar(ptr,len,c) +# define mio_rfind_oochar(ptr,len,c) mio_rfind_uchar(ptr,len,c) +# define mio_find_oochar_in_oocstr(ptr,c) mio_find_uchar_in_ucstr(ptr,c) +# define mio_count_oocstr(str) mio_count_ucstr(str) +#else +# define mio_equal_oochars(str1,str2,len) mio_equal_bchars(str1,str2,len) +# define mio_comp_oochars(str1,len1,str2,len2) mio_comp_bchars(str1,len1,str2,len2) +# define mio_comp_oocstr_bcstr(str1,str2) mio_comp_bcstr(str1,str2) +# define mio_comp_oochars_bcstr(str1,len1,str2) mio_comp_bchars_bcstr(str1,len1,str2) +# define mio_comp_oochars_ucstr(str1,len1,str2) mio_comp_bchars_ucstr(str1,len1,str2) +# define mio_comp_oochars_oocstr(str1,len1,str2) mio_comp_bchars_bcstr(str1,len1,str2) +# define mio_comp_oocstr(str1,str2) mio_comp_bcstr(str1,str2) +# define mio_copy_oochars(dst,src,len) mio_copy_bchars(dst,src,len) +# define mio_copy_bchars_to_oochars(dst,src,len) mio_copy_bchars(dst,src,len) +# define mio_copy_oocstr(dst,len,src) mio_copy_bcstr(dst,len,src) +# define mio_find_oochar(ptr,len,c) mio_find_bchar(ptr,len,c) +# define mio_rfind_oochar(ptr,len,c) mio_rfind_bchar(ptr,len,c) +# define mio_find_oochar_in_oocstr(ptr,c) mio_find_bchar_in_bcstr(ptr,c) +# define mio_count_oocstr(str) mio_count_bcstr(str) +#endif + + + +/* ------------------------------------------------------------------------- */ + +MIO_EXPORT int mio_ucwidth ( + mio_uch_t uc +); + +/* ------------------------------------------------------------------------- */ + +#if defined(MIO_OOCH_IS_UCH) +# define mio_conv_oocs_to_bcs_with_cmgr(oocs,oocslen,bcs,bcslen,cmgr) mio_conv_ucs_to_bcs_with_cmgr(oocs,oocslen,bcs,bcslen,cmgr) +# define mio_conv_oochars_to_bchars_with_cmgr(oocs,oocslen,bcs,bcslen,cmgr) mio_conv_uchars_to_bchars_with_cmgr(oocs,oocslen,bcs,bcslen,cmgr) +#else +# define mio_conv_oocs_to_ucs_with_cmgr(oocs,oocslen,ucs,ucslen,cmgr) mio_conv_bcs_to_ucs_with_cmgr(oocs,oocslen,ucs,ucslen,cmgr,0) +# define mio_conv_oochars_to_uchars_with_cmgr(oocs,oocslen,ucs,ucslen,cmgr) mio_conv_bchars_to_uchars_with_cmgr(oocs,oocslen,ucs,ucslen,cmgr,0) +#endif + + +MIO_EXPORT int mio_conv_bcs_to_ucs_with_cmgr ( + const mio_bch_t* bcs, + mio_oow_t* bcslen, + mio_uch_t* ucs, + mio_oow_t* ucslen, + mio_cmgr_t* cmgr, + int all +); + +MIO_EXPORT int mio_conv_bchars_to_uchars_with_cmgr ( + const mio_bch_t* bcs, + mio_oow_t* bcslen, + mio_uch_t* ucs, + mio_oow_t* ucslen, + mio_cmgr_t* cmgr, + int all +); + +MIO_EXPORT int mio_conv_ucs_to_bcs_with_cmgr ( + const mio_uch_t* ucs, + mio_oow_t* ucslen, + mio_bch_t* bcs, + mio_oow_t* bcslen, + mio_cmgr_t* cmgr +); + +MIO_EXPORT int mio_conv_uchars_to_bchars_with_cmgr ( + const mio_uch_t* ucs, + mio_oow_t* ucslen, + mio_bch_t* bcs, + mio_oow_t* bcslen, + mio_cmgr_t* cmgr +); + +/* ------------------------------------------------------------------------- */ + +MIO_EXPORT mio_cmgr_t* mio_get_utf8_cmgr ( + void +); + +/** + * The mio_conv_uchars_to_utf8() function converts a unicode character string \a ucs + * to a UTF8 string and writes it into the buffer pointed to by \a bcs, but + * not more than \a bcslen bytes including the terminating null. + * + * Upon return, \a bcslen is modified to the actual number of bytes written to + * \a bcs excluding the terminating null; \a ucslen is modified to the number of + * wide characters converted. + * + * You may pass #MIO_NULL for \a bcs to dry-run conversion or to get the + * required buffer size for conversion. -2 is never returned in this case. + * + * \return + * - 0 on full conversion, + * - -1 on no or partial conversion for an illegal character encountered, + * - -2 on no or partial conversion for a small buffer. + * + * \code + * const mio_uch_t ucs[] = { 'H', 'e', 'l', 'l', 'o' }; + * mio_bch_t bcs[10]; + * mio_oow_t ucslen = 5; + * mio_oow_t bcslen = MIO_COUNTOF(bcs); + * n = mio_conv_uchars_to_utf8 (ucs, &ucslen, bcs, &bcslen); + * if (n <= -1) + * { + * // conversion error + * } + * \endcode + */ +MIO_EXPORT int mio_conv_uchars_to_utf8 ( + const mio_uch_t* ucs, + mio_oow_t* ucslen, + mio_bch_t* bcs, + mio_oow_t* bcslen +); + +/** + * The mio_conv_utf8_to_uchars() function converts a UTF8 string to a uncide string. + * + * It never returns -2 if \a ucs is #MIO_NULL. + * + * \code + * const mio_bch_t* bcs = "test string"; + * mio_uch_t ucs[100]; + * mio_oow_t ucslen = MIO_COUNTOF(buf), n; + * mio_oow_t bcslen = 11; + * int n; + * n = mio_conv_utf8_to_uchars (bcs, &bcslen, ucs, &ucslen); + * if (n <= -1) { invalid/incomplenete sequence or buffer to small } + * \endcode + * + * The resulting \a ucslen can still be greater than 0 even if the return + * value is negative. The value indiates the number of characters converted + * before the error has occurred. + * + * \return 0 on success. + * -1 if \a bcs contains an illegal character. + * -2 if the wide-character string buffer is too small. + * -3 if \a bcs is not a complete sequence. + */ +MIO_EXPORT int mio_conv_utf8_to_uchars ( + const mio_bch_t* bcs, + mio_oow_t* bcslen, + mio_uch_t* ucs, + mio_oow_t* ucslen +); + + +MIO_EXPORT int mio_conv_ucstr_to_utf8 ( + const mio_uch_t* ucs, + mio_oow_t* ucslen, + mio_bch_t* bcs, + mio_oow_t* bcslen +); + +MIO_EXPORT int mio_conv_utf8_to_ucstr ( + const mio_bch_t* bcs, + mio_oow_t* bcslen, + mio_uch_t* ucs, + mio_oow_t* ucslen +); + + +MIO_EXPORT mio_oow_t mio_uc_to_utf8 ( + mio_uch_t uc, + mio_bch_t* utf8, + mio_oow_t size +); + +MIO_EXPORT mio_oow_t mio_utf8_to_uc ( + const mio_bch_t* utf8, + mio_oow_t size, + mio_uch_t* uc +); + +/* ------------------------------------------------------------------------- */ + +#if defined(MIO_HAVE_UINT16_T) +MIO_EXPORT mio_uint16_t mio_ntoh16 ( + mio_uint16_t x +); + +MIO_EXPORT mio_uint16_t mio_hton16 ( + mio_uint16_t x +); +#endif + +#if defined(MIO_HAVE_UINT32_T) +MIO_EXPORT mio_uint32_t mio_ntoh32 ( + mio_uint32_t x +); + +MIO_EXPORT mio_uint32_t mio_hton32 ( + mio_uint32_t x +); +#endif + +#if defined(MIO_HAVE_UINT64_T) +MIO_EXPORT mio_uint64_t mio_ntoh64 ( + mio_uint64_t x +); + +MIO_EXPORT mio_uint64_t mio_hton64 ( + mio_uint64_t x +); +#endif + +#if defined(MIO_HAVE_UINT128_T) +MIO_EXPORT mio_uint128_t mio_ntoh128 ( + mio_uint128_t x +); + +MIO_EXPORT mio_uint128_t mio_hton128 ( + mio_uint128_t x +); +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mio/lib/mio.c b/mio/lib/mio.c index 5dc3155..8e3d5ca 100644 --- a/mio/lib/mio.c +++ b/mio/lib/mio.c @@ -99,7 +99,7 @@ static int mux_open (mio_t* mio) mux = MIO_MMGR_ALLOC (mio->mmgr, MIO_SIZEOF(*mux)); if (!mux) { - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; return -1; } @@ -143,7 +143,7 @@ static int mux_control (mio_dev_t* dev, int cmd, mio_syshnd_t hnd, int dev_capa) tmp = MIO_MMGR_REALLOC(mio->mmgr, mux->map.ptr, new_capa * MIO_SIZEOF(*tmp)); if (!tmp) { - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; return -1; } @@ -187,7 +187,7 @@ static int mux_control (mio_dev_t* dev, int cmd, mio_syshnd_t hnd, int dev_capa) tmp1 = MIO_MMGR_REALLOC(mio->mmgr, mux->pd.pfd, new_capa * MIO_SIZEOF(*tmp1)); if (!tmp1) { - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; return -1; } @@ -195,7 +195,7 @@ static int mux_control (mio_dev_t* dev, int cmd, mio_syshnd_t hnd, int dev_capa) if (!tmp2) { MIO_MMGR_FREE (mio->mmgr, tmp1); - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; return -1; } @@ -276,7 +276,7 @@ static int mux_open (mio_t* mio) mux = MIO_MMGR_ALLOC (mio->mmgr, MIO_SIZEOF(*mux)); if (!mux) { - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; return -1; } @@ -352,7 +352,7 @@ mio_t* mio_open (mio_mmgr_t* mmgr, mio_oow_t xtnsize, mio_oow_t tmrcapa, mio_err } else { - if (errnum) *errnum = MIO_ENOMEM; + if (errnum) *errnum = MIO_ESYSMEM; } return mio; @@ -378,7 +378,7 @@ int mio_init (mio_t* mio, mio_mmgr_t* mmgr, mio_oow_t tmrcapa) mio->tmr.jobs = MIO_MMGR_ALLOC (mio->mmgr, tmrcapa * MIO_SIZEOF(mio_tmrjob_t)); if (!mio->tmr.jobs) { - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; mux_close (mio); return -1; } @@ -938,7 +938,7 @@ mio_dev_t* mio_makedev (mio_t* mio, mio_oow_t dev_size, mio_dev_mth_t* dev_mth, dev = MIO_MMGR_ALLOC(mio->mmgr, dev_size); if (!dev) { - mio->errnum = MIO_ENOMEM; + mio->errnum = MIO_ESYSMEM; return MIO_NULL; } @@ -1202,7 +1202,7 @@ void mio_dev_halt (mio_dev_t* dev) int mio_dev_ioctl (mio_dev_t* dev, int cmd, void* arg) { if (dev->dev_mth->ioctl) return dev->dev_mth->ioctl (dev, cmd, arg); - dev->mio->errnum = MIO_ENOSUP; /* TODO: different error code ? */ + dev->mio->errnum = MIO_ENOIMPL; /* TODO: different error code ? */ return -1; } @@ -1502,7 +1502,7 @@ enqueue_data: q = (mio_wq_t*)MIO_MMGR_ALLOC(dev->mio->mmgr, MIO_SIZEOF(*q) + (dstaddr? dstaddr->len: 0) + urem); if (!q) { - dev->mio->errnum = MIO_ENOMEM; + dev->mio->errnum = MIO_ESYSMEM; return -1; } @@ -1580,7 +1580,7 @@ enqueue_completed_write: cwq = (mio_cwq_t*)MIO_MMGR_ALLOC(dev->mio->mmgr, MIO_SIZEOF(*cwq) + cwq_extra_aligned); if (!cwq) { - dev->mio->errnum = MIO_ENOMEM; + dev->mio->errnum = MIO_ESYSMEM; return -1; } } @@ -1640,7 +1640,7 @@ mio_errnum_t mio_syserrtoerrnum (int no) switch (no) { case ENOMEM: - return MIO_ENOMEM; + return MIO_ESYSMEM; case EINVAL: return MIO_EINVAL; @@ -1690,3 +1690,37 @@ mio_errnum_t mio_syserrtoerrnum (int no) return MIO_ESYSERR; } } + + +/* -------------------------------------------------------------------------- */ + +void* mio_allocmem (mio_t* mio, mio_oow_t size) +{ + void* ptr; + + ptr = MIO_MMGR_ALLOC (mio->mmgr, size); + if (!ptr) mio_seterrnum (mio, MIO_ESYSMEM); + return ptr; +} + +void* mio_callocmem (mio_t* mio, mio_oow_t size) +{ + void* ptr; + + ptr = MIO_MMGR_ALLOC (mio->mmgr, size); + if (!ptr) mio_seterrnum (mio, MIO_ESYSMEM); + else MIO_MEMSET (ptr, 0, size); + return ptr; +} + +void* mio_reallocmem (mio_t* mio, void* ptr, mio_oow_t size) +{ + ptr = MIO_MMGR_REALLOC (mio->mmgr, ptr, size); + if (!ptr) mio_seterrnum (mio, MIO_ESYSMEM); + return ptr; +} + +void mio_freemem (mio_t* mio, void* ptr) +{ + MIO_MMGR_FREE (mio->mmgr, ptr); +} diff --git a/mio/lib/mio.h b/mio/lib/mio.h index ec423db..a0ee467 100644 --- a/mio/lib/mio.h +++ b/mio/lib/mio.h @@ -80,34 +80,60 @@ 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, - MIO_ENOIMPL, - MIO_ESYSERR, - MIO_EINTERN, + MIO_ENOERR, /**< no error */ + MIO_EGENERIC, /**< generic error */ + + MIO_ENOIMPL, /**< not implemented */ + MIO_ESYSERR, /**< system error */ + MIO_EINTERN, /**< internal error */ + MIO_ESYSMEM, /**< insufficient system memory */ + MIO_EOOMEM, /**< insufficient object memory */ + MIO_ETYPE, /**< invalid class/type */ + + MIO_EINVAL, /**< invalid parameter or data */ + MIO_ENOENT, /**< data not found */ + MIO_EEXIST, /**< existing/duplicate data */ + MIO_EBUSY, + MIO_EACCES, + MIO_EPERM, /**< operation not permitted */ + MIO_ENOTDIR, + MIO_EINTR, + MIO_EPIPE, + MIO_EAGAIN, + MIO_EBADHND, - MIO_ENOMEM, - MIO_EINVAL, - MIO_EEXIST, - MIO_ENOENT, - MIO_ENOSUP, /* not supported */ MIO_EMFILE, /* too many open files */ MIO_ENFILE, - MIO_EAGAIN, + + MIO_EIOERR, /**< I/O error */ + MIO_EECERR, /**< encoding conversion error */ + MIO_EECMORE, /**< insufficient data for encoding conversion */ + MIO_EBUFFULL, /**< buffer full */ + MIO_ECONRF, /* connection refused */ MIO_ECONRS, /* connection reset */ MIO_ENOCAPA, /* no capability */ MIO_ETMOUT, /* timed out */ - MIO_EPERM, /* operation not permitted */ MIO_EDEVMAKE, MIO_EDEVERR, MIO_EDEVHUP }; - typedef enum mio_errnum_t mio_errnum_t; +#define MIO_ERRMSG_CAPA (2048) + +struct mio_errinf_t +{ + mio_errnum_t num; + mio_ooch_t msg[MIO_ERRMSG_CAPA]; +}; +typedef struct mio_errinf_t mio_errinf_t; + enum mio_stopreq_t { MIO_STOPREQ_NONE = 0, @@ -364,6 +390,71 @@ enum mio_dev_event_t typedef enum mio_dev_event_t mio_dev_event_t; + + + +#define MIO_CWQFL_SIZE 16 +#define MIO_CWQFL_ALIGN 16 + +typedef struct mio_mux_t mio_mux_t; + +struct mio_t +{ + mio_mmgr_t* mmgr; + mio_cmgr_t* cmgr; + mio_errnum_t errnum; + struct + { + union + { + mio_ooch_t ooch[MIO_ERRMSG_CAPA]; + mio_bch_t bch[MIO_ERRMSG_CAPA]; + mio_uch_t uch[MIO_ERRMSG_CAPA]; + } tmpbuf; + mio_ooch_t buf[MIO_ERRMSG_CAPA]; + mio_oow_t len; + } errmsg; + int shuterr; + + mio_stopreq_t stopreq; /* stop request to abort mio_loop() */ + + struct + { + mio_dev_t* head; + mio_dev_t* tail; + } actdev; /* active devices */ + + struct + { + mio_dev_t* head; + mio_dev_t* tail; + } hltdev; /* halted devices */ + + struct + { + mio_dev_t* head; + mio_dev_t* tail; + } zmbdev; /* zombie devices */ + + mio_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */ + + unsigned int renew_watch: 1; + unsigned int in_exec: 1; + + struct + { + mio_oow_t capa; + mio_oow_t size; + mio_tmrjob_t* jobs; + } tmr; + + mio_cwq_t cwq; + mio_cwq_t* cwqfl[MIO_CWQFL_SIZE]; /* list of free cwq objects */ + + /* platform specific fields below */ + mio_mux_t* mux; +}; + /* ========================================================================= */ #ifdef __cplusplus @@ -391,6 +482,84 @@ MIO_EXPORT void mio_fini ( mio_t* mio ); + +#if defined(MIO_HAVE_INLINE) + static MIO_INLINE mio_mmgr_t* mio_getmmgr (mio_t* mio) { return mio->mmgr; } + static MIO_INLINE void* mio_getxtn (mio_t* mio) { return (void*)(mio + 1); } + + static MIO_INLINE mio_cmgr_t* mio_getcmgr (mio_t* mio) { return mio->cmgr; } + static MIO_INLINE void mio_setcmgr (mio_t* mio, mio_cmgr_t* cmgr) { mio->cmgr = cmgr; } + + static MIO_INLINE mio_errnum_t mio_geterrnum (mio_t* mio) { return mio->errnum; } +#else +# define mio_getmmgr(mio) ((mio)->mmgr) +# define mio_getxtn(mio) ((void*)((mio) + 1)) + +# define mio_getcmgr(mio) ((mio)->cmgr) +# define mio_setcmgr(mio,mgr) ((mio)->cmgr = (mgr)) + +# define mio_geterrnum(mio) ((mio)->errnum) +#endif + +MIO_EXPORT void mio_seterrnum ( + mio_t* mio, + mio_errnum_t errnum +); + +MIO_EXPORT void mio_seterrwithsyserr ( + mio_t* mio, + int syserr_type, + int syserr_code +); + +MIO_EXPORT void mio_seterrbfmt ( + mio_t* mio, + mio_errnum_t errnum, + const mio_bch_t* fmt, + ... +); + +MIO_EXPORT void mio_seterrufmt ( + mio_t* mio, + mio_errnum_t errnum, + const mio_uch_t* fmt, + ... +); + +MIO_EXPORT void mio_seterrbfmtwithsyserr ( + mio_t* mio, + int syserr_type, + int syserr_code, + const mio_bch_t* fmt, + ... +); + +MIO_EXPORT void mio_seterrufmtwithsyserr ( + mio_t* mio, + int syserr_type, + int syserr_code, + const mio_uch_t* fmt, + ... +); + +MIO_EXPORT const mio_ooch_t* mio_geterrstr ( + mio_t* mio +); + +MIO_EXPORT const mio_ooch_t* mio_geterrmsg ( + mio_t* mio +); + +MIO_EXPORT void mio_geterrinf ( + mio_t* mio, + mio_errinf_t* info +); + +MIO_EXPORT const mio_ooch_t* mio_backuperrmsg ( + mio_t* mio +); + + MIO_EXPORT int mio_exec ( mio_t* mio ); @@ -549,50 +718,186 @@ MIO_EXPORT int mio_gettmrjobdeadline ( mio_ntime_t* deadline ); -/* ========================================================================= */ - - -#if defined(MIO_HAVE_UINT16_T) -MIO_EXPORT mio_uint16_t mio_ntoh16 ( - mio_uint16_t x +/* ========================================================================= + * SYSTEM MEMORY MANAGEMENT FUCNTIONS VIA MMGR + * ========================================================================= */ +MIO_EXPORT void* mio_allocmem ( + mio_t* mio, + mio_oow_t size ); -MIO_EXPORT mio_uint16_t mio_hton16 ( - mio_uint16_t x +MIO_EXPORT void* mio_callocmem ( + mio_t* mio, + mio_oow_t size ); + +MIO_EXPORT void* mio_reallocmem ( + mio_t* mio, + void* ptr, + mio_oow_t size +); + +MIO_EXPORT void mio_freemem ( + mio_t* mio, + void* ptr +); + +/* ========================================================================= + * STRING ENCODING CONVERSION + * ========================================================================= */ + +#if defined(MIO_OOCH_IS_UCH) +# define mio_convootobchars(mio,oocs,oocslen,bcs,bcslen) mio_convutobchars(mio,oocs,oocslen,bcs,bcslen) +# define mio_convbtooochars(mio,bcs,bcslen,oocs,oocslen) mio_convbtouchars(mio,bcs,bcslen,oocs,oocslen) +# define mio_convootobcstr(mio,oocs,oocslen,bcs,bcslen) mio_convutobcstr(mio,oocs,oocslen,bcs,bcslen) +# define mio_convbtooocstr(mio,bcs,bcslen,oocs,oocslen) mio_convbtoucstr(mio,bcs,bcslen,oocs,oocslen) +#else +# define mio_convootouchars(mio,oocs,oocslen,bcs,bcslen) mio_convbtouchars(mio,oocs,oocslen,bcs,bcslen) +# define mio_convutooochars(mio,bcs,bcslen,oocs,oocslen) mio_convutobchars(mio,bcs,bcslen,oocs,oocslen) +# define mio_convootoucstr(mio,oocs,oocslen,bcs,bcslen) mio_convbtoucstr(mio,oocs,oocslen,bcs,bcslen) +# define mio_convutooocstr(mio,bcs,bcslen,oocs,oocslen) mio_convutobcstr(mio,bcs,bcslen,oocs,oocslen) #endif -#if defined(MIO_HAVE_UINT32_T) -MIO_EXPORT mio_uint32_t mio_ntoh32 ( - mio_uint32_t x +MIO_EXPORT int mio_convbtouchars ( + mio_t* mio, + const mio_bch_t* bcs, + mio_oow_t* bcslen, + mio_uch_t* ucs, + mio_oow_t* ucslen ); -MIO_EXPORT mio_uint32_t mio_hton32 ( - mio_uint32_t x +MIO_EXPORT int mio_convutobchars ( + mio_t* mio, + const mio_uch_t* ucs, + mio_oow_t* ucslen, + mio_bch_t* bcs, + mio_oow_t* bcslen ); + +/** + * The mio_convbtoucstr() function converts a null-terminated byte string + * to a wide string. + */ +MIO_EXPORT int mio_convbtoucstr ( + mio_t* mio, + const mio_bch_t* bcs, + mio_oow_t* bcslen, + mio_uch_t* ucs, + mio_oow_t* ucslen +); + + +/** + * The mio_convutobcstr() function converts a null-terminated wide string + * to a byte string. + */ +MIO_EXPORT int mio_convutobcstr ( + mio_t* mio, + const mio_uch_t* ucs, + mio_oow_t* ucslen, + mio_bch_t* bcs, + mio_oow_t* bcslen +); + + +#if defined(MIO_OOCH_IS_UCH) +# define mio_dupootobcharswithheadroom(mio,hrb,oocs,oocslen,bcslen) mio_duputobcharswithheadroom(mio,hrb,oocs,oocslen,bcslen) +# define mio_dupbtooocharswithheadroom(mio,hrb,bcs,bcslen,oocslen) mio_dupbtoucharswithheadroom(mio,hrb,bcs,bcslen,oocslen) +# define mio_dupootobchars(mio,oocs,oocslen,bcslen) mio_duputobchars(mio,oocs,oocslen,bcslen) +# define mio_dupbtooochars(mio,bcs,bcslen,oocslen) mio_dupbtouchars(mio,bcs,bcslen,oocslen) + +# define mio_dupootobcstrwithheadroom(mio,hrb,oocs,bcslen) mio_duputobcstrwithheadroom(mio,hrb,oocs,bcslen) +# define mio_dupbtooocstrwithheadroom(mio,hrb,bcs,oocslen) mio_dupbtoucstrwithheadroom(mio,hrb,bcs,oocslen) +# define mio_dupootobcstr(mio,oocs,bcslen) mio_duputobcstr(mio,oocs,bcslen) +# define mio_dupbtooocstr(mio,bcs,oocslen) mio_dupbtoucstr(mio,bcs,oocslen) +#else +# define mio_dupootoucharswithheadroom(mio,hrb,oocs,oocslen,ucslen) mio_dupbtoucharswithheadroom(mio,hrb,oocs,oocslen,ucslen) +# define mio_duputooocharswithheadroom(mio,hrb,ucs,ucslen,oocslen) mio_duputobcharswithheadroom(mio,hrb,ucs,ucslen,oocslen) +# define mio_dupootouchars(mio,oocs,oocslen,ucslen) mio_dupbtouchars(mio,oocs,oocslen,ucslen) +# define mio_duputooochars(mio,ucs,ucslen,oocslen) mio_duputobchars(mio,ucs,ucslen,oocslen) + +# define mio_dupootoucstrwithheadroom(mio,hrb,oocs,ucslen) mio_dupbtoucstrwithheadroom(mio,hrb,oocs,ucslen) +# define mio_duputooocstrwithheadroom(mio,hrb,ucs,oocslen) mio_duputobcstrwithheadroom(mio,hrb,ucs,oocslen) +# define mio_dupootoucstr(mio,oocs,ucslen) mio_dupbtoucstr(mio,oocs,ucslen) +# define mio_duputooocstr(mio,ucs,oocslen) mio_duputobcstr(mio,ucs,oocslen) #endif -#if defined(MIO_HAVE_UINT64_T) -MIO_EXPORT mio_uint64_t mio_ntoh64 ( - mio_uint64_t x + +MIO_EXPORT mio_uch_t* mio_dupbtoucharswithheadroom ( + mio_t* mio, + mio_oow_t headroom_bytes, + const mio_bch_t* bcs, + mio_oow_t bcslen, + mio_oow_t* ucslen ); -MIO_EXPORT mio_uint64_t mio_hton64 ( - mio_uint64_t x +MIO_EXPORT mio_bch_t* mio_duputobcharswithheadroom ( + mio_t* mio, + mio_oow_t headroom_bytes, + const mio_uch_t* ucs, + mio_oow_t ucslen, + mio_oow_t* bcslen ); + +MIO_EXPORT mio_uch_t* mio_dupbtouchars ( + mio_t* mio, + const mio_bch_t* bcs, + mio_oow_t bcslen, + mio_oow_t* ucslen +); + +MIO_EXPORT mio_bch_t* mio_duputobchars ( + mio_t* mio, + const mio_uch_t* ucs, + mio_oow_t ucslen, + mio_oow_t* bcslen +); + + +MIO_EXPORT mio_uch_t* mio_dupbtoucstrwithheadroom ( + mio_t* mio, + mio_oow_t headroom_bytes, + const mio_bch_t* bcs, + mio_oow_t* ucslen +); + +MIO_EXPORT mio_bch_t* mio_duputobcstrwithheadroom ( + mio_t* mio, + mio_oow_t headroom_bytes, + const mio_uch_t* ucs, + mio_oow_t* bcslen +); + +MIO_EXPORT mio_uch_t* mio_dupbtoucstr ( + mio_t* mio, + const mio_bch_t* bcs, + mio_oow_t* ucslen /* optional: length of returned string */ +); + +MIO_EXPORT mio_bch_t* mio_duputobcstr ( + mio_t* mio, + const mio_uch_t* ucs, + mio_oow_t* bcslen /* optional: length of returned string */ +); + + +#if defined(MIO_OOCH_IS_UCH) +# define mio_dupoochars(mio,oocs,oocslen) mio_dupuchars(mio,oocs,oocslen) +#else +# define mio_dupoochars(mio,oocs,oocslen) mio_dupbchars(mio,oocs,oocslen) #endif -#if defined(MIO_HAVE_UINT128_T) -MIO_EXPORT mio_uint128_t mio_ntoh128 ( - mio_uint128_t x +MIO_EXPORT mio_uch_t* mio_dupuchars ( + mio_t* mio, + const mio_uch_t* ucs, + mio_oow_t ucslen ); -MIO_EXPORT mio_uint128_t mio_hton128 ( - mio_uint128_t x +MIO_EXPORT mio_bch_t* mio_dupbchars ( + mio_t* mio, + const mio_bch_t* bcs, + mio_oow_t bcslen ); -#endif - -/* ========================================================================= */ #ifdef __cplusplus diff --git a/mio/lib/sck-addr.c b/mio/lib/sck-addr.c index 4dbf27d..80f9552 100644 --- a/mio/lib/sck-addr.c +++ b/mio/lib/sck-addr.c @@ -1,3 +1,53 @@ +/* + * $Id$ + * + Copyright (c) 2015-2016 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 WAfRRANTIES + 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. + */ + + +#include "mio-prv.h" + +#include +#include +#include +#include +#include + +#if defined(HAVE_NETINET_IN_H) +# include +#endif +#if defined(HAVE_SYS_UN_H) +# include +#endif +#if defined(HAVE_NETPACKET_PACKET_H) +# include +#endif +#if defined(HAVE_NET_IF_DL_H) +# include +#endif + +#include + union sockaddr_t { struct sockaddr sa; @@ -16,385 +66,31 @@ union sockaddr_t }; typedef union sockaddr_t sockaddr_t; - -static int str_to_ipv4 (const mio_ooch_t* str, mio_oow_t len, struct in_addr* inaddr) -{ - const mio_ooch_t* end; - int dots = 0, digits = 0; - mio_uint32_t acc = 0, addr = 0; - mio_ooch_t c; - - end = str + len; - - do - { - if (str >= end) - { - if (dots < 3 || digits == 0) return -1; - addr = (addr << 8) | acc; - break; - } - - c = *str++; - - if (c >= '0' && c <= '9') - { - if (digits > 0 && acc == 0) return -1; - acc = acc * 10 + (c - '0'); - if (acc > 255) return -1; - digits++; - } - else if (c == '.') - { - if (dots >= 3 || digits == 0) return -1; - addr = (addr << 8) | acc; - dots++; acc = 0; digits = 0; - } - else return -1; - } - while (1); - - inaddr->s_addr = mio_hton32(addr); - return 0; - -} - -#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) -static int str_to_ipv6 (const mio_ooch_t* src, mio_oow_t len, struct in6_addr* inaddr) -{ - mio_uint8_t* tp, * endp, * colonp; - const mio_ooch_t* curtok; - mio_ooch_t ch; - int saw_xdigit; - unsigned int val; - const mio_ooch_t* src_end; - - src_end = src + len; - - MIO_MEMSET (inaddr, 0, MIO_SIZEOF(*inaddr)); - tp = &inaddr->s6_addr[0]; - endp = &inaddr->s6_addr[MIO_COUNTOF(inaddr->s6_addr)]; - colonp = MIO_NULL; - - /* Leading :: requires some special handling. */ - if (src < src_end && *src == ':') - { - src++; - if (src >= src_end || *src != ':') return -1; - } - - curtok = src; - saw_xdigit = 0; - val = 0; - - while (src < src_end) - { - int v1; - - ch = *src++; - - if (ch >= '0' && ch <= '9') - v1 = ch - '0'; - else if (ch >= 'A' && ch <= 'F') - v1 = ch - 'A' + 10; - else if (ch >= 'a' && ch <= 'f') - v1 = ch - 'a' + 10; - else v1 = -1; - if (v1 >= 0) - { - val <<= 4; - val |= v1; - if (val > 0xffff) return -1; - saw_xdigit = 1; - continue; - } - - if (ch == ':') - { - curtok = src; - if (!saw_xdigit) - { - if (colonp) return -1; - colonp = tp; - continue; - } - else if (src >= src_end) - { - /* a colon can't be the last character */ - return -1; - } - - *tp++ = (mio_uint8_t)(val >> 8) & 0xff; - *tp++ = (mio_uint8_t)val & 0xff; - saw_xdigit = 0; - val = 0; - continue; - } - - if (ch == '.' && ((tp + MIO_SIZEOF(struct in_addr)) <= endp) && - str_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) - { - tp += MIO_SIZEOF(struct in_addr*); - saw_xdigit = 0; - break; - } - - return -1; - } - - if (saw_xdigit) - { - if (tp + MIO_SIZEOF(mio_uint16_t) > endp) return -1; - *tp++ = (mio_uint8_t)(val >> 8) & 0xff; - *tp++ = (mio_uint8_t)val & 0xff; - } - if (colonp != MIO_NULL) - { - /* - * Since some memmove()'s erroneously fail to handle - * overlapping regions, we'll do the shift by hand. - */ - mio_oow_t n = tp - colonp; - mio_oow_t i; - - for (i = 1; i <= n; i++) - { - endp[-i] = colonp[n - i]; - colonp[n - i] = 0; - } - tp = endp; - } - - if (tp != endp) return -1; - - return 0; -} -#endif +#undef char_t +#undef cstr_t +#undef str_to_sockaddr +#undef str_to_ipv4 +#undef str_to_ipv6 +#define CHAR_T_IS_BCH +#undef CHAR_T_IS_UCH +#define char_t mio_bch_t +#define cstr_t mio_bcs_t +#define str_to_sockaddr bcstr_to_sockaddr +#define str_to_ipv4 bcstr_to_ipv4 +#define str_to_ipv6 bcstr_to_ipv6 +#include "sck-addr.h" -static int str_to_sockaddr (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, sockaddr_t* nwad) -{ - const mio_ooch_t* p; - const mio_ooch_t* end; - mio_oocs_t tmp; - - p = str; - end = str + len; - - if (p >= end) - { - mio_seterrbfmt (mio, MIO_EINVAL, "blank address"); - return -1; - } - - MIO_MEMSET (nwad, 0, MIO_SIZEOF(*nwad)); - -#if defined(AF_UNIX) - if (*p == '/' && len >= 2) - { - #if defined(MIO_OOCH_IS_BCH) - mio_copybcstr (nwad->un.sun_path, MIO_COUNTOF(nwad->un.sun_path), str); - #else - mio_oow_t dstlen; - - dstlen = MIO_COUNTOF(nwad->un.sun_path) - 1; - if (mio_convutobchars (mio, p, &len, nwad->un.sun_path, &dstlen) <= -1) - { - mio_seterrbfmt (mio, MIO_EINVAL, "unable to convert encoding"); - return -1; - } - nwad->un.sun_path[dstlen] = '\0'; - #endif - nwad->un.sun_family = AF_UNIX; - return 0; - } -#endif - -#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) - if (*p == '[') - { - /* IPv6 address */ - tmp.ptr = (mio_ooch_t*)++p; /* skip [ and remember the position */ - while (p < end && *p != '%' && *p != ']') p++; - - if (p >= end) goto no_rbrack; - - tmp.len = p - tmp.ptr; - if (*p == '%') - { - /* handle scope id */ - mio_uint32_t x; - - p++; /* skip % */ - - if (p >= end) - { - /* premature end */ - mio_seterrbfmt (mio, MIO_EINVAL, "scope id blank"); - return -1; - } - - if (*p >= '0' && *p <= '9') - { - /* numeric scope id */ - nwad->in6.sin6_scope_id = 0; - do - { - x = nwad->in6.sin6_scope_id * 10 + (*p - '0'); - if (x < nwad->in6.sin6_scope_id) - { - mio_seterrbfmt (mio, MIO_EINVAL, "scope id too large"); - return -1; /* overflow */ - } - nwad->in6.sin6_scope_id = x; - p++; - } - while (p < end && *p >= '0' && *p <= '9'); - } - else - { -#if 0 -TODO: - /* interface name as a scope id? */ - const mio_ooch_t* stmp = p; - unsigned int index; - do p++; while (p < end && *p != ']'); - if (mio_nwifwcsntoindex (stmp, p - stmp, &index) <= -1) return -1; - tmpad.u.in6.scope = index; -#endif - } - - if (p >= end || *p != ']') goto no_rbrack; - } - p++; /* skip ] */ - - if (str_to_ipv6(tmp.ptr, tmp.len, &nwad->in6.sin6_addr) <= -1) goto unrecog; - nwad->in6.sin6_family = AF_INET6; - } - else - { -#endif - /* IPv4 address */ - tmp.ptr = (mio_ooch_t*)p; - while (p < end && *p != ':') p++; - tmp.len = p - tmp.ptr; - - if (str_to_ipv4(tmp.ptr, tmp.len, &nwad->in4.sin_addr) <= -1) - { - #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) - /* check if it is an IPv6 address not enclosed in []. - * the port number can't be specified in this format. */ - if (p >= end || *p != ':') - { - /* without :, it can't be an ipv6 address */ - goto unrecog; - } - - - while (p < end && *p != '%') p++; - tmp.len = p - tmp.ptr; - - if (str_to_ipv6(tmp.ptr, tmp.len, &nwad->in6.sin6_addr) <= -1) goto unrecog; - - if (p < end && *p == '%') - { - /* handle scope id */ - mio_uint32_t x; - - p++; /* skip % */ - - if (p >= end) - { - /* premature end */ - mio_seterrbfmt (mio, MIO_EINVAL, "scope id blank"); - return -1; - } - - if (*p >= '0' && *p <= '9') - { - /* numeric scope id */ - nwad->in6.sin6_scope_id = 0; - do - { - x = nwad->in6.sin6_scope_id * 10 + (*p - '0'); - if (x < nwad->in6.sin6_scope_id) - { - mio_seterrbfmt (mio, MIO_EINVAL, "scope id too large"); - return -1; /* overflow */ - } - nwad->in6.sin6_scope_id = x; - p++; - } - while (p < end && *p >= '0' && *p <= '9'); - } - else - { -#if 0 -TODO - /* interface name as a scope id? */ - const mio_ooch_t* stmp = p; - unsigned int index; - do p++; while (p < end); - if (mio_nwifwcsntoindex (stmp, p - stmp, &index) <= -1) return -1; - nwad->in6.sin6_scope_id = index; -#endif - } - } - - if (p < end) goto unrecog; /* some gargage after the end? */ - - nwad->in6.sin6_family = AF_INET6; - return 0; - #else - goto unrecog; - #endif - } - - nwad->in4.sin_family = AF_INET; -#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) - } -#endif - - if (p < end && *p == ':') - { - /* port number */ - mio_uint32_t port = 0; - - p++; /* skip : */ - - tmp.ptr = (mio_ooch_t*)p; - while (p < end && *p >= '0' && *p <= '9') - { - port = port * 10 + (*p - '0'); - p++; - } - - tmp.len = p - tmp.ptr; - if (tmp.len <= 0 || tmp.len >= 6 || - port > MIO_TYPE_MAX(mio_uint16_t)) - { - mio_seterrbfmt (mio, MIO_EINVAL, "port number blank or too large"); - return -1; - } - - #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) - if (nwad->in4.sin_family == AF_INET) - nwad->in4.sin_port = mio_hton16(port); - else - nwad->in6.sin6_port = mio_hton16(port); - #else - nwad->in4.sin_port = mio_hton16(port); - #endif - } - - return 0; - - -unrecog: - mio_seterrbfmt (mio, MIO_EINVAL, "unrecognized address"); - return -1; - -no_rbrack: - mio_seterrbfmt (mio, MIO_EINVAL, "missing right bracket"); - return -1; -} +#undef char_t +#undef cstr_t +#undef str_to_sockaddr +#undef str_to_ipv4 +#undef str_to_ipv6 +#undef CHAR_T_IS_BCH +#define CHAR_T_IS_UCH +#define char_t mio_uch_t +#define cstr_t mio_ucs_t +#define str_to_sockaddr ucstr_to_sockaddr +#define str_to_ipv4 ucstr_to_ipv4 +#define str_to_ipv6 ucstr_to_ipv6 +#include "sck-addr.h" diff --git a/mio/lib/sck-addr.h b/mio/lib/sck-addr.h new file mode 100644 index 0000000..59fb160 --- /dev/null +++ b/mio/lib/sck-addr.h @@ -0,0 +1,383 @@ +/* this file is included by sck-addr.c */ + +static int str_to_ipv4 (const char_t* str, mio_oow_t len, struct in_addr* inaddr) +{ + const char_t* end; + int dots = 0, digits = 0; + mio_uint32_t acc = 0, addr = 0; + char_t c; + + end = str + len; + + do + { + if (str >= end) + { + if (dots < 3 || digits == 0) return -1; + addr = (addr << 8) | acc; + break; + } + + c = *str++; + + if (c >= '0' && c <= '9') + { + if (digits > 0 && acc == 0) return -1; + acc = acc * 10 + (c - '0'); + if (acc > 255) return -1; + digits++; + } + else if (c == '.') + { + if (dots >= 3 || digits == 0) return -1; + addr = (addr << 8) | acc; + dots++; acc = 0; digits = 0; + } + else return -1; + } + while (1); + + inaddr->s_addr = mio_hton32(addr); + return 0; + +} + +#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) +static int str_to_ipv6 (const char_t* src, mio_oow_t len, struct in6_addr* inaddr) +{ + mio_uint8_t* tp, * endp, * colonp; + const char_t* curtok; + char_t ch; + int saw_xdigit; + unsigned int val; + const char_t* src_end; + + src_end = src + len; + + MIO_MEMSET (inaddr, 0, MIO_SIZEOF(*inaddr)); + tp = &inaddr->s6_addr[0]; + endp = &inaddr->s6_addr[MIO_COUNTOF(inaddr->s6_addr)]; + colonp = MIO_NULL; + + /* Leading :: requires some special handling. */ + if (src < src_end && *src == ':') + { + src++; + if (src >= src_end || *src != ':') return -1; + } + + curtok = src; + saw_xdigit = 0; + val = 0; + + while (src < src_end) + { + int v1; + + ch = *src++; + + if (ch >= '0' && ch <= '9') + v1 = ch - '0'; + else if (ch >= 'A' && ch <= 'F') + v1 = ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + v1 = ch - 'a' + 10; + else v1 = -1; + if (v1 >= 0) + { + val <<= 4; + val |= v1; + if (val > 0xffff) return -1; + saw_xdigit = 1; + continue; + } + + if (ch == ':') + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) return -1; + colonp = tp; + continue; + } + else if (src >= src_end) + { + /* a colon can't be the last character */ + return -1; + } + + *tp++ = (mio_uint8_t)(val >> 8) & 0xff; + *tp++ = (mio_uint8_t)val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + + if (ch == '.' && ((tp + MIO_SIZEOF(struct in_addr)) <= endp) && + str_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) + { + tp += MIO_SIZEOF(struct in_addr*); + saw_xdigit = 0; + break; + } + + return -1; + } + + if (saw_xdigit) + { + if (tp + MIO_SIZEOF(mio_uint16_t) > endp) return -1; + *tp++ = (mio_uint8_t)(val >> 8) & 0xff; + *tp++ = (mio_uint8_t)val & 0xff; + } + if (colonp != MIO_NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + mio_oow_t n = tp - colonp; + mio_oow_t i; + + for (i = 1; i <= n; i++) + { + endp[-i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + + if (tp != endp) return -1; + + return 0; +} +#endif + + +static int str_to_sockaddr (mio_t* mio, const char_t* str, mio_oow_t len, sockaddr_t* nwad) +{ + const char_t* p; + const char_t* end; + cstr_t tmp; + + p = str; + end = str + len; + + if (p >= end) + { + mio_seterrbfmt (mio, MIO_EINVAL, "blank address"); + return -1; + } + + MIO_MEMSET (nwad, 0, MIO_SIZEOF(*nwad)); + +#if defined(AF_UNIX) + if (*p == '/' && len >= 2) + { + #if defined(CHAR_T_IS_BCH) + mio_copy_bcstr (nwad->un.sun_path, MIO_COUNTOF(nwad->un.sun_path), str); + #else + mio_oow_t dstlen; + + dstlen = MIO_COUNTOF(nwad->un.sun_path) - 1; + if (mio_convutobchars(mio, p, &len, nwad->un.sun_path, &dstlen) <= -1) + { + mio_seterrbfmt (mio, MIO_EINVAL, "unable to convert encoding"); + return -1; + } + nwad->un.sun_path[dstlen] = '\0'; + #endif + nwad->un.sun_family = AF_UNIX; + return 0; + } +#endif + +#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + if (*p == '[') + { + /* IPv6 address */ + tmp.ptr = (char_t*)++p; /* skip [ and remember the position */ + while (p < end && *p != '%' && *p != ']') p++; + + if (p >= end) goto no_rbrack; + + tmp.len = p - tmp.ptr; + if (*p == '%') + { + /* handle scope id */ + mio_uint32_t x; + + p++; /* skip % */ + + if (p >= end) + { + /* premature end */ + mio_seterrbfmt (mio, MIO_EINVAL, "scope id blank"); + return -1; + } + + if (*p >= '0' && *p <= '9') + { + /* numeric scope id */ + nwad->in6.sin6_scope_id = 0; + do + { + x = nwad->in6.sin6_scope_id * 10 + (*p - '0'); + if (x < nwad->in6.sin6_scope_id) + { + mio_seterrbfmt (mio, MIO_EINVAL, "scope id too large"); + return -1; /* overflow */ + } + nwad->in6.sin6_scope_id = x; + p++; + } + while (p < end && *p >= '0' && *p <= '9'); + } + else + { +#if 0 +TODO: + /* interface name as a scope id? */ + const char_t* stmp = p; + unsigned int index; + do p++; while (p < end && *p != ']'); + if (mio_nwifwcsntoindex (stmp, p - stmp, &index) <= -1) return -1; + tmpad.u.in6.scope = index; +#endif + } + + if (p >= end || *p != ']') goto no_rbrack; + } + p++; /* skip ] */ + + if (str_to_ipv6(tmp.ptr, tmp.len, &nwad->in6.sin6_addr) <= -1) goto unrecog; + nwad->in6.sin6_family = AF_INET6; + } + else + { +#endif + /* IPv4 address */ + tmp.ptr = (char_t*)p; + while (p < end && *p != ':') p++; + tmp.len = p - tmp.ptr; + + if (str_to_ipv4(tmp.ptr, tmp.len, &nwad->in4.sin_addr) <= -1) + { + #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + /* check if it is an IPv6 address not enclosed in []. + * the port number can't be specified in this format. */ + if (p >= end || *p != ':') + { + /* without :, it can't be an ipv6 address */ + goto unrecog; + } + + + while (p < end && *p != '%') p++; + tmp.len = p - tmp.ptr; + + if (str_to_ipv6(tmp.ptr, tmp.len, &nwad->in6.sin6_addr) <= -1) goto unrecog; + + if (p < end && *p == '%') + { + /* handle scope id */ + mio_uint32_t x; + + p++; /* skip % */ + + if (p >= end) + { + /* premature end */ + mio_seterrbfmt (mio, MIO_EINVAL, "scope id blank"); + return -1; + } + + if (*p >= '0' && *p <= '9') + { + /* numeric scope id */ + nwad->in6.sin6_scope_id = 0; + do + { + x = nwad->in6.sin6_scope_id * 10 + (*p - '0'); + if (x < nwad->in6.sin6_scope_id) + { + mio_seterrbfmt (mio, MIO_EINVAL, "scope id too large"); + return -1; /* overflow */ + } + nwad->in6.sin6_scope_id = x; + p++; + } + while (p < end && *p >= '0' && *p <= '9'); + } + else + { +#if 0 +TODO + /* interface name as a scope id? */ + const char_t* stmp = p; + unsigned int index; + do p++; while (p < end); + if (mio_nwifwcsntoindex (stmp, p - stmp, &index) <= -1) return -1; + nwad->in6.sin6_scope_id = index; +#endif + } + } + + if (p < end) goto unrecog; /* some gargage after the end? */ + + nwad->in6.sin6_family = AF_INET6; + return 0; + #else + goto unrecog; + #endif + } + + nwad->in4.sin_family = AF_INET; +#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + } +#endif + + if (p < end && *p == ':') + { + /* port number */ + mio_uint32_t port = 0; + + p++; /* skip : */ + + tmp.ptr = (char_t*)p; + while (p < end && *p >= '0' && *p <= '9') + { + port = port * 10 + (*p - '0'); + p++; + } + + tmp.len = p - tmp.ptr; + if (tmp.len <= 0 || tmp.len >= 6 || + port > MIO_TYPE_MAX(mio_uint16_t)) + { + mio_seterrbfmt (mio, MIO_EINVAL, "port number blank or too large"); + return -1; + } + + #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + if (nwad->in4.sin_family == AF_INET) + nwad->in4.sin_port = mio_hton16(port); + else + nwad->in6.sin6_port = mio_hton16(port); + #else + nwad->in4.sin_port = mio_hton16(port); + #endif + } + + return 0; + + +unrecog: + mio_seterrbfmt (mio, MIO_EINVAL, "unrecognized address"); + return -1; + +no_rbrack: + mio_seterrbfmt (mio, MIO_EINVAL, "missing right bracket"); + return -1; +} diff --git a/mio/lib/utl.c b/mio/lib/utl.c new file mode 100644 index 0000000..03b727a --- /dev/null +++ b/mio/lib/utl.c @@ -0,0 +1,1368 @@ +/* + * $Id$ + * + Copyright (c) 2015-2016 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 WAfRRANTIES + 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. + */ + +#include "mio-prv.h" + + +#define MIO_MT(x) (x) +#define IS_MSPACE(x) ((x) == MIO_MT(' ') || (x) == MIO_MT('\t') || (x) == MIO_MT('\n') || (x) == MIO_MT('\r')) + +mio_bch_t* mio_mbsdup (mio_t* mio, const mio_bch_t* src) +{ + mio_bch_t* dst; + mio_oow_t len; + + dst = (mio_bch_t*)src; + while (*dst != MIO_MT('\0')) dst++; + len = dst - src; + + dst = MIO_MMGR_ALLOC (mio->mmgr, (len + 1) * MIO_SIZEOF(*src)); + if (!dst) + { + mio->errnum = MIO_ESYSMEM; + return MIO_NULL; + } + + MIO_MEMCPY (dst, src, (len + 1) * MIO_SIZEOF(*src)); + return dst; +} + +mio_oow_t mio_mbscpy (mio_bch_t* buf, const mio_bch_t* str) +{ + mio_bch_t* org = buf; + while ((*buf++ = *str++) != MIO_MT('\0')); + return buf - org - 1; +} + +int mio_mbsspltrn ( + mio_bch_t* s, const mio_bch_t* delim, + mio_bch_t lquote, mio_bch_t rquote, + mio_bch_t escape, const mio_bch_t* trset) +{ + mio_bch_t* p = s, *d; + mio_bch_t* sp = MIO_NULL, * ep = MIO_NULL; + int delim_mode; + int cnt = 0; + + if (delim == MIO_NULL) delim_mode = 0; + else + { + delim_mode = 1; + for (d = (mio_bch_t*)delim; *d != MIO_MT('\0'); d++) + if (!IS_MSPACE(*d)) delim_mode = 2; + } + + if (delim_mode == 0) + { + /* skip preceding space characters */ + while (IS_MSPACE(*p)) p++; + + /* when 0 is given as "delim", it has an effect of cutting + preceding and trailing space characters off "s". */ + if (lquote != MIO_MT('\0') && *p == lquote) + { + mio_mbscpy (p, p + 1); + + for (;;) + { + if (*p == MIO_MT('\0')) return -1; + + if (escape != MIO_MT('\0') && *p == escape) + { + if (trset != MIO_NULL && p[1] != MIO_MT('\0')) + { + const mio_bch_t* ep = trset; + while (*ep != MIO_MT('\0')) + { + if (p[1] == *ep++) + { + p[1] = *ep; + break; + } + } + } + + mio_mbscpy (p, p + 1); + } + else + { + if (*p == rquote) + { + p++; + break; + } + } + + if (sp == 0) sp = p; + ep = p; + p++; + } + while (IS_MSPACE(*p)) p++; + if (*p != MIO_MT('\0')) return -1; + + if (sp == 0 && ep == 0) s[0] = MIO_MT('\0'); + else + { + ep[1] = MIO_MT('\0'); + if (s != (mio_bch_t*)sp) mio_mbscpy (s, sp); + cnt++; + } + } + else + { + while (*p) + { + if (!IS_MSPACE(*p)) + { + if (sp == 0) sp = p; + ep = p; + } + p++; + } + + if (sp == 0 && ep == 0) s[0] = MIO_MT('\0'); + else + { + ep[1] = MIO_MT('\0'); + if (s != (mio_bch_t*)sp) mio_mbscpy (s, sp); + cnt++; + } + } + } + else if (delim_mode == 1) + { + mio_bch_t* o; + + while (*p) + { + o = p; + while (IS_MSPACE(*p)) p++; + if (o != p) { mio_mbscpy (o, p); p = o; } + + if (lquote != MIO_MT('\0') && *p == lquote) + { + mio_mbscpy (p, p + 1); + + for (;;) + { + if (*p == MIO_MT('\0')) return -1; + + if (escape != MIO_MT('\0') && *p == escape) + { + if (trset != MIO_NULL && p[1] != MIO_MT('\0')) + { + const mio_bch_t* ep = trset; + while (*ep != MIO_MT('\0')) + { + if (p[1] == *ep++) + { + p[1] = *ep; + break; + } + } + } + mio_mbscpy (p, p + 1); + } + else + { + if (*p == rquote) + { + *p++ = MIO_MT('\0'); + cnt++; + break; + } + } + p++; + } + } + else + { + o = p; + for (;;) + { + if (*p == MIO_MT('\0')) + { + if (o != p) cnt++; + break; + } + if (IS_MSPACE (*p)) + { + *p++ = MIO_MT('\0'); + cnt++; + break; + } + p++; + } + } + } + } + else /* if (delim_mode == 2) */ + { + mio_bch_t* o; + int ok; + + while (*p != MIO_MT('\0')) + { + o = p; + while (IS_MSPACE(*p)) p++; + if (o != p) { mio_mbscpy (o, p); p = o; } + + if (lquote != MIO_MT('\0') && *p == lquote) + { + mio_mbscpy (p, p + 1); + + for (;;) + { + if (*p == MIO_MT('\0')) return -1; + + if (escape != MIO_MT('\0') && *p == escape) + { + if (trset != MIO_NULL && p[1] != MIO_MT('\0')) + { + const mio_bch_t* ep = trset; + while (*ep != MIO_MT('\0')) + { + if (p[1] == *ep++) + { + p[1] = *ep; + break; + } + } + } + + mio_mbscpy (p, p + 1); + } + else + { + if (*p == rquote) + { + *p++ = MIO_MT('\0'); + cnt++; + break; + } + } + p++; + } + + ok = 0; + while (IS_MSPACE(*p)) p++; + if (*p == MIO_MT('\0')) ok = 1; + for (d = (mio_bch_t*)delim; *d != MIO_MT('\0'); d++) + { + if (*p == *d) + { + ok = 1; + mio_mbscpy (p, p + 1); + break; + } + } + if (ok == 0) return -1; + } + else + { + o = p; sp = ep = 0; + + for (;;) + { + if (*p == MIO_MT('\0')) + { + if (ep) + { + ep[1] = MIO_MT('\0'); + p = &ep[1]; + } + cnt++; + break; + } + for (d = (mio_bch_t*)delim; *d != MIO_MT('\0'); d++) + { + if (*p == *d) + { + if (sp == MIO_NULL) + { + mio_mbscpy (o, p); p = o; + *p++ = MIO_MT('\0'); + } + else + { + mio_mbscpy (&ep[1], p); + mio_mbscpy (o, sp); + o[ep - sp + 1] = MIO_MT('\0'); + p = &o[ep - sp + 2]; + } + cnt++; + /* last empty field after delim */ + if (*p == MIO_MT('\0')) cnt++; + goto exit_point; + } + } + + if (!IS_MSPACE (*p)) + { + if (sp == MIO_NULL) sp = p; + ep = p; + } + p++; + } +exit_point: + ; + } + } + } + + return cnt; +} + +int mio_mbsspl ( + mio_bch_t* s, const mio_bch_t* delim, + mio_bch_t lquote, mio_bch_t rquote, mio_bch_t escape) +{ + return mio_mbsspltrn (s, delim, lquote, rquote, escape, MIO_NULL); +} + +/* ========================================================================= */ + +int mio_equal_uchars (const mio_uch_t* str1, const mio_uch_t* str2, mio_oow_t len) +{ + mio_oow_t i; + + /* NOTE: you should call this function after having ensured that + * str1 and str2 are in the same length */ + + for (i = 0; i < len; i++) + { + if (str1[i] != str2[i]) return 0; + } + + return 1; +} + +int mio_equal_bchars (const mio_bch_t* str1, const mio_bch_t* str2, mio_oow_t len) +{ + mio_oow_t i; + + /* NOTE: you should call this function after having ensured that + * str1 and str2 are in the same length */ + + for (i = 0; i < len; i++) + { + if (str1[i] != str2[i]) return 0; + } + + return 1; +} + +int mio_comp_uchars (const mio_uch_t* str1, mio_oow_t len1, const mio_uch_t* str2, mio_oow_t len2) +{ + mio_uchu_t c1, c2; + const mio_uch_t* end1 = str1 + len1; + const mio_uch_t* end2 = str2 + len2; + + while (str1 < end1) + { + c1 = *str1; + if (str2 < end2) + { + c2 = *str2; + if (c1 > c2) return 1; + if (c1 < c2) return -1; + } + else return 1; + str1++; str2++; + } + + return (str2 < end2)? -1: 0; +} + +int mio_comp_bchars (const mio_bch_t* str1, mio_oow_t len1, const mio_bch_t* str2, mio_oow_t len2) +{ + mio_bchu_t c1, c2; + const mio_bch_t* end1 = str1 + len1; + const mio_bch_t* end2 = str2 + len2; + + while (str1 < end1) + { + c1 = *str1; + if (str2 < end2) + { + c2 = *str2; + if (c1 > c2) return 1; + if (c1 < c2) return -1; + } + else return 1; + str1++; str2++; + } + + return (str2 < end2)? -1: 0; +} + +int mio_comp_ucstr (const mio_uch_t* str1, const mio_uch_t* str2) +{ + while (*str1 == *str2) + { + if (*str1 == '\0') return 0; + str1++; str2++; + } + + return ((mio_uchu_t)*str1 > (mio_uchu_t)*str2)? 1: -1; +} + +int mio_comp_bcstr (const mio_bch_t* str1, const mio_bch_t* str2) +{ + while (*str1 == *str2) + { + if (*str1 == '\0') return 0; + str1++; str2++; + } + + return ((mio_bchu_t)*str1 > (mio_bchu_t)*str2)? 1: -1; +} + +int mio_comp_ucstr_bcstr (const mio_uch_t* str1, const mio_bch_t* str2) +{ + while (*str1 == *str2) + { + if (*str1 == '\0') return 0; + str1++; str2++; + } + + return ((mio_uchu_t)*str1 > (mio_bchu_t)*str2)? 1: -1; +} + +int mio_comp_uchars_ucstr (const mio_uch_t* str1, mio_oow_t len, const mio_uch_t* str2) +{ + /* for "abc\0" of length 4 vs "abc", the fourth character + * of the first string is equal to the terminating null of + * the second string. the first string is still considered + * bigger */ + const mio_uch_t* end = str1 + len; + while (str1 < end && *str2 != '\0') + { + if (*str1 != *str2) return ((mio_uchu_t)*str1 > (mio_uchu_t)*str2)? 1: -1; + str1++; str2++; + } + return (str1 < end)? 1: (*str2 == '\0'? 0: -1); +} + +int mio_comp_uchars_bcstr (const mio_uch_t* str1, mio_oow_t len, const mio_bch_t* str2) +{ + const mio_uch_t* end = str1 + len; + while (str1 < end && *str2 != '\0') + { + if (*str1 != *str2) return ((mio_uchu_t)*str1 > (mio_bchu_t)*str2)? 1: -1; + str1++; str2++; + } + return (str1 < end)? 1: (*str2 == '\0'? 0: -1); +} + +int mio_comp_bchars_bcstr (const mio_bch_t* str1, mio_oow_t len, const mio_bch_t* str2) +{ + const mio_bch_t* end = str1 + len; + while (str1 < end && *str2 != '\0') + { + if (*str1 != *str2) return ((mio_bchu_t)*str1 > (mio_bchu_t)*str2)? 1: -1; + str1++; str2++; + } + return (str1 < end)? 1: (*str2 == '\0'? 0: -1); +} + +int mio_comp_bchars_ucstr (const mio_bch_t* str1, mio_oow_t len, const mio_uch_t* str2) +{ + const mio_bch_t* end = str1 + len; + while (str1 < end && *str2 != '\0') + { + if (*str1 != *str2) return ((mio_bchu_t)*str1 > (mio_uchu_t)*str2)? 1: -1; + str1++; str2++; + } + return (str1 < end)? 1: (*str2 == '\0'? 0: -1); +} + +void mio_copy_uchars (mio_uch_t* dst, const mio_uch_t* src, mio_oow_t len) +{ + /* take note of no forced null termination */ + mio_oow_t i; + for (i = 0; i < len; i++) dst[i] = src[i]; +} + +void mio_copy_bchars (mio_bch_t* dst, const mio_bch_t* src, mio_oow_t len) +{ + /* take note of no forced null termination */ + mio_oow_t i; + for (i = 0; i < len; i++) dst[i] = src[i]; +} + +void mio_copy_bchars_to_uchars (mio_uch_t* dst, const mio_bch_t* src, mio_oow_t len) +{ + /* copy without conversions. + * use mio_bctouchars() for conversion encoding */ + mio_oow_t i; + for (i = 0; i < len; i++) dst[i] = src[i]; +} + +mio_oow_t mio_copy_ucstr (mio_uch_t* dst, mio_oow_t len, const mio_uch_t* src) +{ + mio_uch_t* p, * p2; + + p = dst; p2 = dst + len - 1; + + while (p < p2) + { + if (*src == '\0') break; + *p++ = *src++; + } + + if (len > 0) *p = '\0'; + return p - dst; +} + +mio_oow_t mio_copy_bcstr (mio_bch_t* dst, mio_oow_t len, const mio_bch_t* src) +{ + mio_bch_t* p, * p2; + + p = dst; p2 = dst + len - 1; + + while (p < p2) + { + if (*src == '\0') break; + *p++ = *src++; + } + + if (len > 0) *p = '\0'; + return p - dst; +} + +mio_oow_t mio_count_ucstr (const mio_uch_t* str) +{ + const mio_uch_t* ptr = str; + while (*ptr != '\0') ptr++; + return ptr - str; +} + +mio_oow_t mio_count_bcstr (const mio_bch_t* str) +{ + const mio_bch_t* ptr = str; + while (*ptr != '\0') ptr++; + return ptr - str; +} + +mio_uch_t* mio_find_uchar (const mio_uch_t* ptr, mio_oow_t len, mio_uch_t c) +{ + const mio_uch_t* end; + + end = ptr + len; + while (ptr < end) + { + if (*ptr == c) return (mio_uch_t*)ptr; + ptr++; + } + + return MIO_NULL; +} + +mio_bch_t* mio_find_bchar (const mio_bch_t* ptr, mio_oow_t len, mio_bch_t c) +{ + const mio_bch_t* end; + + end = ptr + len; + while (ptr < end) + { + if (*ptr == c) return (mio_bch_t*)ptr; + ptr++; + } + + return MIO_NULL; +} + +mio_uch_t* mio_rfind_uchar (const mio_uch_t* ptr, mio_oow_t len, mio_uch_t c) +{ + const mio_uch_t* cur; + + cur = ptr + len; + while (cur > ptr) + { + --cur; + if (*cur == c) return (mio_uch_t*)cur; + } + + return MIO_NULL; +} + +mio_bch_t* mio_rfind_bchar (const mio_bch_t* ptr, mio_oow_t len, mio_bch_t c) +{ + const mio_bch_t* cur; + + cur = ptr + len; + while (cur > ptr) + { + --cur; + if (*cur == c) return (mio_bch_t*)cur; + } + + return MIO_NULL; +} + +mio_uch_t* mio_find_uchar_in_ucstr (const mio_uch_t* ptr, mio_uch_t c) +{ + while (*ptr != '\0') + { + if (*ptr == c) return (mio_uch_t*)ptr; + ptr++; + } + + return MIO_NULL; +} + +mio_bch_t* mio_find_bchar_in_bcstr (const mio_bch_t* ptr, mio_bch_t c) +{ + while (*ptr != '\0') + { + if (*ptr == c) return (mio_bch_t*)ptr; + ptr++; + } + + return MIO_NULL; +} + +/* ========================================================================= */ + +MIO_INLINE int mio_conv_bchars_to_uchars_with_cmgr ( + const mio_bch_t* bcs, mio_oow_t* bcslen, + mio_uch_t* ucs, mio_oow_t* ucslen, mio_cmgr_t* cmgr, int all) +{ + const mio_bch_t* p; + int ret = 0; + mio_oow_t mlen; + + if (ucs) + { + /* destination buffer is specified. + * copy the conversion result to the buffer */ + + mio_uch_t* q, * qend; + + p = bcs; + q = ucs; + qend = ucs + *ucslen; + mlen = *bcslen; + + while (mlen > 0) + { + mio_oow_t n; + + if (q >= qend) + { + /* buffer too small */ + ret = -2; + break; + } + + n = cmgr->bctouc (p, mlen, q); + if (n == 0) + { + /* invalid sequence */ + if (all) + { + n = 1; + *q = '?'; + } + else + { + ret = -1; + break; + } + } + if (n > mlen) + { + /* incomplete sequence */ + if (all) + { + n = 1; + *q = '?'; + } + else + { + ret = -3; + break; + } + } + + q++; + p += n; + mlen -= n; + } + + *ucslen = q - ucs; + *bcslen = p - bcs; + } + else + { + /* no destination buffer is specified. perform conversion + * but don't copy the result. the caller can call this function + * without a buffer to find the required buffer size, allocate + * a buffer with the size and call this function again with + * the buffer. */ + + mio_uch_t w; + mio_oow_t wlen = 0; + + p = bcs; + mlen = *bcslen; + + while (mlen > 0) + { + mio_oow_t n; + + n = cmgr->bctouc (p, mlen, &w); + if (n == 0) + { + /* invalid sequence */ + if (all) n = 1; + else + { + ret = -1; + break; + } + } + if (n > mlen) + { + /* incomplete sequence */ + if (all) n = 1; + else + { + ret = -3; + break; + } + } + + p += n; + mlen -= n; + wlen += 1; + } + + *ucslen = wlen; + *bcslen = p - bcs; + } + + return ret; +} + +MIO_INLINE int mio_conv_bcs_to_ucs_with_cmgr ( + const mio_bch_t* bcs, mio_oow_t* bcslen, + mio_uch_t* ucs, mio_oow_t* ucslen, mio_cmgr_t* cmgr, int all) +{ + const mio_bch_t* bp; + mio_oow_t mlen, wlen; + int n; + + for (bp = bcs; *bp != '\0'; bp++) /* nothing */ ; + + mlen = bp - bcs; wlen = *ucslen; + n = mio_conv_bchars_to_uchars_with_cmgr (bcs, &mlen, ucs, &wlen, cmgr, all); + if (ucs) + { + /* null-terminate the target buffer if it has room for it. */ + if (wlen < *ucslen) ucs[wlen] = '\0'; + else n = -2; /* buffer too small */ + } + *bcslen = mlen; *ucslen = wlen; + + return n; +} + +MIO_INLINE int mio_conv_uchars_to_bchars_with_cmgr ( + const mio_uch_t* ucs, mio_oow_t* ucslen, + mio_bch_t* bcs, mio_oow_t* bcslen, mio_cmgr_t* cmgr) +{ + const mio_uch_t* p = ucs; + const mio_uch_t* end = ucs + *ucslen; + int ret = 0; + + if (bcs) + { + mio_oow_t rem = *bcslen; + + while (p < end) + { + mio_oow_t n; + + if (rem <= 0) + { + ret = -2; /* buffer too small */ + break; + } + + n = cmgr->uctobc (*p, bcs, rem); + if (n == 0) + { + ret = -1; + break; /* illegal character */ + } + if (n > rem) + { + ret = -2; /* buffer too small */ + break; + } + bcs += n; rem -= n; p++; + } + + *bcslen -= rem; + } + else + { + mio_bch_t bcsbuf[MIO_BCSIZE_MAX]; + mio_oow_t mlen = 0; + + while (p < end) + { + mio_oow_t n; + + n = cmgr->uctobc (*p, bcsbuf, MIO_COUNTOF(bcsbuf)); + if (n == 0) + { + ret = -1; + break; /* illegal character */ + } + + /* it assumes that bcsbuf is large enough to hold a character */ + /*MIO_ASSERT (mio, n <= MIO_COUNTOF(bcsbuf));*/ + + p++; mlen += n; + } + + /* this length excludes the terminating null character. + * this function doesn't even null-terminate the result. */ + *bcslen = mlen; + } + + *ucslen = p - ucs; + return ret; +} + +MIO_INLINE int mio_conv_ucs_to_bcs_with_cmgr ( + const mio_uch_t* ucs, mio_oow_t* ucslen, + mio_bch_t* bcs, mio_oow_t* bcslen, mio_cmgr_t* cmgr) +{ + const mio_uch_t* p = ucs; + int ret = 0; + + if (bcs) + { + mio_oow_t rem = *bcslen; + + while (*p != '\0') + { + mio_oow_t n; + + if (rem <= 0) + { + ret = -2; + break; + } + + n = cmgr->uctobc(*p, bcs, rem); + if (n == 0) + { + ret = -1; + break; /* illegal character */ + } + if (n > rem) + { + ret = -2; + break; /* buffer too small */ + } + + bcs += n; rem -= n; p++; + } + + /* update bcslen to the length of the bcs string converted excluding + * terminating null */ + *bcslen -= rem; + + /* null-terminate the multibyte sequence if it has sufficient space */ + if (rem > 0) *bcs = '\0'; + else + { + /* if ret is -2 and cs[cslen] == '\0', + * this means that the bcs buffer was lacking one + * slot for the terminating null */ + ret = -2; /* buffer too small */ + } + } + else + { + mio_bch_t bcsbuf[MIO_BCSIZE_MAX]; + mio_oow_t mlen = 0; + + while (*p != '\0') + { + mio_oow_t n; + + n = cmgr->uctobc(*p, bcsbuf, MIO_COUNTOF(bcsbuf)); + if (n == 0) + { + ret = -1; + break; /* illegal character */ + } + + /* it assumes that bcs is large enough to hold a character */ + /*MIO_ASSERT (mio, n <= MIO_COUNTOF(bcs));*/ + + p++; mlen += n; + } + + /* this length holds the number of resulting multi-byte characters + * excluding the terminating null character */ + *bcslen = mlen; + } + + *ucslen = p - ucs; /* the number of wide characters handled. */ + return ret; +} + +/* ----------------------------------------------------------------------- */ + +static mio_cmgr_t utf8_cmgr = +{ + mio_utf8_to_uc, + mio_uc_to_utf8 +}; + +mio_cmgr_t* mio_get_utf8_cmgr (void) +{ + return &utf8_cmgr; +} + +int mio_conv_utf8_to_uchars (const mio_bch_t* bcs, mio_oow_t* bcslen, mio_uch_t* ucs, mio_oow_t* ucslen) +{ + /* the source is length bound */ + return mio_conv_bchars_to_uchars_with_cmgr(bcs, bcslen, ucs, ucslen, &utf8_cmgr, 0); +} + +int mio_conv_uchars_to_utf8 (const mio_uch_t* ucs, mio_oow_t* ucslen, mio_bch_t* bcs, mio_oow_t* bcslen) +{ + /* length bound */ + return mio_conv_uchars_to_bchars_with_cmgr(ucs, ucslen, bcs, bcslen, &utf8_cmgr); +} + +int mio_conv_utf8_to_ucstr (const mio_bch_t* bcs, mio_oow_t* bcslen, mio_uch_t* ucs, mio_oow_t* ucslen) +{ + /* null-terminated. */ + return mio_conv_bcs_to_ucs_with_cmgr(bcs, bcslen, ucs, ucslen, &utf8_cmgr, 0); +} + +int mio_conv_ucstr_to_utf8 (const mio_uch_t* ucs, mio_oow_t* ucslen, mio_bch_t* bcs, mio_oow_t* bcslen) +{ + /* null-terminated */ + return mio_conv_ucs_to_bcs_with_cmgr(ucs, ucslen, bcs, bcslen, &utf8_cmgr); +} + +/* ----------------------------------------------------------------------- */ + +int mio_convbtouchars (mio_t* mio, const mio_bch_t* bcs, mio_oow_t* bcslen, mio_uch_t* ucs, mio_oow_t* ucslen) +{ + /* length bound */ + int n; + + n = mio_conv_bchars_to_uchars_with_cmgr(bcs, bcslen, ucs, ucslen, mio->cmgr, 0); + + if (n <= -1) + { + /* -1: illegal character, -2: buffer too small, -3: incomplete sequence */ + mio_seterrnum (mio, (n == -2)? MIO_EBUFFULL: MIO_EECERR); + } + + return n; +} + +int mio_convutobchars (mio_t* mio, const mio_uch_t* ucs, mio_oow_t* ucslen, mio_bch_t* bcs, mio_oow_t* bcslen) +{ + /* length bound */ + int n; + + n = mio_conv_uchars_to_bchars_with_cmgr(ucs, ucslen, bcs, bcslen, mio->cmgr); + + if (n <= -1) + { + mio_seterrnum (mio, (n == -2)? MIO_EBUFFULL: MIO_EECERR); + } + + return n; +} + +int mio_convbtoucstr (mio_t* mio, const mio_bch_t* bcs, mio_oow_t* bcslen, mio_uch_t* ucs, mio_oow_t* ucslen) +{ + /* null-terminated. */ + int n; + + n = mio_conv_bcs_to_ucs_with_cmgr(bcs, bcslen, ucs, ucslen, mio->cmgr, 0); + + if (n <= -1) + { + mio_seterrnum (mio, (n == -2)? MIO_EBUFFULL: MIO_EECERR); + } + + return n; +} + +int mio_convutobcstr (mio_t* mio, const mio_uch_t* ucs, mio_oow_t* ucslen, mio_bch_t* bcs, mio_oow_t* bcslen) +{ + /* null-terminated */ + int n; + + n = mio_conv_ucs_to_bcs_with_cmgr(ucs, ucslen, bcs, bcslen, mio->cmgr); + + if (n <= -1) + { + mio_seterrnum (mio, (n == -2)? MIO_EBUFFULL: MIO_EECERR); + } + + return n; +} + +/* ----------------------------------------------------------------------- */ + +MIO_INLINE mio_uch_t* mio_dupbtoucharswithheadroom (mio_t* mio, mio_oow_t headroom_bytes, const mio_bch_t* bcs, mio_oow_t bcslen, mio_oow_t* ucslen) +{ + mio_oow_t inlen, outlen; + mio_uch_t* ptr; + + inlen = bcslen; + if (mio_convbtouchars(mio, bcs, &inlen, MIO_NULL, &outlen) <= -1) + { + /* note it's also an error if no full conversion is made in this function */ + return MIO_NULL; + } + + ptr = (mio_uch_t*)mio_allocmem(mio, headroom_bytes + ((outlen + 1) * MIO_SIZEOF(mio_uch_t))); + if (!ptr) return MIO_NULL; + + inlen = bcslen; + + ptr = (mio_uch_t*)((mio_oob_t*)ptr + headroom_bytes); + mio_convbtouchars (mio, bcs, &inlen, ptr, &outlen); + + /* mio_convbtouchars() doesn't null-terminate the target. + * but in mio_dupbtouchars(), i allocate space. so i don't mind + * null-terminating it with 1 extra character overhead */ + ptr[outlen] = '\0'; + if (ucslen) *ucslen = outlen; + return ptr; +} + +mio_uch_t* mio_dupbtouchars (mio_t* mio, const mio_bch_t* bcs, mio_oow_t bcslen, mio_oow_t* ucslen) +{ + return mio_dupbtoucharswithheadroom (mio, 0, bcs, bcslen, ucslen); +} + +MIO_INLINE mio_bch_t* mio_duputobcharswithheadroom (mio_t* mio, mio_oow_t headroom_bytes, const mio_uch_t* ucs, mio_oow_t ucslen, mio_oow_t* bcslen) +{ + mio_oow_t inlen, outlen; + mio_bch_t* ptr; + + inlen = ucslen; + if (mio_convutobchars(mio, ucs, &inlen, MIO_NULL, &outlen) <= -1) + { + /* note it's also an error if no full conversion is made in this function */ + return MIO_NULL; + } + + ptr = (mio_bch_t*)mio_allocmem(mio, headroom_bytes + ((outlen + 1) * MIO_SIZEOF(mio_bch_t))); + if (!ptr) return MIO_NULL; + + inlen = ucslen; + ptr = (mio_bch_t*)((mio_oob_t*)ptr + headroom_bytes); + mio_convutobchars (mio, ucs, &inlen, ptr, &outlen); + + ptr[outlen] = '\0'; + if (bcslen) *bcslen = outlen; + return ptr; +} + +mio_bch_t* mio_duputobchars (mio_t* mio, const mio_uch_t* ucs, mio_oow_t ucslen, mio_oow_t* bcslen) +{ + return mio_duputobcharswithheadroom (mio, 0, ucs, ucslen, bcslen); +} + + +/* ----------------------------------------------------------------------- */ + +MIO_INLINE mio_uch_t* mio_dupbtoucstrwithheadroom (mio_t* mio, mio_oow_t headroom_bytes, const mio_bch_t* bcs, mio_oow_t* ucslen) +{ + mio_oow_t inlen, outlen; + mio_uch_t* ptr; + + if (mio_convbtoucstr(mio, bcs, &inlen, MIO_NULL, &outlen) <= -1) + { + /* note it's also an error if no full conversion is made in this function */ + return MIO_NULL; + } + + outlen++; + ptr = (mio_uch_t*)mio_allocmem(mio, headroom_bytes + (outlen * MIO_SIZEOF(mio_uch_t))); + if (!ptr) return MIO_NULL; + + mio_convbtoucstr (mio, bcs, &inlen, ptr, &outlen); + if (ucslen) *ucslen = outlen; + return ptr; +} + +mio_uch_t* mio_dupbtoucstr (mio_t* mio, const mio_bch_t* bcs, mio_oow_t* ucslen) +{ + return mio_dupbtoucstrwithheadroom (mio, 0, bcs, ucslen); +} + +MIO_INLINE mio_bch_t* mio_duputobcstrwithheadroom (mio_t* mio, mio_oow_t headroom_bytes, const mio_uch_t* ucs, mio_oow_t* bcslen) +{ + mio_oow_t inlen, outlen; + mio_bch_t* ptr; + + if (mio_convutobcstr(mio, ucs, &inlen, MIO_NULL, &outlen) <= -1) + { + /* note it's also an error if no full conversion is made in this function */ + return MIO_NULL; + } + + outlen++; + ptr = (mio_bch_t*)mio_allocmem(mio, headroom_bytes + (outlen * MIO_SIZEOF(mio_bch_t))); + if (!ptr) return MIO_NULL; + + ptr = (mio_bch_t*)((mio_oob_t*)ptr + headroom_bytes); + + mio_convutobcstr (mio, ucs, &inlen, ptr, &outlen); + if (bcslen) *bcslen = outlen; + return ptr; +} + +mio_bch_t* mio_duputobcstr (mio_t* mio, const mio_uch_t* ucs, mio_oow_t* bcslen) +{ + return mio_duputobcstrwithheadroom (mio, 0, ucs, bcslen); +} +/* ----------------------------------------------------------------------- */ + +mio_uch_t* mio_dupuchars (mio_t* mio, const mio_uch_t* ucs, mio_oow_t ucslen) +{ + mio_uch_t* ptr; + + ptr = (mio_uch_t*)mio_allocmem(mio, (ucslen + 1) * MIO_SIZEOF(mio_uch_t)); + if (!ptr) return MIO_NULL; + + mio_copy_uchars (ptr, ucs, ucslen); + ptr[ucslen] = '\0'; + return ptr; +} + +mio_bch_t* mio_dupbchars (mio_t* mio, const mio_bch_t* bcs, mio_oow_t bcslen) +{ + mio_bch_t* ptr; + + ptr = (mio_bch_t*)mio_allocmem(mio, (bcslen + 1) * MIO_SIZEOF(mio_bch_t)); + if (!ptr) return MIO_NULL; + + mio_copy_bchars (ptr, bcs, bcslen); + ptr[bcslen] = '\0'; + return ptr; +} + +/* ========================================================================= */ + +#if defined(MIO_HAVE_UINT16_T) + +mio_uint16_t mio_ntoh16 (mio_uint16_t x) +{ +#if defined(MIO_ENDIAN_BIG) + return x; +#elif defined(MIO_ENDIAN_LITTLE) + mio_uint8_t* c = (mio_uint8_t*)&x; + return (mio_uint16_t)( + ((mio_uint16_t)c[0] << 8) | + ((mio_uint16_t)c[1] << 0)); +#else +# error Unknown endian +#endif +} + +mio_uint16_t mio_hton16 (mio_uint16_t x) +{ +#if defined(MIO_ENDIAN_BIG) + return x; +#elif defined(MIO_ENDIAN_LITTLE) + mio_uint8_t* c = (mio_uint8_t*)&x; + return (mio_uint16_t)( + ((mio_uint16_t)c[0] << 8) | + ((mio_uint16_t)c[1] << 0)); +#else +# error Unknown endian +#endif +} + +#endif + +/* ========================================================================= */ + +#if defined(MIO_HAVE_UINT32_T) + +mio_uint32_t mio_ntoh32 (mio_uint32_t x) +{ +#if defined(MIO_ENDIAN_BIG) + return x; +#elif defined(MIO_ENDIAN_LITTLE) + mio_uint8_t* c = (mio_uint8_t*)&x; + return (mio_uint32_t)( + ((mio_uint32_t)c[0] << 24) | + ((mio_uint32_t)c[1] << 16) | + ((mio_uint32_t)c[2] << 8) | + ((mio_uint32_t)c[3] << 0)); +#else +# error Unknown endian +#endif +} + +mio_uint32_t mio_hton32 (mio_uint32_t x) +{ +#if defined(MIO_ENDIAN_BIG) + return x; +#elif defined(MIO_ENDIAN_LITTLE) + mio_uint8_t* c = (mio_uint8_t*)&x; + return (mio_uint32_t)( + ((mio_uint32_t)c[0] << 24) | + ((mio_uint32_t)c[1] << 16) | + ((mio_uint32_t)c[2] << 8) | + ((mio_uint32_t)c[3] << 0)); +#else +# error Unknown endian +#endif +} +#endif + +/* ========================================================================= */ + +#if defined(MIO_HAVE_UINT64_T) + +mio_uint64_t mio_ntoh64 (mio_uint64_t x) +{ +#if defined(MIO_ENDIAN_BIG) + return x; +#elif defined(MIO_ENDIAN_LITTLE) + mio_uint8_t* c = (mio_uint8_t*)&x; + return (mio_uint64_t)( + ((mio_uint64_t)c[0] << 56) | + ((mio_uint64_t)c[1] << 48) | + ((mio_uint64_t)c[2] << 40) | + ((mio_uint64_t)c[3] << 32) | + ((mio_uint64_t)c[4] << 24) | + ((mio_uint64_t)c[5] << 16) | + ((mio_uint64_t)c[6] << 8) | + ((mio_uint64_t)c[7] << 0)); +#else +# error Unknown endian +#endif +} + +mio_uint64_t mio_hton64 (mio_uint64_t x) +{ +#if defined(MIO_ENDIAN_BIG) + return x; +#elif defined(MIO_ENDIAN_LITTLE) + mio_uint8_t* c = (mio_uint8_t*)&x; + return (mio_uint64_t)( + ((mio_uint64_t)c[0] << 56) | + ((mio_uint64_t)c[1] << 48) | + ((mio_uint64_t)c[2] << 40) | + ((mio_uint64_t)c[3] << 32) | + ((mio_uint64_t)c[4] << 24) | + ((mio_uint64_t)c[5] << 16) | + ((mio_uint64_t)c[6] << 8) | + ((mio_uint64_t)c[7] << 0)); +#else +# error Unknown endian +#endif +} + +#endif + +/* ========================================================================= */ + +#if defined(MIO_HAVE_UINT128_T) + +mio_uint128_t mio_ntoh128 (mio_uint128_t x) +{ +#if defined(MIO_ENDIAN_BIG) + return x; +#elif defined(MIO_ENDIAN_LITTLE) + mio_uint8_t* c = (mio_uint8_t*)&x; + return (mio_uint128_t)( + ((mio_uint128_t)c[0] << 120) | + ((mio_uint128_t)c[1] << 112) | + ((mio_uint128_t)c[2] << 104) | + ((mio_uint128_t)c[3] << 96) | + ((mio_uint128_t)c[4] << 88) | + ((mio_uint128_t)c[5] << 80) | + ((mio_uint128_t)c[6] << 72) | + ((mio_uint128_t)c[7] << 64) | + ((mio_uint128_t)c[8] << 56) | + ((mio_uint128_t)c[9] << 48) | + ((mio_uint128_t)c[10] << 40) | + ((mio_uint128_t)c[11] << 32) | + ((mio_uint128_t)c[12] << 24) | + ((mio_uint128_t)c[13] << 16) | + ((mio_uint128_t)c[14] << 8) | + ((mio_uint128_t)c[15] << 0)); +#else +# error Unknown endian +#endif +} + +mio_uint128_t mio_hton128 (mio_uint128_t x) +{ +#if defined(MIO_ENDIAN_BIG) + return x; +#elif defined(MIO_ENDIAN_LITTLE) + mio_uint8_t* c = (mio_uint8_t*)&x; + return (mio_uint128_t)( + ((mio_uint128_t)c[0] << 120) | + ((mio_uint128_t)c[1] << 112) | + ((mio_uint128_t)c[2] << 104) | + ((mio_uint128_t)c[3] << 96) | + ((mio_uint128_t)c[4] << 88) | + ((mio_uint128_t)c[5] << 80) | + ((mio_uint128_t)c[6] << 72) | + ((mio_uint128_t)c[7] << 64) | + ((mio_uint128_t)c[8] << 56) | + ((mio_uint128_t)c[9] << 48) | + ((mio_uint128_t)c[10] << 40) | + ((mio_uint128_t)c[11] << 32) | + ((mio_uint128_t)c[12] << 24) | + ((mio_uint128_t)c[13] << 16) | + ((mio_uint128_t)c[14] << 8) | + ((mio_uint128_t)c[15] << 0)); +#else +# error Unknown endian +#endif +} + +#endif + +/* ========================================================================= */