diff --git a/qse/configure b/qse/configure
index 9dfcff8a..7c30e813 100755
--- a/qse/configure
+++ b/qse/configure
@@ -16057,7 +16057,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h
fi
-for ac_header in stddef.h wchar.h wctype.h errno.h signal.h fcntl.h
+for ac_header in stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.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"
@@ -16177,7 +16177,7 @@ _ACEOF
fi
done
-for ac_func in lseek64 stat64 fstat64 lstat64 ftruncate64
+for ac_func in lseek64 stat64 fstat64 lstat64 ftruncate64 readdir64
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/qse/configure.ac b/qse/configure.ac
index 821d6fe0..ded6543f 100644
--- a/qse/configure.ac
+++ b/qse/configure.ac
@@ -82,7 +82,7 @@ AC_SUBST(LIBM, $LIBM)
dnl check header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h])
+AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h])
AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h])
AC_CHECK_HEADERS([sys/resource.h sys/wait.h sys/syscall.h sys/sendfile.h sys/epoll.h])
AC_CHECK_HEADERS([net/if.h])
@@ -100,7 +100,7 @@ AC_CHECK_FUNCS([mbrlen mbrtowc wcrtomb])
AC_CHECK_FUNCS([mbsnrtowcs mbsrtowcs wcsnrtombs wcsrtombs])
AC_CHECK_FUNCS([wctype iswctype wctrans towctrans])
AC_CHECK_FUNCS([isblank iswblank])
-AC_CHECK_FUNCS([lseek64 stat64 fstat64 lstat64 ftruncate64])
+AC_CHECK_FUNCS([lseek64 stat64 fstat64 lstat64 ftruncate64 readdir64])
AC_CHECK_FUNCS([timegm timelocal])
AC_CHECK_FUNCS([utime utimes])
AC_CHECK_FUNCS([sysconf])
diff --git a/qse/doc/page/awk.doc b/qse/doc/page/awk.doc
index f896bd4f..d11624cf 100644
--- a/qse/doc/page/awk.doc
+++ b/qse/doc/page/awk.doc
@@ -199,16 +199,22 @@ QSEAWK implements the language described in the book
The AWK Proramming Language with various @ref awk_ext "extensions".
-An AWK program, at the top level, can composed of the following elements shown below. Each language element requires the option in the second column to be on.
+An AWK program can be composed of the following elements shown below.
+Each language element requires the option in the second column to be on.
Element | Option |
+Comment | |
Global variable declaration | #QSE_AWK_EXPLICIT |
Pattern-action block | #QSE_AWK_PABLOCK |
User-defined function | |
\@include | #QSE_AWK_INCLUDE |
+Single line comments begin with the '#' letter and end at the end of the
+same line. The C style multi-line comments are supported as well.
+Comments are ignored.
+
- pattern-action-block := pattern action-block
- pattern := BEGIN | END | expression | expression-range
- expression-range := expression , expression
diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in
index c87cf217..69d453b6 100644
--- a/qse/include/qse/config.h.in
+++ b/qse/include/qse/config.h.in
@@ -202,6 +202,9 @@
/* Have PTHREAD_PRIO_INHERIT. */
#undef HAVE_PTHREAD_PRIO_INHERIT
+/* Define to 1 if you have the `readdir64' function. */
+#undef HAVE_READDIR64
+
/* Define to 1 if you have the `round' function. */
#undef HAVE_ROUND
diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h
index 5ee9f601..85071d0e 100644
--- a/qse/include/qse/net/httpd.h
+++ b/qse/include/qse/net/httpd.h
@@ -104,6 +104,12 @@ typedef int (*qse_httpd_muxcb_t) (
void* cbarg
);
+typedef struct qse_httpd_dirent_t qse_httpd_dirent_t;
+struct qse_httpd_dirent_t
+{
+};
+
+
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
struct qse_httpd_cbs_t
{
@@ -211,8 +217,6 @@ struct qse_httpd_cbs_t
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
int (*handle_request) (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req);
-
- int (*listdir) (qse_httpd_t* httpd, const qse_mchar_t* path);
};
typedef struct qse_httpd_task_t qse_httpd_task_t;
@@ -502,6 +506,14 @@ qse_httpd_task_t* qse_httpd_entaskfile (
qse_htre_t* req
);
+qse_httpd_task_t* qse_httpd_entaskdir (
+ qse_httpd_t* httpd,
+ qse_httpd_client_t* client,
+ qse_httpd_task_t* pred,
+ const qse_mchar_t* name,
+ qse_htre_t* req
+);
+
qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
diff --git a/qse/lib/awk/err.c b/qse/lib/awk/err.c
index 1a0f9129..24831efe 100644
--- a/qse/lib/awk/err.c
+++ b/qse/lib/awk/err.c
@@ -20,7 +20,7 @@
#include "awk.h"
-const qse_char_t* qse_awk_dflerrstr (qse_awk_t* awk, qse_awk_errnum_t errnum)
+const qse_char_t* qse_awk_dflerrstr (const qse_awk_t* awk, qse_awk_errnum_t errnum)
{
static const qse_char_t* errstr[] =
{
diff --git a/qse/lib/awk/err.h b/qse/lib/awk/err.h
index 473ea402..cb8fd518 100644
--- a/qse/lib/awk/err.h
+++ b/qse/lib/awk/err.h
@@ -25,7 +25,7 @@
extern "C" {
#endif
-const qse_char_t* qse_awk_dflerrstr (qse_awk_t* awk, qse_awk_errnum_t errnum);
+const qse_char_t* qse_awk_dflerrstr (const qse_awk_t* awk, qse_awk_errnum_t errnum);
#ifdef __cplusplus
}
diff --git a/qse/lib/awk/val.c b/qse/lib/awk/val.c
index 3efe9a07..5cba0a50 100644
--- a/qse/lib/awk/val.c
+++ b/qse/lib/awk/val.c
@@ -1268,6 +1268,7 @@ qse_long_t qse_awk_rtx_hashval (qse_awk_rtx_t* rtx, qse_awk_val_t* v)
return -1;
}
+ /* turn off the sign bit */
return hv & ~(((qse_ulong_t)1) << ((QSE_SIZEOF(qse_ulong_t) * 8) - 1));
}
diff --git a/qse/lib/cmn/glob.c b/qse/lib/cmn/glob.c
index c1e63e6f..18dca22a 100644
--- a/qse/lib/cmn/glob.c
+++ b/qse/lib/cmn/glob.c
@@ -34,9 +34,7 @@
# include
# include
#else
-# include
-# include
-# include
+# include "syscall.h"
#endif
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
@@ -326,40 +324,41 @@ static int get_next_segment (glob_t* g, segment_t* seg)
#if defined(_WIN32)
-struct DIR
+struct qse_dir_t
{
HANDLE h;
WIN32_FIND_DATA wfd;
int done;
};
-typedef struct DIR DIR;
+typedef struct qse_dir_t qse_dir_t;
#elif defined(__OS2__)
-struct DIR
+struct qse_dir_t
{
HDIR h;
FILEFINDBUF3L ffb;
ULONG count;
};
-typedef struct DIR DIR;
+typedef struct qse_dir_t qse_dir_t;
#elif defined(__DOS__)
-struct DIR
+
+struct qse_dir_t
{
struct find_t f;
int done;
};
-typedef struct DIR DIR;
+typedef struct qse_dir_t qse_dir_t;
#endif
-static DIR* xopendir (glob_t* g, const qse_cstr_t* path)
+static qse_dir_t* xopendir (glob_t* g, const qse_cstr_t* path)
{
#if defined(_WIN32)
/* ------------------------------------------------------------------- */
- DIR* dp;
+ qse_dir_t* dp;
dp = QSE_MMGR_ALLOC (g->mmgr, QSE_SIZEOF(*dp));
if (dp == QSE_NULL) return QSE_NULL;
@@ -400,7 +399,7 @@ static DIR* xopendir (glob_t* g, const qse_cstr_t* path)
#elif defined(__OS2__)
/* ------------------------------------------------------------------- */
- DIR* dp;
+ qse_dir_t* dp;
APIRET rc;
qse_mchar_t* mptr;
@@ -463,7 +462,7 @@ static DIR* xopendir (glob_t* g, const qse_cstr_t* path)
#elif defined(__DOS__)
/* ------------------------------------------------------------------- */
- DIR* dp;
+ qse_dir_t* dp;
unsigned int rc;
qse_mchar_t* mptr;
qse_size_t wl, ml;
@@ -519,13 +518,12 @@ static DIR* xopendir (glob_t* g, const qse_cstr_t* path)
#else
/* ------------------------------------------------------------------- */
-
#if defined(QSE_CHAR_IS_MCHAR)
- return opendir ((path->len <= 0)? QSE_T("."): path->ptr);
+ return QSE_OPENDIR ((path->len <= 0)? QSE_T("."): path->ptr);
#else
if (path->len <= 0)
{
- return opendir (QSE_MT("."));
+ return QSE_OPENDIR (QSE_MT("."));
}
else
{
@@ -534,7 +532,7 @@ static DIR* xopendir (glob_t* g, const qse_cstr_t* path)
mptr = wcs_to_mbuf (g, path->ptr, &g->mbuf);
if (mptr == QSE_NULL) return QSE_NULL;
- return opendir (mptr);
+ return QSE_OPENDIR (mptr);
}
#endif
/* ------------------------------------------------------------------- */
@@ -542,7 +540,7 @@ static DIR* xopendir (glob_t* g, const qse_cstr_t* path)
#endif
}
-static int xreaddir (glob_t* g, DIR* dp, qse_str_t* path)
+static int xreaddir (glob_t* g, qse_dir_t* dp, qse_str_t* path)
{
#if defined(_WIN32)
@@ -615,14 +613,14 @@ static int xreaddir (glob_t* g, DIR* dp, qse_str_t* path)
#else
/* ------------------------------------------------------------------- */
- struct dirent* de;
+ qse_dirent_t* de;
#if defined(QSE_CHAR_IS_MCHAR)
/* nothing */
#else
qse_size_t ml, wl, tmp;
#endif
- de = readdir (dp);
+ de = QSE_READDIR (dp);
if (de == NULL) return 0;
#if defined(QSE_CHAR_IS_MCHAR)
@@ -640,7 +638,7 @@ static int xreaddir (glob_t* g, DIR* dp, qse_str_t* path)
#endif
}
-static void xclosedir (glob_t* g, DIR* dp)
+static void xclosedir (glob_t* g, qse_dir_t* dp)
{
#if defined(_WIN32)
FindClose (dp->h);
@@ -652,7 +650,7 @@ static void xclosedir (glob_t* g, DIR* dp)
_dos_findclose (&dp->f);
QSE_MMGR_FREE (g->mmgr, dp);
#else
- closedir (dp);
+ QSE_CLOSEDIR (dp);
#endif
}
@@ -722,7 +720,7 @@ struct stack_node_t
{
qse_size_t tmp;
qse_size_t tmp2;
- DIR* dp;
+ qse_dir_t* dp;
segment_t seg;
stack_node_t* next;
@@ -731,7 +729,7 @@ struct stack_node_t
static int search (glob_t* g, segment_t* seg)
{
- DIR* dp;
+ qse_dir_t* dp;
qse_size_t tmp, tmp2;
#if defined(NO_RECURSION)
diff --git a/qse/lib/cmn/syscall.h b/qse/lib/cmn/syscall.h
index 3fdfc1b4..9acb7625 100644
--- a/qse/lib/cmn/syscall.h
+++ b/qse/lib/cmn/syscall.h
@@ -23,39 +23,42 @@
/* This file defines unix/linux system calls */
-#ifdef HAVE_SYS_TYPES_H
+#if defined(HAVE_SYS_TYPES_H)
# include
#endif
-#ifdef HAVE_UNISTD_H
+#if defined(HAVE_UNISTD_H)
# include
#endif
-#ifdef HAVE_SYS_WAIT_H
+#if defined(HAVE_SYS_WAIT_H)
# include
#endif
-#ifdef HAVE_SIGNAL_H
+#if defined(HAVE_SIGNAL_H)
# include
#endif
-#ifdef HAVE_ERRNO_H
+#if defined(HAVE_ERRNO_H)
# include
#endif
-#ifdef HAVE_FCNTL_H
+#if defined(HAVE_FCNTL_H)
# include
#endif
-#ifdef HAVE_TIME_H
+#if defined(HAVE_TIME_H)
# include
#endif
-#ifdef HAVE_SYS_TIME_H
+#if defined(HAVE_SYS_TIME_H)
# include
#endif
-#ifdef HAVE_UTIME_H
+#if defined(HAVE_UTIME_H)
# include
#endif
-#ifdef HAVE_SYS_RESOURCE_H
+#if defined(HAVE_SYS_RESOURCE_H)
# include
#endif
-#ifdef HAVE_SYS_STAT_H
+#if defined(HAVE_SYS_STAT_H)
# include
#endif
+#if defined(HAVE_DIRENT_H)
+# include
+#endif
#if defined(QSE_USE_SYSCALL) && defined(HAVE_SYS_SYSCALL_H)
# include
@@ -355,6 +358,19 @@
# define QSE_UTIMES(path,t) utimes(path,t)
#endif
+/* ===== DIRECTORY - not really system calls ===== */
+typedef DIR qse_dir_t;
+#define QSE_OPENDIR(name) opendir(name)
+#define QSE_CLOSEDIR(name) closedir(name)
+
+#if defined(HAVE_READDIR64)
+ typedef struct dirent64 qse_dirent_t;
+# define QSE_READDIR(x) readdir64(x)
+#else
+ typedef struct dirent qse_dirent_t;
+# define QSE_READDIR(x) readdir(x)
+#endif
+
/* ------------------------------------------------------------------------ */
#if defined(__linux) && defined(__GNUC__) && defined(__x86_64)
diff --git a/qse/lib/net/Makefile.am b/qse/lib/net/Makefile.am
index 49bf4013..2d738541 100644
--- a/qse/lib/net/Makefile.am
+++ b/qse/lib/net/Makefile.am
@@ -14,6 +14,8 @@ libqsenet_la_SOURCES = \
htrd.c \
httpd.c \
httpd-cgi.c \
+ httpd-dir.c \
+ httpd-file.c \
httpd-proxy.c \
httpd-resol.c \
httpd-std.c \
diff --git a/qse/lib/net/Makefile.in b/qse/lib/net/Makefile.in
index 5b091304..91b1406e 100644
--- a/qse/lib/net/Makefile.in
+++ b/qse/lib/net/Makefile.in
@@ -79,8 +79,8 @@ am__installdirs = "$(DESTDIR)$(libdir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libqsenet_la_DEPENDENCIES =
am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \
- httpd-cgi.lo httpd-proxy.lo httpd-resol.lo httpd-std.lo \
- httpd-task.lo upxd.lo
+ httpd-cgi.lo httpd-dir.lo httpd-file.lo httpd-proxy.lo \
+ httpd-resol.lo httpd-std.lo httpd-task.lo upxd.lo
libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS)
libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@@ -271,6 +271,8 @@ libqsenet_la_SOURCES = \
htrd.c \
httpd.c \
httpd-cgi.c \
+ httpd-dir.c \
+ httpd-file.c \
httpd-proxy.c \
httpd-resol.c \
httpd-std.c \
@@ -357,6 +359,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htre.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-cgi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-dir.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-file.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-proxy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-resol.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-std.Plo@am__quote@
diff --git a/qse/lib/net/httpd-dir.c b/qse/lib/net/httpd-dir.c
new file mode 100644
index 00000000..de9b00e4
--- /dev/null
+++ b/qse/lib/net/httpd-dir.c
@@ -0,0 +1,487 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2012 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+#include "httpd.h"
+#include "../cmn/mem.h"
+#include "../cmn/syscall.h"
+#include
+#include /* TODO: remove this */
+
+typedef struct task_dir_t task_dir_t;
+struct task_dir_t
+{
+ const qse_mchar_t* path;
+ qse_http_version_t version;
+ int keepalive;
+};
+
+typedef struct task_dseg_t task_dseg_t;
+struct task_dseg_t
+{
+ const qse_mchar_t* path;
+ qse_dir_t* handle;
+ qse_dirent_t* dent;
+
+ int header_added;
+ int footer_pending;
+
+ /*qse_mchar_t buf[4096];*/
+ qse_mchar_t buf[512]; /* TOOD: increate size */
+ qse_size_t bufpos;
+ qse_size_t buflen;
+ qse_size_t bufrem;
+ qse_size_t chunklen;
+};
+
+static int task_init_dseg (
+ qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
+{
+ task_dseg_t* xtn = qse_httpd_gettaskxtn (httpd, task);
+
+ QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
+ qse_mbscpy ((qse_mchar_t*)(xtn + 1), xtn->path);
+ xtn->path = (qse_mchar_t*)(xtn + 1);
+ task->ctx = xtn;
+
+ return 0;
+}
+
+static void task_fini_dseg (
+ qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
+{
+ task_dseg_t* ctx = (task_dseg_t*)task->ctx;
+ QSE_CLOSEDIR (ctx->handle);
+}
+
+static int task_main_dseg_chunked (
+ qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
+{
+ task_dseg_t* ctx = (task_dseg_t*)task->ctx;
+ qse_ssize_t n;
+ int x;
+
+ if (ctx->bufpos < ctx->buflen) goto send_dirlist;
+
+ /* the buffer size is fixed to QSE_COUNTOF(ctx->buf).
+ * the number of digits need to hold the the size converted to
+ * a hexadecimal notation is roughly (log16(QSE_COUNTOF(ctx->buf) + 1).
+ * it should be safter to use ceil(log16(QSE_COUNTOF(ctx->buf)) + 1
+ * for precision issues.
+ *
+ * 16**X = QSE_COUNTOF(ctx->buf).
+ * X = log16(QSE_COUNTOF(ctx->buf).
+ * X + 1 is a required number of digits.
+ *
+ * Since log16 is not provided, we should use a natural log function
+ * whose base is the constant e (2.718).
+ *
+ * log16(n) = log(n) / log(16)
+ *
+ * The final fomula is here.
+ *
+ * X = ceil((log(QSE_COUNTOF(ctx->buf)) / log(16))) + 1;
+ *
+ * However, i won't use these floating-point opertions.
+ * instead i'll reserve a hardcoded size. so when you change
+ * the size of the buffer arrray, you should check this size.
+ */
+
+#define SIZE_CHLEN 4
+#define SIZE_CHLENCRLF 2
+#define SIZE_CHENDCRLF 2
+
+ /* reserve space to fill with the chunk length
+ * 4 for the actual chunk length and +2 for \r\n */
+ ctx->buflen = SIZE_CHLEN + SIZE_CHLENCRLF;
+
+ /* free space remaing in the buffer for the chunk data */
+ ctx->bufrem = QSE_COUNTOF(ctx->buf) - ctx->buflen - SIZE_CHENDCRLF;
+
+ if (ctx->footer_pending)
+ {
+ x = snprintf (
+ &ctx->buf[ctx->buflen],
+ ctx->bufrem,
+ QSE_MT("