diff --git a/qse/cmd/awk/awk.c b/qse/cmd/awk/awk.c
index b8650450..72a42fb7 100644
--- a/qse/cmd/awk/awk.c
+++ b/qse/cmd/awk/awk.c
@@ -651,7 +651,7 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
if (qse_strcmp(opt.lngopt, QSE_T("script-encoding")) == 0)
{
- arg->script_cmgr = qse_getcmgrbyname (opt.arg);
+ arg->script_cmgr = qse_findcmgr (opt.arg);
if (arg->script_cmgr == QSE_NULL)
{
print_err (QSE_T("unknown script encoding - %s\n"), opt.arg);
@@ -660,7 +660,7 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
}
else if (qse_strcmp(opt.lngopt, QSE_T("console-encoding")) == 0)
{
- arg->console_cmgr = qse_getcmgrbyname (opt.arg);
+ arg->console_cmgr = qse_findcmgr (opt.arg);
if (arg->console_cmgr == QSE_NULL)
{
print_err (QSE_T("unknown console encoding - %s\n"), opt.arg);
diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am
index a4b1112e..38754dbe 100644
--- a/qse/include/qse/cmn/Makefile.am
+++ b/qse/include/qse/cmn/Makefile.am
@@ -11,11 +11,14 @@ pkginclude_HEADERS = \
fs.h \
gdl.h \
htb.h \
+ hton.h \
+ ipad.h \
lda.h \
main.h \
map.h \
mbwc.h \
mem.h \
+ nwad.h \
oht.h \
opt.h \
path.h \
diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in
index 5c00051d..de425273 100644
--- a/qse/include/qse/cmn/Makefile.in
+++ b/qse/include/qse/cmn/Makefile.in
@@ -52,10 +52,10 @@ CONFIG_CLEAN_VPATH_FILES =
SOURCES =
DIST_SOURCES =
am__pkginclude_HEADERS_DIST = alg.h chr.h dll.h env.h fio.h fma.h \
- fmt.h fs.h gdl.h htb.h lda.h main.h map.h mbwc.h mem.h oht.h \
- opt.h path.h pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h \
- stdio.h str.h time.h tio.h tre.h utf8.h xma.h Mmgr.hpp \
- StdMmgr.hpp Mmged.hpp
+ fmt.h fs.h gdl.h htb.h hton.h ipad.h lda.h main.h map.h mbwc.h \
+ mem.h nwad.h oht.h opt.h path.h pio.h pma.h rbt.h rex.h sio.h \
+ sll.h slmb.h stdio.h str.h time.h tio.h tre.h utf8.h xma.h \
+ Mmgr.hpp StdMmgr.hpp Mmged.hpp
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -229,9 +229,10 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
pkginclude_HEADERS = alg.h chr.h dll.h env.h fio.h fma.h fmt.h fs.h \
- gdl.h htb.h lda.h main.h map.h mbwc.h mem.h oht.h opt.h path.h \
- pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h stdio.h str.h \
- time.h tio.h tre.h utf8.h xma.h $(am__append_1)
+ gdl.h htb.h hton.h ipad.h lda.h main.h map.h mbwc.h mem.h \
+ nwad.h oht.h opt.h path.h pio.h pma.h rbt.h rex.h sio.h sll.h \
+ slmb.h stdio.h str.h time.h tio.h tre.h utf8.h xma.h \
+ $(am__append_1)
all: all-am
.SUFFIXES:
diff --git a/qse/include/qse/cmn/hton.h b/qse/include/qse/cmn/hton.h
new file mode 100644
index 00000000..46db5a90
--- /dev/null
+++ b/qse/include/qse/cmn/hton.h
@@ -0,0 +1,75 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2011 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+#ifndef _QSE_CMN_HTON_H_
+#define _QSE_CMN_HTON_H_
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(QSE_HAVE_UINT16_T)
+qse_uint16_t qse_ntoh16 (
+ qse_uint16_t x
+);
+
+qse_uint16_t qse_hton16 (
+ qse_uint16_t x
+);
+#endif
+
+#if defined(QSE_HAVE_UINT32_T)
+qse_uint32_t qse_ntoh32 (
+ qse_uint32_t x
+);
+
+qse_uint32_t qse_hton32 (
+ qse_uint32_t x
+);
+#endif
+
+#if defined(QSE_HAVE_UINT64_T)
+qse_uint64_t qse_ntoh64 (
+ qse_uint64_t x
+);
+
+qse_uint64_t qse_hton64 (
+ qse_uint64_t x
+);
+#endif
+
+#if defined(QSE_HAVE_UINT128_T)
+qse_uint128_t qse_ntoh128 (
+ qse_uint128_t x
+);
+
+qse_uint128_t qse_hton128 (
+ qse_uint128_t x
+);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/qse/include/qse/cmn/ipad.h b/qse/include/qse/cmn/ipad.h
new file mode 100644
index 00000000..6246c4ef
--- /dev/null
+++ b/qse/include/qse/cmn/ipad.h
@@ -0,0 +1,66 @@
+
+/*
+ * $Id$
+ *
+ Copyright 2006-2011 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+#ifndef _QSE_CMN_IPAD_H_
+#define _QSE_CMN_IPAD_H_
+
+#include
+#include
+
+typedef struct qse_ipad_t qse_ipad_t;
+typedef struct qse_ipad4_t qse_ipad4_t;
+typedef struct qse_ipad6_t qse_ipad6_t;
+
+#include
+struct qse_ipad4_t
+{
+ qse_uint32_t value;
+};
+struct qse_ipad6_t
+{
+ qse_uint8_t value[16];
+};
+#include
+
+struct qse_ipad_t
+{
+ enum
+ {
+ QSE_IPAD_IP4,
+ QSE_IPAD_IP6
+ } type;
+
+ union
+ {
+ qse_ipad4_t ip4;
+ qse_ipad4_t ip6;
+ } u;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/qse/include/qse/cmn/mbwc.h b/qse/include/qse/cmn/mbwc.h
index f3ba9618..24ec511b 100644
--- a/qse/include/qse/cmn/mbwc.h
+++ b/qse/include/qse/cmn/mbwc.h
@@ -28,6 +28,8 @@
#include
#include
+typedef qse_cmgr_t* (*qse_cmgr_finder_t) (const qse_char_t* name);
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -39,15 +41,23 @@ extern qse_cmgr_t* qse_utf8cmgr;
extern qse_cmgr_t* qse_slmbcmgr;
/**
- * The qse_getcmgrbyname() function find a builtin cmgr matching a given
+ * The qse_getfindcmgr() function find a builtin cmgr matching a given
* @a name and returns it. It returns #QSE_NULL if no match is found.
* The @a name can be one of "utf8", "slmb", and an empty string. Calling this
* function with an empty string is the same as calling qse_getdflcmgr().
*/
-qse_cmgr_t* qse_getcmgrbyname (
+qse_cmgr_t* qse_findcmgr (
const qse_char_t* name
);
+void qse_setcmgrfinder (
+ qse_cmgr_finder_t finder
+);
+
+qse_cmgr_finder_t qse_getcmgrfinder (
+ void
+);
+
/* --------------------------------------------------- */
/* DEFAULT GLOBAL CMGR */
/* --------------------------------------------------- */
diff --git a/qse/include/qse/cmn/nwad.h b/qse/include/qse/cmn/nwad.h
new file mode 100644
index 00000000..2f64336c
--- /dev/null
+++ b/qse/include/qse/cmn/nwad.h
@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2011 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+#ifndef _QSE_CMN_NWAD_H_
+#define _QSE_CMN_NWAD_H_
+
+#include
+#include
+#include
+
+struct qse_nwad_t
+{
+ enum
+ {
+ QSE_NWAD_IP4,
+ QSE_NWAD_IP6
+ } type;
+
+ union
+ {
+ struct
+ {
+ qse_ipad4_t addr;
+ qse_uint16_t port;
+ } ip4;
+
+ struct
+ {
+ qse_ipad6_t addr;
+ qse_uint16_t port;
+ } ip6;
+ } u;
+};
+
+#endif
diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h
index 566e68a9..7fe092de 100644
--- a/qse/include/qse/net/httpd.h
+++ b/qse/include/qse/net/httpd.h
@@ -52,6 +52,14 @@ enum qse_httpd_option_t
QSE_HTTPD_CGINOCLOEXEC = (1 << 1)
};
+typedef struct qse_httpd_stat_t qse_httpd_stat_t;
+struct qse_httpd_stat_t
+{
+ qse_foff_t size;
+ qse_ntime_t mtime;
+ const qse_mchar_t* mime;
+};
+
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
struct qse_httpd_cbs_t
{
@@ -65,14 +73,16 @@ struct qse_httpd_cbs_t
struct
{
- int (*executable) (qse_httpd_t* httpd, const qse_mchar_t* path);
- } path;
+ int (*executable) (
+ qse_httpd_t* httpd, const qse_mchar_t* path);
- struct
- {
+ int (*stat) (
+ qse_httpd_t* httpd, const qse_mchar_t* path,
+ qse_httpd_stat_t* stat);
+
int (*ropen) (
qse_httpd_t* httpd, const qse_mchar_t* path,
- qse_ubi_t* handle, qse_foff_t* size);
+ qse_ubi_t* handle);
int (*wopen) (
qse_httpd_t* httpd, const qse_mchar_t* path,
qse_ubi_t* handle);
@@ -115,7 +125,6 @@ struct qse_httpd_cbs_t
int (*handle_request) (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
- const qse_mchar_t* (*getmimetype) (qse_httpd_t* httpd, const qse_mchar_t* path);
int (*listdir) (qse_httpd_t* httpd, const qse_mchar_t* path);
};
@@ -313,6 +322,14 @@ qse_httpd_task_t* qse_httpd_entaskcontinue (
qse_htre_t* req
);
+qse_httpd_task_t* qse_httpd_entaskauth (
+ qse_httpd_t* httpd,
+ qse_httpd_client_t* client,
+ const qse_httpd_task_t* task,
+ const qse_mchar_t* realm,
+ qse_htre_t* req
+);
+
qse_httpd_task_t* qse_httpd_entaskdir (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
diff --git a/qse/lib/awk/StdAwk.cpp b/qse/lib/awk/StdAwk.cpp
index 3c2da892..9c2fd112 100644
--- a/qse/lib/awk/StdAwk.cpp
+++ b/qse/lib/awk/StdAwk.cpp
@@ -238,7 +238,7 @@ int StdAwk::setenc (Run& run, Value& ret, const Value* args, size_t nargs,
return ret.setInt ((long_t)-1);
}
- qse_cmgr_t* cmgr = qse_getcmgrbyname (ptr[1]);
+ qse_cmgr_t* cmgr = qse_findcmgr (ptr[1]);
if (cmgr == QSE_NULL)
{
return ret.setInt ((long_t)-1);
diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c
index 276a441b..cacfc5eb 100644
--- a/qse/lib/awk/std.c
+++ b/qse/lib/awk/std.c
@@ -124,7 +124,8 @@ typedef struct rxtn_t
} rxtn_t;
#if defined(QSE_CHAR_IS_WCHAR)
-static qse_cmgr_t* getcmgr_from_cmgrtab (qse_awk_rtx_t* rtx, const qse_char_t* ioname);
+static qse_cmgr_t* getcmgr_from_cmgrtab (
+ qse_awk_rtx_t* rtx, const qse_char_t* ioname);
#endif
static qse_flt_t custom_awk_pow (qse_awk_t* awk, qse_flt_t x, qse_flt_t y)
@@ -1562,7 +1563,8 @@ skip_system:
}
#if defined(QSE_CHAR_IS_WCHAR)
-static qse_cmgr_t* getcmgr_from_cmgrtab (qse_awk_rtx_t* rtx, const qse_char_t* ioname)
+static qse_cmgr_t* getcmgr_from_cmgrtab (
+ qse_awk_rtx_t* rtx, const qse_char_t* ioname)
{
rxtn_t* rxtn;
qse_htb_pair_t* pair;
@@ -1617,7 +1619,7 @@ static int fnc_setenc (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm)
}
}
- cmgr = qse_getcmgrbyname (ptr[1]);
+ cmgr = qse_findcmgr (ptr[1]);
if (cmgr == QSE_NULL) fret = -1;
else
{
diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am
index d388e09a..4db96187 100644
--- a/qse/lib/cmn/Makefile.am
+++ b/qse/lib/cmn/Makefile.am
@@ -36,10 +36,13 @@ libqsecmn_la_SOURCES = \
fs.c \
fs-err.c \
fs-move.c \
+ hton.c \
+ ipad.c \
main.c \
mbwc.c \
mbwc-str.c \
mem.c \
+ nwad.c \
oht.c \
opt.c \
path-basename.c \
diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in
index 48d3d743..f8adab80 100644
--- a/qse/lib/cmn/Makefile.in
+++ b/qse/lib/cmn/Makefile.in
@@ -77,18 +77,18 @@ LTLIBRARIES = $(lib_LTLIBRARIES)
libqsecmn_la_DEPENDENCIES =
am_libqsecmn_la_OBJECTS = alg-rand.lo alg-search.lo alg-sort.lo \
assert.lo chr.lo dll.lo env.lo gdl.lo htb.lo lda.lo fio.lo \
- fma.lo fmt.lo fs.lo fs-err.lo fs-move.lo main.lo mbwc.lo \
- mbwc-str.lo mem.lo oht.lo opt.lo path-basename.lo \
- path-canon.lo pio.lo pma.lo rbt.lo rex.lo sio.lo sll.lo \
- slmb.lo stdio.lo str-beg.lo str-cat.lo str-chr.lo str-cnv.lo \
- str-cmp.lo str-cpy.lo str-del.lo str-dup.lo str-dynm.lo \
- str-dynw.lo str-end.lo str-excl.lo str-fcpy.lo str-fnmat.lo \
- str-incl.lo str-len.lo str-pac.lo str-pbrk.lo str-put.lo \
- str-rev.lo str-rot.lo str-set.lo str-spl.lo str-spn.lo \
- str-str.lo str-subst.lo str-tok.lo str-trm.lo str-word.lo \
- time.lo tio.lo tio-get.lo tio-put.lo tre.lo tre-ast.lo \
- tre-compile.lo tre-match-backtrack.lo tre-match-parallel.lo \
- tre-parse.lo tre-stack.lo utf8.lo xma.lo
+ fma.lo fmt.lo fs.lo fs-err.lo fs-move.lo hton.lo ipad.lo \
+ main.lo mbwc.lo mbwc-str.lo mem.lo nwad.lo oht.lo opt.lo \
+ path-basename.lo path-canon.lo pio.lo pma.lo rbt.lo rex.lo \
+ sio.lo sll.lo slmb.lo stdio.lo str-beg.lo str-cat.lo \
+ str-chr.lo str-cnv.lo str-cmp.lo str-cpy.lo str-del.lo \
+ str-dup.lo str-dynm.lo str-dynw.lo str-end.lo str-excl.lo \
+ str-fcpy.lo str-fnmat.lo str-incl.lo str-len.lo str-pac.lo \
+ str-pbrk.lo str-put.lo str-rev.lo str-rot.lo str-set.lo \
+ str-spl.lo str-spn.lo str-str.lo str-subst.lo str-tok.lo \
+ str-trm.lo str-word.lo time.lo tio.lo tio-get.lo tio-put.lo \
+ tre.lo tre-ast.lo tre-compile.lo tre-match-backtrack.lo \
+ tre-match-parallel.lo tre-parse.lo tre-stack.lo utf8.lo xma.lo
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@@ -310,10 +310,13 @@ libqsecmn_la_SOURCES = \
fs.c \
fs-err.c \
fs-move.c \
+ hton.c \
+ ipad.c \
main.c \
mbwc.c \
mbwc-str.c \
mem.c \
+ nwad.c \
oht.c \
opt.c \
path-basename.c \
@@ -468,11 +471,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hton.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipad.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbwc-str.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbwc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwad.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oht.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-basename.Plo@am__quote@
diff --git a/qse/lib/cmn/hton.c b/qse/lib/cmn/hton.c
new file mode 100644
index 00000000..616b30ba
--- /dev/null
+++ b/qse/lib/cmn/hton.c
@@ -0,0 +1,203 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2011 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+#include
+
+
+/* --------------------------------------------------------------- */
+
+#if defined(QSE_HAVE_UINT16_T)
+
+qse_uint16_t qse_ntoh16 (qse_uint16_t x)
+{
+#if defined(QSE_ENDIAN_BIG)
+ return x;
+#elif defined(QSE_ENDIAN_LITTLE)
+ qse_uint8_t* c = (qse_uint8_t*)&x;
+ return (qse_uint16_t)(
+ ((qse_uint16_t)c[0] << 8) |
+ ((qse_uint16_t)c[1] << 0));
+#else
+# error Unknown endian
+#endif
+}
+
+qse_uint16_t qse_hton16 (qse_uint16_t x)
+{
+#if defined(QSE_ENDIAN_BIG)
+ return x;
+#elif defined(QSE_ENDIAN_LITTLE)
+ qse_uint8_t* c = (qse_uint8_t*)&x;
+ return (qse_uint16_t)(
+ ((qse_uint16_t)c[0] << 8) |
+ ((qse_uint16_t)c[1] << 0));
+#else
+# error Unknown endian
+#endif
+}
+
+#endif
+
+/* --------------------------------------------------------------- */
+
+#if defined(QSE_HAVE_UINT32_T)
+
+qse_uint32_t qse_ntoh32 (qse_uint32_t x)
+{
+#if defined(QSE_ENDIAN_BIG)
+ return x;
+#elif defined(QSE_ENDIAN_LITTLE)
+ qse_uint8_t* c = (qse_uint8_t*)&x;
+ return (qse_uint32_t)(
+ ((qse_uint32_t)c[0] << 24) |
+ ((qse_uint32_t)c[1] << 16) |
+ ((qse_uint32_t)c[2] << 8) |
+ ((qse_uint32_t)c[3] << 0));
+#else
+# error Unknown endian
+#endif
+}
+
+qse_uint32_t qse_hton32 (qse_uint32_t x)
+{
+#if defined(QSE_ENDIAN_BIG)
+ return x;
+#elif defined(QSE_ENDIAN_LITTLE)
+ qse_uint8_t* c = (qse_uint8_t*)&x;
+ return (qse_uint32_t)(
+ ((qse_uint32_t)c[0] << 24) |
+ ((qse_uint32_t)c[1] << 16) |
+ ((qse_uint32_t)c[2] << 8) |
+ ((qse_uint32_t)c[3] << 0));
+#else
+# error Unknown endian
+#endif
+}
+#endif
+
+/* --------------------------------------------------------------- */
+
+#if defined(QSE_HAVE_UINT64_T)
+
+qse_uint64_t qse_ntoh64 (qse_uint64_t x)
+{
+#if defined(QSE_ENDIAN_BIG)
+ return x;
+#elif defined(QSE_ENDIAN_LITTLE)
+ qse_uint8_t* c = (qse_uint8_t*)&x;
+ return (qse_uint64_t)(
+ ((qse_uint64_t)c[0] << 56) |
+ ((qse_uint64_t)c[1] << 48) |
+ ((qse_uint64_t)c[2] << 40) |
+ ((qse_uint64_t)c[3] << 32) |
+ ((qse_uint64_t)c[4] << 24) |
+ ((qse_uint64_t)c[5] << 16) |
+ ((qse_uint64_t)c[6] << 8) |
+ ((qse_uint64_t)c[7] << 0));
+#else
+# error Unknown endian
+#endif
+}
+
+qse_uint64_t qse_hton64 (qse_uint64_t x)
+{
+#if defined(QSE_ENDIAN_BIG)
+ return x;
+#elif defined(QSE_ENDIAN_LITTLE)
+ qse_uint8_t* c = (qse_uint8_t*)&x;
+ return (qse_uint64_t)(
+ ((qse_uint64_t)c[0] << 56) |
+ ((qse_uint64_t)c[1] << 48) |
+ ((qse_uint64_t)c[2] << 40) |
+ ((qse_uint64_t)c[3] << 32) |
+ ((qse_uint64_t)c[4] << 24) |
+ ((qse_uint64_t)c[5] << 16) |
+ ((qse_uint64_t)c[6] << 8) |
+ ((qse_uint64_t)c[7] << 0));
+#else
+# error Unknown endian
+#endif
+}
+
+#endif
+
+/* --------------------------------------------------------------- */
+
+#if defined(QSE_HAVE_UINT128_T)
+
+qse_uint128_t qse_ntoh128 (qse_uint128_t x)
+{
+#if defined(QSE_ENDIAN_BIG)
+ return x;
+#elif defined(QSE_ENDIAN_LITTLE)
+ qse_uint8_t* c = (qse_uint8_t*)&x;
+ return (qse_uint128_t)(
+ ((qse_uint128_t)c[0] << 120) |
+ ((qse_uint128_t)c[1] << 112) |
+ ((qse_uint128_t)c[2] << 104) |
+ ((qse_uint128_t)c[3] << 96) |
+ ((qse_uint128_t)c[4] << 88) |
+ ((qse_uint128_t)c[5] << 80) |
+ ((qse_uint128_t)c[6] << 72) |
+ ((qse_uint128_t)c[7] << 64) |
+ ((qse_uint128_t)c[8] << 56) |
+ ((qse_uint128_t)c[9] << 48) |
+ ((qse_uint128_t)c[10] << 40) |
+ ((qse_uint128_t)c[11] << 32) |
+ ((qse_uint128_t)c[12] << 24) |
+ ((qse_uint128_t)c[13] << 16) |
+ ((qse_uint128_t)c[14] << 8) |
+ ((qse_uint128_t)c[15] << 0));
+#else
+# error Unknown endian
+#endif
+}
+
+qse_uint128_t qse_hton128 (qse_uint128_t x)
+{
+#if defined(QSE_ENDIAN_BIG)
+ return x;
+#elif defined(QSE_ENDIAN_LITTLE)
+ qse_uint8_t* c = (qse_uint8_t*)&x;
+ return (qse_uint128_t)(
+ ((qse_uint128_t)c[0] << 120) |
+ ((qse_uint128_t)c[1] << 112) |
+ ((qse_uint128_t)c[2] << 104) |
+ ((qse_uint128_t)c[3] << 96) |
+ ((qse_uint128_t)c[4] << 88) |
+ ((qse_uint128_t)c[5] << 80) |
+ ((qse_uint128_t)c[6] << 72) |
+ ((qse_uint128_t)c[7] << 64) |
+ ((qse_uint128_t)c[8] << 56) |
+ ((qse_uint128_t)c[9] << 48) |
+ ((qse_uint128_t)c[10] << 40) |
+ ((qse_uint128_t)c[11] << 32) |
+ ((qse_uint128_t)c[12] << 24) |
+ ((qse_uint128_t)c[13] << 16) |
+ ((qse_uint128_t)c[14] << 8) |
+ ((qse_uint128_t)c[15] << 0));
+#else
+# error Unknown endian
+#endif
+}
+
+#endif
+
+/* --------------------------------------------------------------- */
diff --git a/qse/lib/cmn/ipad.c b/qse/lib/cmn/ipad.c
new file mode 100644
index 00000000..abd7c464
--- /dev/null
+++ b/qse/lib/cmn/ipad.c
@@ -0,0 +1,573 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2011 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+/* Copyright (c) 1996-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include
+
+#if 0
+const qse_ipad4_t qse_ipad4_any =
+{
+ 0 /* 0.0.0.0 */
+};
+
+const qse_ipad4_t qse_ipad4_loopback =
+{
+#if defined(QSE_ENDIAN_BIG)
+ 0x7F000001u /* 127.0.0.1 */
+#elif defined(QSE_ENDIAN_LITTLE)
+ 0x0100007Fu
+#else
+# error Unknown endian
+#endif
+};
+
+const qse_ipad6_t qse_ipad6_any =
+{
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* :: */
+};
+
+const qse_ipad6_t qse_ipad6_loopback =
+{
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } /* ::1 */
+};
+#endif
+
+#if 0
+int qse_strtoipad4 (const qse_char_t* str, qse_ipad4_t* ipad)
+{
+ qse_char_t c;
+ int dots = 0, digits = 0;
+ qse_uint32_t acc = 0, addr = 0;
+
+ do
+ {
+ c = *str;
+
+ if (c == QSE_T('\0'))
+ {
+ if (dots < 3 || digits == 0) return -1;
+ addr = (addr << 8) | acc;
+ break;
+ }
+ else if (c >= QSE_T('0') && c <= QSE_T('9'))
+ {
+ if (digits > 0 && acc == 0) return -1;
+ acc = acc * 10 + (c - QSE_T('0'));
+ if (acc > 255) return -1;
+ digits++;
+ }
+ else if (c == QSE_T('.'))
+ {
+ if (dots >= 3 || digits == 0) return -1;
+ addr = (addr << 8) | acc;
+ dots++; acc = 0; digits = 0;
+ }
+ else return -1;
+
+ str++;
+ }
+ while (1);
+
+ if (ipad != QSE_NULL) ipad->value = qse_hton32(addr);
+ return 0;
+}
+
+int qse_strxtoipad4 (
+ const qse_char_t* str, qse_size_t len, qse_ipad4_t* ipad)
+{
+ qse_char_t c;
+ int dots = 0, digits = 0;
+ qse_uint32_t acc = 0, addr = 0;
+ const qse_char_t* end = str + len;
+
+ do
+ {
+ if (str >= end)
+ {
+ if (dots < 3 || digits == 0) return -1;
+ addr = (addr << 8) | acc;
+ break;
+ }
+
+ c = *str;
+
+ if (c >= QSE_T('0') && c <= QSE_T('9'))
+ {
+ if (digits > 0 && acc == 0) return -1;
+ acc = acc * 10 + (c - QSE_T('0'));
+ if (acc > 255) return -1;
+ digits++;
+ }
+ else if (c == QSE_T('.'))
+ {
+ if (dots >= 3 || digits == 0) return -1;
+ addr = (addr << 8) | acc;
+ dots++; acc = 0; digits = 0;
+ }
+ else return -1;
+
+ str++;
+ }
+ while (1);
+
+ if (ipad != QSE_NULL) ipad->value = qse_hton32(addr);
+ return 0;
+}
+
+#define __BTOA(b,p,end) \
+ do { \
+ qse_char_t* sp = p; \
+ do { \
+ if (p >= end) { \
+ if (p == sp) break; \
+ if (p - sp > 1) p[-2] = p[-1]; \
+ p[-1] = (b % 10) + QSE_T('0'); \
+ } \
+ else *p++ = (b % 10) + QSE_T('0'); \
+ b /= 10; \
+ } while (b > 0); \
+ if (p - sp > 1) { \
+ qse_char_t t = sp[0]; \
+ sp[0] = p[-1]; \
+ p[-1] = t; \
+ } \
+ } while (0);
+
+#define __ADDDOT(p, end) \
+ do { \
+ if (p >= end) break; \
+ *p++ = QSE_T('.'); \
+ } while (0)
+
+qse_size_t qse_ipad4tostrx (
+ const qse_ipad4_t* ipad, qse_char_t* buf, qse_size_t size)
+{
+ qse_byte_t b;
+ qse_char_t* p, * end;
+ qse_uint32_t ip;
+
+ if (size <= 0) return 0;
+
+ ip = ipad->value;
+
+ p = buf;
+ end = buf + size - 1;
+
+#if defined(QSE_ENDIAN_BIG)
+ b = (ip >> 24) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end);
+ b = (ip >> 16) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end);
+ b = (ip >> 8) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end);
+ b = (ip >> 0) & 0xFF; __BTOA (b, p, end);
+#elif defined(QSE_ENDIAN_LITTLE)
+ b = (ip >> 0) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end);
+ b = (ip >> 8) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end);
+ b = (ip >> 16) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end);
+ b = (ip >> 24) & 0xFF; __BTOA (b, p, end);
+#else
+# error Unknown Endian
+#endif
+
+ *p = QSE_T('\0');
+ return p - buf;
+}
+
+int qse_strtoipad6 (const qse_char_t* src, qse_ipad6_t* ipad)
+{
+#if 0
+ static const qse_char_t xdigits_l[] = QSE_T("0123456789abcdef"),
+ xdigits_u[] = QSE_T("0123456789ABCDEF");
+ const qse_char_t* xdigits;
+#endif
+
+ qse_ipad6_t tmp;
+ qse_byte_t* tp, * endp, * colonp;
+ const qse_char_t* curtok;
+ qse_char_t ch;
+ int saw_xdigit;
+ unsigned int val;
+
+ qse_memset (&tmp, 0, QSE_SIZEOF(tmp));
+ tp = &tmp.value[0];
+ endp = &tmp.value[QSE_COUNTOF(tmp.value)];
+ colonp = QSE_NULL;
+
+ /* Leading :: requires some special handling. */
+ if (*src == QSE_T(':'))
+ {
+ if (*++src != QSE_T(':')) return -1;
+ }
+
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != QSE_T('\0'))
+ {
+ #if 0
+ const char *pch;
+ if ((pch = qse_strchr((xdigits = xdigits_l), ch)) == QSE_NULL)
+ pch = qse_strchr((xdigits = xdigits_u), ch);
+ if (pch != QSE_NULL)
+ {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff) return -1;
+ saw_xdigit = 1;
+ continue;
+ }
+ #endif
+ int v1;
+ if (ch >= QSE_T('0') && ch <= QSE_T('9'))
+ v1 = ch - QSE_T('0');
+ else if (ch >= QSE_T('A') && ch <= QSE_T('F'))
+ v1 = ch - QSE_T('A') + 10;
+ else if (ch >= QSE_T('a') && ch <= QSE_T('f'))
+ v1 = ch - QSE_T('a') + 10;
+ else v1 = -1;
+ if (v1 >= 0)
+ {
+ val <<= 4;
+ val |= v1;
+ if (val > 0xffff) return -1;
+ saw_xdigit = 1;
+ continue;
+ }
+
+ if (ch == QSE_T(':'))
+ {
+ curtok = src;
+ if (!saw_xdigit)
+ {
+ if (colonp) return -1;
+ colonp = tp;
+ continue;
+ }
+ else if (*src == QSE_T('\0'))
+ {
+ /* a colon can't be the last character */
+ return -1;
+ }
+
+ if (tp + QSE_SIZEOF(qse_uint16_t) > endp) return -1;
+ *tp++ = (qse_byte_t) (val >> 8) & 0xff;
+ *tp++ = (qse_byte_t) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ #if 0
+ if (ch == QSE_T('.') && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0)
+ {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ #endif
+ if (ch == QSE_T('.') && ((tp + QSE_SIZEOF(qse_ipad4_t)) <= endp) &&
+ qse_strtoipad4(curtok, (qse_ipad4_t*)tp) == 0)
+ {
+ tp += QSE_SIZEOF(qse_ipad4_t);
+ saw_xdigit = 0;
+ break;
+ }
+
+ return -1;
+ }
+
+ if (saw_xdigit)
+ {
+ if (tp + QSE_SIZEOF(qse_uint16_t) > endp) return -1;
+ *tp++ = (qse_byte_t) (val >> 8) & 0xff;
+ *tp++ = (qse_byte_t) val & 0xff;
+ }
+ if (colonp != QSE_NULL)
+ {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ qse_size_t n = tp - colonp;
+ qse_size_t i;
+
+ for (i = 1; i <= n; i++)
+ {
+ endp[-i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+
+ if (tp != endp) return -1;
+
+ *ipad = tmp;
+ return 0;
+}
+
+int qse_strxtoipad6 (const qse_char_t* src, qse_size_t len, qse_ipad6_t* ipad)
+{
+ qse_ipad6_t tmp;
+ qse_byte_t* tp, * endp, * colonp;
+ const qse_char_t* curtok;
+ qse_char_t ch;
+ int saw_xdigit;
+ unsigned int val;
+ const qse_char_t* src_end;
+
+ src_end = src + len;
+
+ qse_memset (&tmp, 0, QSE_SIZEOF(tmp));
+ tp = &tmp.value[0];
+ endp = &tmp.value[QSE_COUNTOF(tmp.value)];
+ colonp = QSE_NULL;
+
+ /* Leading :: requires some special handling. */
+ if (src < src_end && *src == QSE_T(':'))
+ {
+ src++;
+ if (src >= src_end || *src != QSE_T(':')) return -1;
+ }
+
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+
+ while (src < src_end)
+ {
+ int v1;
+
+ ch = *src++;
+
+ if (ch >= QSE_T('0') && ch <= QSE_T('9'))
+ v1 = ch - QSE_T('0');
+ else if (ch >= QSE_T('A') && ch <= QSE_T('F'))
+ v1 = ch - QSE_T('A') + 10;
+ else if (ch >= QSE_T('a') && ch <= QSE_T('f'))
+ v1 = ch - QSE_T('a') + 10;
+ else v1 = -1;
+ if (v1 >= 0)
+ {
+ val <<= 4;
+ val |= v1;
+ if (val > 0xffff) return -1;
+ saw_xdigit = 1;
+ continue;
+ }
+
+ if (ch == QSE_T(':'))
+ {
+ 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++ = (qse_byte_t) (val >> 8) & 0xff;
+ *tp++ = (qse_byte_t) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+
+ if (ch == QSE_T('.') && ((tp + QSE_SIZEOF(qse_ipad4_t)) <= endp) &&
+ qse_strxtoipad4(curtok, src_end - curtok, (qse_ipad4_t*)tp) == 0)
+ {
+ tp += QSE_SIZEOF(qse_ipad4_t);
+ saw_xdigit = 0;
+ break;
+ }
+
+ return -1;
+ }
+
+ if (saw_xdigit)
+ {
+ if (tp + QSE_SIZEOF(qse_uint16_t) > endp) return -1;
+ *tp++ = (qse_byte_t) (val >> 8) & 0xff;
+ *tp++ = (qse_byte_t) val & 0xff;
+ }
+ if (colonp != QSE_NULL)
+ {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ qse_size_t n = tp - colonp;
+ qse_size_t i;
+
+ for (i = 1; i <= n; i++)
+ {
+ endp[-i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+
+ if (tp != endp) return -1;
+
+ *ipad = tmp;
+ return 0;
+}
+
+qse_size_t qse_ipad6tostrx (
+ const qse_ipad6_t* ipad, qse_char_t* buf, qse_size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+
+#define IP6ADDR_NWORDS (QSE_SIZEOF(ipad->value) / QSE_SIZEOF(qse_uint16_t))
+
+ qse_char_t tmp[QSE_COUNTOF(QSE_T("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"))], *tp;
+ struct { int base, len; } best, cur;
+ qse_uint16_t words[IP6ADDR_NWORDS];
+ int i;
+
+ if (size <= 0) return 0;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ qse_memset (words, 0, QSE_SIZEOF(words));
+ for (i = 0; i < QSE_SIZEOF(ipad->value); i++)
+ words[i / 2] |= (ipad->value[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ cur.base = -1;
+
+ for (i = 0; i < IP6ADDR_NWORDS; i++)
+ {
+ if (words[i] == 0)
+ {
+ if (cur.base == -1)
+ {
+ cur.base = i;
+ cur.len = 1;
+ }
+ else
+ {
+ cur.len++;
+ }
+ }
+ else
+ {
+ if (cur.base != -1)
+ {
+ if (best.base == -1 || cur.len > best.len) best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1)
+ {
+ if (best.base == -1 || cur.len > best.len) best = cur;
+ }
+ if (best.base != -1 && best.len < 2) best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < IP6ADDR_NWORDS; i++)
+ {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len))
+ {
+ if (i == best.base) *tp++ = QSE_T(':');
+ continue;
+ }
+
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0) *tp++ = QSE_T(':');
+
+ /* Is this address an encapsulated IPv4? ipv4-compatible or ipv4-mapped */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
+ {
+ qse_ipad4_t ipad4;
+ qse_memcpy (&ipad4.value, ipad->value+12, QSE_SIZEOF(ipad4.value));
+ tp += qse_ipad4tostrx (&ipad4, tp, QSE_SIZEOF(tmp) - (tp - tmp));
+ break;
+ }
+
+ tp += qse_uint16tostr_lower (words[i], tp, QSE_SIZEOF(tmp) - (tp - tmp), 16, QSE_T('\0'));
+ }
+
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 &&
+ (best.base + best.len) == IP6ADDR_NWORDS) *tp++ = QSE_T(':');
+ *tp++ = QSE_T('\0');
+
+ return qse_strxcpy (buf, size, tmp);
+
+#undef IP6ADDR_NWORDS
+}
+
+int qse_strtoipad (const qse_char_t* str, qse_ipad_t* ipad)
+{
+ if (qse_strtoipad4 (str, &ipad->u.ip4) <= -1)
+ {
+ if (qse_strtoipad6 (str, &ipad->u.ip6) <= -1) return -1;
+ ipad->type = QSE_IPAD_IP6;
+ }
+ else ipad->type = QSE_IPAD_IP4;
+
+ return 0;
+}
+
+int qse_strxtoipad (const qse_char_t* str, qse_size_t len, qse_ipad_t* ipad)
+{
+ if (qse_strxtoipad4 (str, len, &ipad->u.ip4) <= -1)
+ {
+ if (qse_strxtoipad6 (str, len, &ipad->u.ip6) <= -1) return -1;
+ ipad->type = QSE_IPAD_IP6;
+ }
+ else ipad->type = QSE_IPAD_IP4;
+
+ return 0;
+}
+#endif
diff --git a/qse/lib/cmn/mbwc.c b/qse/lib/cmn/mbwc.c
index 3a176d64..07360da3 100644
--- a/qse/lib/cmn/mbwc.c
+++ b/qse/lib/cmn/mbwc.c
@@ -47,6 +47,7 @@ qse_cmgr_t* qse_slmbcmgr = &builtin_cmgr[0];
qse_cmgr_t* qse_utf8cmgr = &builtin_cmgr[1];
static qse_cmgr_t* dfl_cmgr = &builtin_cmgr[0];
+static qse_cmgr_finder_t cmgr_finder = QSE_NULL;
qse_cmgr_t* qse_getdflcmgr (void)
{
@@ -58,24 +59,34 @@ void qse_setdflcmgr (qse_cmgr_t* cmgr)
dfl_cmgr = (cmgr? cmgr: &builtin_cmgr[0]);
}
-/* TODO:
-qse_addcmgr (const qse_char_t* name, qse_cmgr_t* cmgr);
-qse_delcmgr (const qse_char_t* name);
-*/
-
-qse_cmgr_t* qse_getcmgrbyname (const qse_char_t* name)
+qse_cmgr_t* qse_findcmgr (const qse_char_t* name)
{
if (name)
{
- /* TODO: binary search */
+ if (cmgr_finder)
+ {
+ qse_cmgr_t* cmgr;
+ cmgr = cmgr_finder (name);
+ if (cmgr) return cmgr;
+ }
+
if (qse_strcmp(name, QSE_T("")) == 0) return dfl_cmgr;
if (qse_strcmp(name, QSE_T("utf8")) == 0) return qse_utf8cmgr;
if (qse_strcmp(name, QSE_T("slmb")) == 0) return qse_slmbcmgr;
- /* TODO: add more - handle those added with qse_addcmgr() */
}
return QSE_NULL;
}
+void qse_setcmgrfinder (qse_cmgr_finder_t finder)
+{
+ cmgr_finder = finder;
+}
+
+qse_cmgr_finder_t qse_getcmgrfinder (void)
+{
+ return cmgr_finder;
+}
+
/* string conversion function using default character conversion manager */
int qse_mbstowcs (
diff --git a/qse/lib/cmn/nwad.c b/qse/lib/cmn/nwad.c
new file mode 100644
index 00000000..55684eef
--- /dev/null
+++ b/qse/lib/cmn/nwad.c
@@ -0,0 +1,37 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2011 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+/* Copyright (c) 1996-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include
diff --git a/qse/lib/cmn/pio.c b/qse/lib/cmn/pio.c
index 026abd84..8eb96d34 100644
--- a/qse/lib/cmn/pio.c
+++ b/qse/lib/cmn/pio.c
@@ -49,7 +49,6 @@ static qse_ssize_t pio_output (
#if defined(_WIN32)
static qse_pio_errnum_t syserr_to_errnum (DWORD e)
{
-
switch (e)
{
case ERROR_INVALID_PARAMETER:
@@ -573,13 +572,18 @@ int qse_pio_init (
if (flags & QSE_PIO_WRITEIN)
{
/* child reads, parent writes */
- if (CreatePipe (
- &handle[0], &handle[1],
- &secattr, 0) == FALSE) goto oops;
+ if (CreatePipe (&handle[0], &handle[1], &secattr, 0) == FALSE)
+ {
+ pio->errnum = syserr_to_errnum (GetLastError());
+ goto oops;
+ }
/* don't inherit write handle */
- if (SetHandleInformation (
- handle[1], HANDLE_FLAG_INHERIT, 0) == FALSE) goto oops;
+ if (SetHandleInformation (handle[1], HANDLE_FLAG_INHERIT, 0) == FALSE)
+ {
+ pio->errnum = syserr_to_errnum (GetLastError());
+ goto oops;
+ }
minidx = 0; maxidx = 1;
}
@@ -587,13 +591,18 @@ int qse_pio_init (
if (flags & QSE_PIO_READOUT)
{
/* child writes, parent reads */
- if (CreatePipe (
- &handle[2], &handle[3],
- &secattr, 0) == FALSE) goto oops;
+ if (CreatePipe (&handle[2], &handle[3], &secattr, 0) == FALSE)
+ {
+ pio->errnum = syserr_to_errnum (GetLastError());
+ goto oops;
+ }
/* don't inherit read handle */
- if (SetHandleInformation (
- handle[2], HANDLE_FLAG_INHERIT, 0) == FALSE) goto oops;
+ if (SetHandleInformation (handle[2], HANDLE_FLAG_INHERIT, 0) == FALSE)
+ {
+ pio->errnum = syserr_to_errnum (GetLastError());
+ goto oops;
+ }
if (minidx == -1) minidx = 2;
maxidx = 3;
@@ -602,13 +611,18 @@ int qse_pio_init (
if (flags & QSE_PIO_READERR)
{
/* child writes, parent reads */
- if (CreatePipe (
- &handle[4], &handle[5],
- &secattr, 0) == FALSE) goto oops;
+ if (CreatePipe (&handle[4], &handle[5], &secattr, 0) == FALSE)
+ {
+ pio->errnum = syserr_to_errnum (GetLastError());
+ goto oops;
+ }
/* don't inherit read handle */
- if (SetHandleInformation (
- handle[4], HANDLE_FLAG_INHERIT, 0) == FALSE) goto oops;
+ if (SetHandleInformation (handle[4], HANDLE_FLAG_INHERIT, 0) == FALSE)
+ {
+ pio->errnum = syserr_to_errnum (GetLastError());
+ goto oops;
+ }
if (minidx == -1) minidx = 4;
maxidx = 5;
@@ -629,7 +643,11 @@ int qse_pio_init (
FILE_SHARE_READ | FILE_SHARE_WRITE,
&secattr, OPEN_EXISTING, 0, NULL
);
- if (windevnul == INVALID_HANDLE_VALUE) goto oops;
+ if (windevnul == INVALID_HANDLE_VALUE)
+ {
+ pio->errnum = syserr_to_errnum (GetLastError());
+ goto oops;
+ }
}
QSE_MEMSET (&procinfo, 0, QSE_SIZEOF(procinfo));
@@ -743,25 +761,7 @@ int qse_pio_init (
QSE_MMGR_FREE (mmgr, dupcmd);
if (x == FALSE)
- {
- DWORD e = GetLastError ();
- switch (e)
- {
- case ERROR_ACCESS_DENIED:
- pio->errnum = QSE_PIO_EACCES;
- break;
-
- case ERROR_FILE_NOT_FOUND:
- case ERROR_PATH_NOT_FOUND:
- pio->errnum = QSE_PIO_ENOENT;
- break;
-
- case ERROR_NOT_ENOUGH_MEMORY:
- case ERROR_OUTOFMEMORY:
- pio->errnum = QSE_PIO_ENOMEM;
- break;
- }
- }
+ pio->errnum = syserr_to_errnum (GetLastError());
}
if (windevnul != INVALID_HANDLE_VALUE)
@@ -792,18 +792,32 @@ int qse_pio_init (
#elif defined(__OS2__)
#define DOS_DUP_HANDLE(x,y) QSE_BLOCK ( \
- if (DosDupHandle(x,y) != NO_ERROR) goto oops; \
+ rc = DosDupHandle(x,y); \
+ if (rc != NO_ERROR) \
+ { \
+ pio->errnum = syserr_to_errnum (rc); \
+ goto oops; \
+ } \
)
if (flags & QSE_PIO_WRITEIN)
{
/* child reads, parent writes */
- if (DosCreatePipe (
- &handle[0], &handle[1], pipe_size) != NO_ERROR) goto oops;
+ rc = DosCreatePipe (&handle[0], &handle[1], pipe_size);
+ if (rc != NO_ERROR)
+ {
+ pio->errnum = syserr_to_errnum (rc);
+ goto oops;
+ }
/* the parent writes to handle[1] and the child reads from
* handle[0] inherited. set the flag not to inherit handle[1]. */
- if (DosSetFHState (handle[1], OPEN_FLAGS_NOINHERIT) != NO_ERROR) goto oops;
+ rc = DosSetFHState (handle[1], OPEN_FLAGS_NOINHERIT);
+ if (rc != NO_ERROR)
+ {
+ pio->errnum = syserr_to_errnum (rc);
+ goto oops;
+ }
/* Need to do somthing like this to set the flag instead?
ULONG state;
@@ -816,12 +830,21 @@ int qse_pio_init (
if (flags & QSE_PIO_READOUT)
{
/* child writes, parent reads */
- if (DosCreatePipe (
- &handle[2], &handle[3], pipe_size) != NO_ERROR) goto oops;
+ rc = DosCreatePipe (&handle[2], &handle[3], pipe_size);
+ if (rc != NO_ERROR)
+ {
+ pio->errnum = syserr_to_errnum (rc);
+ goto oops;
+ }
/* the parent reads from handle[2] and the child writes to
* handle[3] inherited. set the flag not to inherit handle[2] */
- if (DosSetFHState (handle[2], OPEN_FLAGS_NOINHERIT) != NO_ERROR) goto oops;
+ rc = DosSetFHState (handle[2], OPEN_FLAGS_NOINHERIT);
+ if (rc != NO_ERROR)
+ {
+ pio->errnum = syserr_to_errnum (rc);
+ goto oops;
+ }
if (minidx == -1) minidx = 2;
maxidx = 3;
@@ -830,12 +853,21 @@ int qse_pio_init (
if (flags & QSE_PIO_READERR)
{
/* child writes, parent reads */
- if (DosCreatePipe (
- &handle[4], &handle[5], pipe_size) != NO_ERROR) goto oops;
+ rc = DosCreatePipe (&handle[4], &handle[5], pipe_size);
+ if (rc != NO_ERROR)
+ {
+ pio->errnum = syserr_to_errnum (rc);
+ goto oops;
+ }
/* the parent reads from handle[4] and the child writes to
* handle[5] inherited. set the flag not to inherit handle[4] */
- if (DosSetFHState (handle[4], OPEN_FLAGS_NOINHERIT) != NO_ERROR) goto oops;
+ rc = DosSetFHState (handle[4], OPEN_FLAGS_NOINHERIT);
+ if (rc != NO_ERROR)
+ {
+ pio->errnum = syserr_to_errnum (rc);
+ goto oops;
+ }
if (minidx == -1) minidx = 4;
maxidx = 5;
@@ -867,22 +899,32 @@ int qse_pio_init (
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE,
0L
);
- if (rc != NO_ERROR) goto oops;
+ if (rc != NO_ERROR)
+ {
+ pio->errnum = syserr_to_errnum (rc);
+ goto oops;
+ }
}
/* duplicate the current stdin/out/err to old_in/out/err as a new handle */
- if (DosDupHandle (std_in, &old_in) != NO_ERROR)
+ rc = DosDupHandle (std_in, &old_in);
+ if (rc != NO_ERROR)
{
+ pio->errnum = syserr_to_errnum (rc);
goto oops;
}
- if (DosDupHandle (std_out, &old_out) != NO_ERROR)
+ rc = DosDupHandle (std_out, &old_out);
+ if (rc != NO_ERROR)
{
+ pio->errnum = syserr_to_errnum (rc);
DosClose (old_in); old_in = QSE_PIO_HND_NIL;
goto oops;
}
- if (DosDupHandle (std_err, &old_err) != NO_ERROR)
+ rc = DosDupHandle (std_err, &old_err);
+ if (rc != NO_ERROR)
{
+ pio->errnum = syserr_to_errnum (rc);
DosClose (old_out); old_out = QSE_PIO_HND_NIL;
DosClose (old_in); old_in = QSE_PIO_HND_NIL;
goto oops;
@@ -1060,8 +1102,6 @@ int qse_pio_init (
cmd_file
);
-/* TODO: translate error code ... */
-
QSE_MMGR_FREE (mmgr, cmd_line);
cmd_line = QSE_NULL;
@@ -1074,7 +1114,11 @@ int qse_pio_init (
DosDupHandle (old_err, &std_err);
DosClose (old_err); old_err = QSE_PIO_HND_NIL;
- if (rc != NO_ERROR) goto oops;
+ if (rc != NO_ERROR)
+ {
+ pio->errnum = syserr_to_errnum (rc);
+ goto oops;
+ }
pio->child = child_rc.codeTerminate;
#elif defined(__DOS__)
@@ -1085,20 +1129,32 @@ int qse_pio_init (
#elif defined(HAVE_POSIX_SPAWN)
if (flags & QSE_PIO_WRITEIN)
{
- if (QSE_PIPE(&handle[0]) <= -1) goto oops;
+ if (QSE_PIPE(&handle[0]) <= -1)
+ {
+ pio->errnum = syserr_to_errnum (errno);
+ goto oops;
+ }
minidx = 0; maxidx = 1;
}
if (flags & QSE_PIO_READOUT)
{
- if (QSE_PIPE(&handle[2]) <= -1) goto oops;
+ if (QSE_PIPE(&handle[2]) <= -1)
+ {
+ pio->errnum = syserr_to_errnum (errno);
+ goto oops;
+ }
if (minidx == -1) minidx = 2;
maxidx = 3;
}
if (flags & QSE_PIO_READERR)
{
- if (QSE_PIPE(&handle[4]) <= -1) goto oops;
+ if (QSE_PIPE(&handle[4]) <= -1)
+ {
+ pio->errnum = syserr_to_errnum (errno);
+ goto oops;
+ }
if (minidx == -1) minidx = 4;
maxidx = 5;
}
diff --git a/qse/lib/net/httpd_task.c b/qse/lib/net/httpd_task.c
index e1e4e2fd..c22cad76 100644
--- a/qse/lib/net/httpd_task.c
+++ b/qse/lib/net/httpd_task.c
@@ -411,94 +411,21 @@ qse_httpd_task_t* qse_httpd_entaskcontinue (
/*------------------------------------------------------------------------*/
-#if 0
-typedef struct task_file_t task_file_t;
-struct task_file_t
+qse_httpd_task_t* qse_httpd_entaskauth (
+ qse_httpd_t* httpd, qse_httpd_client_t* client,
+ const qse_httpd_task_t* task, const qse_mchar_t* realm, qse_htre_t* req)
{
- qse_ubi_t handle;
- qse_foff_t left;
- qse_foff_t offset;
-};
-
-static int task_init_file (
- qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
-{
- task_file_t* xtn = qse_httpd_gettaskxtn (httpd, task);
- QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
- task->ctx = xtn;
- return 0;
-}
-
-static void task_fini_file (
- qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
-{
- task_file_t* ctx = (task_file_t*)task->ctx;
-qse_printf (QSE_T("closing file %d\n"), ctx->handle.i);
- QSE_CLOSE (ctx->handle.i);
-}
-
-static int task_main_file (
- qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
-{
- qse_ssize_t n;
- qse_size_t count;
- task_file_t* ctx = (task_file_t*)task->ctx;
-
- count = MAX_SEND_SIZE;
- if (count >= ctx->left) count = ctx->left;
-
-/* TODO: more adjustment needed for OS with different sendfile semantics... */
- n = httpd->cbs->client.sendfile (
- httpd, client, ctx->handle, &ctx->offset, count);
- if (n <= -1)
- {
-// HANDLE EGAIN specially???
- return -1; /* TODO: any logging */
- }
-
- if (n == 0 && count > 0)
- {
- /* The file could be truncated when this condition is set.
- * The content-length sent in the header can't be fulfilled.
- * So let's return an error here so that the main loop abort
- * the connection. */
-/* TODO: any logging....??? */
- return -1;
- }
-
- ctx->left -= n;
- if (ctx->left <= 0) return 0;
-
- return 1; /* more work to do */
-}
-
-qse_httpd_task_t* qse_httpd_entaskfile (
- qse_httpd_t* httpd,
- qse_httpd_client_t* client,
- const qse_httpd_task_t* pred,
- qse_ubi_t handle,
- qse_foff_t offset,
- qse_foff_t size)
-{
- qse_httpd_task_t task;
- task_file_t data;
-
- QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
- data.handle = handle;
- data.offset = offset;
- data.left = size;
-
- QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
- task.init = task_init_file;
- task.main = task_main_file;
- task.fini = task_fini_file;
- task.ctx = &data;
-
-qse_printf (QSE_T("Debug: entasking file (%d)\n"), client->handle.i);
- return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data));
+ const qse_http_version_t* version = qse_htre_getversion(req);
+/* TODO: */
+ return qse_httpd_entaskformat (
+ httpd, client, task,
+ QSE_MT("HTTP/%d.%d 401 Unauthorized\r\nContent-Length: 0\r\nWWW-Authenticate: Digest realm=\"%s\", qop=\"auth\", nonce=\"%s\""),
+ version->major, version->minor);
}
/*------------------------------------------------------------------------*/
+
+#if 0
typedef struct task_dir_t task_dir_t;
struct task_dir_t
{
@@ -867,161 +794,6 @@ static int task_init_path (
return 0;
}
-static QSE_INLINE int task_main_path_file (
- qse_httpd_t* httpd, qse_httpd_client_t* client,
- qse_httpd_task_t* task, qse_foff_t filesize)
-{
- task_path_t* data = (task_path_t*)task->ctx;
- qse_httpd_task_t* x = task;
- qse_ubi_t handle;
- int oflags;
-
-/* TODO: if you should deal with files on a network-mounted drive,
- setting a trigger or non-blocking I/O are needed. */
-
- /* when it comes to the file size, using fstat after opening
- * can be more accurate. but this function uses information
- * set into the task context before the call to this function */
-
-qse_printf (QSE_T("opening file %hs\n"), data->name);
-
- oflags = O_RDONLY;
-#if defined(O_LARGEFILE)
- oflags |= O_LARGEFILE;
-#endif
- handle.i = QSE_OPEN (data->name, oflags, 0);
- if (handle.i <= -1)
- {
- x = entask_error (
- httpd, client, x, 404, &data->version, data->keepalive);
- goto no_file_send;
- }
- oflags = QSE_FCNTL (handle.i, F_GETFD, 0);
- if (oflags >= 0)
- QSE_FCNTL (handle.i, F_SETFD, oflags | FD_CLOEXEC);
-
- if (data->range.type != QSE_HTTP_RANGE_NONE)
- {
- const qse_mchar_t* mime_type = QSE_NULL;
-
- if (data->range.type == QSE_HTTP_RANGE_SUFFIX)
- {
- if (data->range.to > filesize) data->range.to = filesize;
- data->range.from = filesize - data->range.to;
- data->range.to = data->range.to + data->range.from;
- if (filesize > 0) data->range.to--;
- }
-
- if (data->range.from >= filesize)
- {
- x = entask_error (
- httpd, client, x, 416, &data->version, data->keepalive);
- goto no_file_send;
- }
-
- if (data->range.to >= filesize) data->range.to = filesize - 1;
-
- if (httpd->cbs->getmimetype)
- {
- httpd->errnum = QSE_HTTPD_ENOERR;
- mime_type = httpd->cbs->getmimetype (httpd, data->name);
- /*TODO: how to handle an error... */
- }
-
-#if (QSE_SIZEOF_LONG_LONG > 0)
- x = qse_httpd_entaskformat (
- httpd, client, x,
- QSE_MT("HTTP/%d.%d 206 Partial Content\r\nConnection: %s\r\n%s%s%sContent-Length: %llu\r\nContent-Range: bytes %llu-%llu/%llu\r\n\r\n"),
- data->version.major,
- data->version.minor,
- (data->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
- (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
- (mime_type? mime_type: QSE_MT("")),
- (mime_type? QSE_MT("\r\n"): QSE_MT("")),
- (unsigned long long)(data->range.to - data->range.from + 1),
- (unsigned long long)data->range.from,
- (unsigned long long)data->range.to,
- (unsigned long long)filesize
- );
-#else
- x = qse_httpd_entaskformat (
- httpd, client, x,
- QSE_MT("HTTP/%d.%d 206 Partial Content\r\nConnection: %s\r\n%s%s%sContent-Length: %lu\r\nContent-Range: bytes %lu-%lu/%lu\r\n\r\n"),
- data->version.major,
- data->version.minor,
- (data->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
- (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
- (mime_type? mime_type: QSE_MT("")),
- (mime_type? QSE_MT("\r\n"): QSE_MT("")),
- (unsigned long)(data->range.to - data->range.from + 1),
- (unsigned long)data->range.from,
- (unsigned long)data->range.to,
- (unsigned long)filesize
- );
-#endif
- if (x)
- {
- x = qse_httpd_entaskfile (
- httpd, client, x,
- handle,
- data->range.from,
- (data->range.to - data->range.from + 1)
- );
- }
- }
- else
- {
-/* TODO: int64 format.... don't hard code it llu */
- const qse_mchar_t* mime_type = QSE_NULL;
-
- if (httpd->cbs->getmimetype)
- {
- httpd->errnum = QSE_HTTPD_ENOERR;
- mime_type = httpd->cbs->getmimetype (httpd, data->name);
-/*TODO: how to handle an error... */
- }
-
- /* wget 1.8.2 set 'Connection: keep-alive' in the http 1.0 header.
- * if the reply doesn't contain 'Connection: keep-alive', it didn't
- * close connection.*/
-#if (QSE_SIZEOF_LONG_LONG > 0)
- x = qse_httpd_entaskformat (
- httpd, client, x,
- QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\n%s%s%sContent-Length: %llu\r\n\r\n"),
- data->version.major, data->version.minor,
- (data->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
- (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
- (mime_type? mime_type: QSE_MT("")),
- (mime_type? QSE_MT("\r\n"): QSE_MT("")),
- (unsigned long long)filesize
- );
-#else
- x = qse_httpd_entaskformat (
- httpd, client, x,
- QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\n%s%s%sContent-Length: %lu\r\n\r\n"),
- data->version.major,
- data->version.minor,
- (data->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
- (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
- (mime_type? mime_type: QSE_MT("")),
- (mime_type? QSE_MT("\r\n"): QSE_MT("")),
- (unsigned long)filesize
- );
-#endif
- if (x)
- {
- x = qse_httpd_entaskfile (
- httpd, client, x, handle, 0, filesize);
- }
- }
-
- return (x == QSE_NULL)? -1: 0;
-
-no_file_send:
- if (handle.i >= 0) close (handle.i);
- return (x == QSE_NULL)? -1: 0;
-}
-
static QSE_INLINE int task_main_path_dir (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
@@ -1259,8 +1031,8 @@ static QSE_INLINE int task_main_file (
task_file_t* file;
qse_httpd_task_t* x;
qse_ubi_t handle;
- qse_foff_t filesize;
int fileopen = 0;
+ qse_httpd_stat_t st;
file = (task_file_t*)task->ctx;
x = task;
@@ -1269,9 +1041,21 @@ static QSE_INLINE int task_main_file (
setting a trigger or non-blocking I/O are needed. */
qse_printf (QSE_T("opening file %hs\n"), file->path);
+
+ httpd->errnum = QSE_HTTPD_ENOERR;
+ if (httpd->cbs->file.stat (httpd, file->path, &st) <= -1)
+ {
+ int http_errnum;
+ http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
+ (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
+ x = entask_error (
+ httpd, client, x, http_errnum,
+ &file->version, file->keepalive);
+ goto no_file_send;
+ }
httpd->errnum = QSE_HTTPD_ENOERR;
- if (httpd->cbs->file.ropen (httpd, file->path, &handle, &filesize) <= -1)
+ if (httpd->cbs->file.ropen (httpd, file->path, &handle) <= -1)
{
int http_errnum;
http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
@@ -1285,31 +1069,22 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
if (file->range.type != QSE_HTTP_RANGE_NONE)
{
- const qse_mchar_t* mime_type = QSE_NULL;
-
if (file->range.type == QSE_HTTP_RANGE_SUFFIX)
{
- if (file->range.to > filesize) file->range.to = filesize;
- file->range.from = filesize - file->range.to;
+ if (file->range.to > st.size) file->range.to = st.size;
+ file->range.from = st.size - file->range.to;
file->range.to = file->range.to + file->range.from;
- if (filesize > 0) file->range.to--;
+ if (st.size > 0) file->range.to--;
}
- if (file->range.from >= filesize)
+ if (file->range.from >= st.size)
{
x = entask_error (
httpd, client, x, 416, &file->version, file->keepalive);
goto no_file_send;
}
- if (file->range.to >= filesize) file->range.to = filesize - 1;
-
- if (httpd->cbs->getmimetype)
- {
- httpd->errnum = QSE_HTTPD_ENOERR;
- mime_type = httpd->cbs->getmimetype (httpd, file->path);
- /*TODO: how to handle an error... */
- }
+ if (file->range.to >= st.size) file->range.to = st.size - 1;
#if (QSE_SIZEOF_LONG_LONG > 0)
x = qse_httpd_entaskformat (
@@ -1318,13 +1093,13 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
file->version.major,
file->version.minor,
(file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
- (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
- (mime_type? mime_type: QSE_MT("")),
- (mime_type? QSE_MT("\r\n"): QSE_MT("")),
+ (st.mime? QSE_MT("Content-Type: "): QSE_MT("")),
+ (st.mime? st.mime: QSE_MT("")),
+ (st.mime? QSE_MT("\r\n"): QSE_MT("")),
(unsigned long long)(file->range.to - file->range.from + 1),
(unsigned long long)file->range.from,
(unsigned long long)file->range.to,
- (unsigned long long)filesize
+ (unsigned long long)st.size
);
#else
x = qse_httpd_entaskformat (
@@ -1333,13 +1108,13 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
file->version.major,
file->version.minor,
(file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
- (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
- (mime_type? mime_type: QSE_MT("")),
- (mime_type? QSE_MT("\r\n"): QSE_MT("")),
+ (st.mime? QSE_MT("Content-Type: "): QSE_MT("")),
+ (st.mime? st.mime: QSE_MT("")),
+ (st.mime? QSE_MT("\r\n"): QSE_MT("")),
(unsigned long)(file->range.to - file->range.from + 1),
(unsigned long)file->range.from,
(unsigned long)file->range.to,
- (unsigned long)filesize
+ (unsigned long)st.size
);
#endif
if (x)
@@ -1355,15 +1130,6 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
else
{
/* TODO: int64 format.... don't hard code it llu */
- const qse_mchar_t* mime_type = QSE_NULL;
-
- if (httpd->cbs->getmimetype)
- {
- httpd->errnum = QSE_HTTPD_ENOERR;
- mime_type = httpd->cbs->getmimetype (httpd, file->path);
-/*TODO: how to handle an error... */
- }
-
/* wget 1.8.2 set 'Connection: keep-alive' in the http 1.0 header.
* if the reply doesn't contain 'Connection: keep-alive', it didn't
* close connection.*/
@@ -1373,10 +1139,10 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\n%s%s%sContent-Length: %llu\r\n\r\n"),
file->version.major, file->version.minor,
(file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
- (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
- (mime_type? mime_type: QSE_MT("")),
- (mime_type? QSE_MT("\r\n"): QSE_MT("")),
- (unsigned long long)filesize
+ (st.mime? QSE_MT("Content-Type: "): QSE_MT("")),
+ (st.mime? st.mime: QSE_MT("")),
+ (st.mime? QSE_MT("\r\n"): QSE_MT("")),
+ (unsigned long long)st.size
);
#else
x = qse_httpd_entaskformat (
@@ -1385,16 +1151,15 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
file->version.major,
file->version.minor,
(file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
- (mime_type? QSE_MT("Content-Type: "): QSE_MT("")),
- (mime_type? mime_type: QSE_MT("")),
- (mime_type? QSE_MT("\r\n"): QSE_MT("")),
- (unsigned long)filesize
+ (st.mime? QSE_MT("Content-Type: "): QSE_MT("")),
+ (st.mime? st.mime: QSE_MT("")),
+ (st.mime? QSE_MT("\r\n"): QSE_MT("")),
+ (unsigned long)st.size
);
#endif
if (x)
{
- x = entask_file_segment (
- httpd, client, x, handle, 0, filesize);
+ x = entask_file_segment (httpd, client, x, handle, 0, st.size);
}
}
@@ -1772,6 +1537,7 @@ qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), qse_htre_getqpathptr(req), qse_htre_getqpat
qse_env_insertmbs (env, QSE_MT("SERVER_PROTOCOL"), proto);
}
// TODO: HTTP_ headers.
+// TODO: REMOTE_USER ...
#if 0
qse_env_insertmbs (env, "SERVER_NAME",
@@ -2573,19 +2339,6 @@ static QSE_INLINE qse_httpd_task_t* entask_cgi (
qse_httpd_task_t task;
task_cgi_arg_t arg;
-#if 0
- int x;
-
-/* TODO: NEED TO CHECK IF it's a regular file and executable??
-directory may be treated as executable???
-*/
- x = httpd->cbs->path.executable (httpd, path);
- if (x == 0)
- return qse_httpd_entaskerror (httpd, client, pred, 403, req);
- else if (x <= -1)
- return qse_httpd_entaskerror (httpd, client, pred, 404, req);
-#endif
-
arg.path = path;
arg.req = req;
arg.nph = nph;
diff --git a/qse/samples/net/http01.c b/qse/samples/net/http01.c
index ac417150..79a83a64 100644
--- a/qse/samples/net/http01.c
+++ b/qse/samples/net/http01.c
@@ -5,9 +5,11 @@
#include
#include
#include
+#include
#include
#include
+#include
#if defined(_WIN32)
# include
#else
@@ -18,6 +20,8 @@
#endif
#include
+#include
+#include
// TODO: remove this and export structured needed like qse_httpd_client_t
@@ -226,22 +230,59 @@ static int mux_writable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec)
/* ------------------------------------------------------------------- */
-static int path_executable (qse_httpd_t* httpd, const qse_mchar_t* path)
+static int file_executable (qse_httpd_t* httpd, const qse_mchar_t* path)
{
if (access (path, X_OK) == -1)
return (errno == EACCES)? 0 /*no*/: -1 /*error*/;
return 1; /* yes */
}
-/* ------------------------------------------------------------------- */
+static int file_stat (
+ qse_httpd_t* httpd, const qse_mchar_t* path, qse_httpd_stat_t* hst)
+{
+ struct stat st;
+
+/* TODO: lstat? or stat? */
+ if (stat (path, &st) <= -1)
+ {
+ qse_httpd_seterrnum (httpd,
+ (errno == ENOENT? QSE_HTTPD_ENOENT:
+ errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS));
+ return -1;
+ }
+
+ /* stating for a file. it should be a regular file.
+ * i don't allow other file types. */
+ if (!S_ISREG(st.st_mode))
+ {
+ qse_httpd_seterrnum (httpd, QSE_HTTPD_EACCES);
+ return -1;
+ }
+
+ memset (hst, 0, QSE_SIZEOF(*hst));
+
+ hst->size = st.st_size;
+#if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
+ hst->mtime = QSE_SECNSEC_TO_MSEC(st.st_mtim.tv_sec,st.st_mtim.tv_nsec);
+#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
+ hst->mtime = QSE_SECNSEC_TO_MSEC(st.st_mtimespec.tv_sec,st.st_mtimespec.tv_nsec);
+#else
+ hst->mtime = st.st_mtime * QSE_MSECS_PER_SEC;
+#endif
+
+ hst->mime = qse_mbsend (path, QSE_MT(".html"))? QSE_MT("text/html"):
+ qse_mbsend (path, QSE_MT(".txt"))? QSE_MT("text/plain"):
+ qse_mbsend (path, QSE_MT(".jpg"))? QSE_MT("image/jpeg"):
+ qse_mbsend (path, QSE_MT(".mp4"))? QSE_MT("video/mp4"):
+ qse_mbsend (path, QSE_MT(".mp3"))? QSE_MT("audio/mpeg"): QSE_NULL;
+ return 0;
+}
static int file_ropen (
- qse_httpd_t* httpd, const qse_mchar_t* path,
- qse_ubi_t* handle, qse_foff_t* size)
+ qse_httpd_t* httpd, const qse_mchar_t* path, qse_ubi_t* handle)
{
int fd;
int flags;
- struct stat st;
flags = O_RDONLY;
#if defined(O_LARGEFILE)
@@ -261,25 +302,6 @@ qse_printf (QSE_T("opening file [%hs] for reading\n"), path);
flags = fcntl (fd, F_GETFD);
if (flags >= 0) fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
-/* TODO: fstat64??? */
- if (fstat (fd, &st) <= -1)
- {
- qse_httpd_seterrnum (httpd,
- (errno == ENOENT? QSE_HTTPD_ENOENT:
- errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS));
- close (fd);
- return -1;
- }
-
-/* check if it is a link. symbolic link??? */
- if (!S_ISREG(st.st_mode))
- {
- qse_httpd_seterrnum (httpd, QSE_HTTPD_EACCES);
- close (fd);
- return -1;
- }
-
- *size = (st.st_size <= 0)? 0: st.st_size;
handle->i = fd;
qse_printf (QSE_T("opened file %hs\n"), path);
return 0;
@@ -617,16 +639,6 @@ static int handle_request (
return process_request (httpd, client, req, 0);
}
-const qse_mchar_t* get_mime_type (qse_httpd_t* httpd, const qse_mchar_t* path)
-{
- if (qse_mbsend (path, QSE_MT(".html"))) return QSE_MT("text/html");
- if (qse_mbsend (path, QSE_MT(".txt"))) return QSE_MT("text/plain");
- if (qse_mbsend (path, QSE_MT(".jpg"))) return QSE_MT("image/jpeg");
- if (qse_mbsend (path, QSE_MT(".mp4"))) return QSE_MT("video/mp4");
- if (qse_mbsend (path, QSE_MT(".mp3"))) return QSE_MT("audio/mpeg");
- return QSE_NULL;
-}
-
int list_directory (qse_httpd_t* httpd, const qse_mchar_t* path)
{
return 404;
@@ -637,11 +649,10 @@ static qse_httpd_cbs_t httpd_cbs =
/* multiplexer */
{ mux_readable, mux_writable },
- /* path operation */
- { path_executable },
-
/* file operation */
- { file_ropen,
+ { file_executable,
+ file_stat,
+ file_ropen,
file_wopen,
file_close,
file_read,
@@ -659,7 +670,6 @@ static qse_httpd_cbs_t httpd_cbs =
peek_request,
handle_request,
- get_mime_type,
list_directory
};