diff --git a/qse/include/qse/cmn/str.h b/qse/include/qse/cmn/str.h
index d32203e2..5a33fe41 100644
--- a/qse/include/qse/cmn/str.h
+++ b/qse/include/qse/cmn/str.h
@@ -914,6 +914,56 @@ QSE_EXPORT qse_size_t qse_wcsxncat (
# define qse_strxncat(buf,bsz,str,len) qse_wcsxncat(buf,bsz,str,len)
#endif
+
+/* ---------------------------------------------------- */
+
+QSE_EXPORT qse_size_t qse_mbsjoin (
+ qse_mchar_t* buf,
+ ...
+);
+
+QSE_EXPORT qse_size_t qse_mbsxjoin (
+ qse_mchar_t* buf,
+ qse_size_t size,
+ ...
+);
+
+/*
+ * The qse_wcsjoin() function joins a list of wide-charcter strings into
+ * a buffer. The list of strings is terminated by QSE_NULL.
+ *
+ * \code
+ * qse_wcsjoin (x, QSE_T("hello"), QSE_T("world"), QSE_NULL);
+ * \endcode
+ *
+ * \return the number of character in the joined string excluding
+ * the terminating null.
+ */
+QSE_EXPORT qse_size_t qse_wcsjoin (
+ qse_wchar_t* buf,
+ ...
+);
+
+QSE_EXPORT qse_size_t qse_wcsxjoin (
+ qse_wchar_t* buf,
+ qse_size_t size,
+ ...
+);
+
+QSE_EXPORT qse_size_t qse_strjoin (
+ qse_char_t* buf,
+ ...
+);
+
+QSE_EXPORT qse_size_t qse_strxjoin (
+ qse_char_t* buf,
+ qse_size_t size,
+ ...
+);
+
+/* ---------------------------------------------------- */
+
+
QSE_EXPORT int qse_mbscmp (
const qse_mchar_t* s1,
const qse_mchar_t* s2
diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am
index adbef0d0..e637acbd 100644
--- a/qse/lib/cmn/Makefile.am
+++ b/qse/lib/cmn/Makefile.am
@@ -12,6 +12,7 @@ noinst_HEADERS = \
fs.h \
mem.h \
printf.h \
+ str-join.h \
str-subst.h \
syscall.h \
syserr.h \
@@ -83,6 +84,7 @@ libqsecmn_la_SOURCES = \
str-fcpy.c \
str-fnmat.c \
str-incl.c \
+ str-join.c \
str-len.c \
str-pac.c \
str-pbrk.c \
diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in
index 1f515e01..f8706e60 100644
--- a/qse/lib/cmn/Makefile.in
+++ b/qse/lib/cmn/Makefile.in
@@ -94,12 +94,12 @@ am__libqsecmn_la_SOURCES_DIST = alg-base64.c alg-rand.c alg-search.c \
slmb.c stdio.c str-beg.c str-cat.c str-chr.c str-cnv.c \
str-cmp.c str-cpy.c str-del.c str-dup.c str-dynm.c str-dynw.c \
str-end.c str-excl.c str-fcpy.c str-fnmat.c str-incl.c \
- str-len.c str-pac.c str-pbrk.c str-put.c str-rev.c str-rot.c \
- str-set.c str-spl.c str-spn.c str-str.c str-subst.c str-tok.c \
- str-trm.c str-word.c task.c time.c tio.c tre.c tre-ast.c \
- tre-compile.c tre-match-backtrack.c tre-match-parallel.c \
- tre-parse.c tre-stack.c uri.c utf8.c xma.c uni.c cp949.c \
- cp950.c
+ str-join.c str-len.c str-pac.c str-pbrk.c str-put.c str-rev.c \
+ str-rot.c str-set.c str-spl.c str-spn.c str-str.c str-subst.c \
+ str-tok.c str-trm.c str-word.c task.c time.c tio.c tre.c \
+ tre-ast.c tre-compile.c tre-match-backtrack.c \
+ tre-match-parallel.c tre-parse.c tre-stack.c uri.c utf8.c \
+ xma.c uni.c cp949.c cp950.c
@ENABLE_BUNDLED_UNICODE_TRUE@am__objects_1 = uni.lo
@ENABLE_XCMGRS_TRUE@am__objects_2 = cp949.lo cp950.lo
am_libqsecmn_la_OBJECTS = alg-base64.lo alg-rand.lo alg-search.lo \
@@ -112,12 +112,13 @@ am_libqsecmn_la_OBJECTS = alg-base64.lo alg-rand.lo alg-search.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 task.lo time.lo \
- tio.lo tre.lo tre-ast.lo tre-compile.lo tre-match-backtrack.lo \
- tre-match-parallel.lo tre-parse.lo tre-stack.lo uri.lo utf8.lo \
- xma.lo $(am__objects_1) $(am__objects_2)
+ str-join.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 \
+ task.lo time.lo tio.lo tre.lo tre-ast.lo tre-compile.lo \
+ tre-match-backtrack.lo tre-match-parallel.lo tre-parse.lo \
+ tre-stack.lo uri.lo utf8.lo xma.lo $(am__objects_1) \
+ $(am__objects_2)
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -369,6 +370,7 @@ noinst_HEADERS = \
fs.h \
mem.h \
printf.h \
+ str-join.h \
str-subst.h \
syscall.h \
syserr.h \
@@ -387,10 +389,10 @@ libqsecmn_la_SOURCES = alg-base64.c alg-rand.c alg-search.c alg-sort.c \
pio.c pma.c rbt.c rex.c printf.c sio.c sll.c slmb.c stdio.c \
str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c str-cpy.c \
str-del.c str-dup.c str-dynm.c str-dynw.c str-end.c str-excl.c \
- str-fcpy.c str-fnmat.c str-incl.c str-len.c str-pac.c \
- str-pbrk.c str-put.c str-rev.c str-rot.c str-set.c str-spl.c \
- str-spn.c str-str.c str-subst.c str-tok.c str-trm.c str-word.c \
- task.c time.c tio.c tre.c tre-ast.c tre-compile.c \
+ str-fcpy.c str-fnmat.c str-incl.c str-join.c str-len.c \
+ str-pac.c str-pbrk.c str-put.c str-rev.c str-rot.c str-set.c \
+ str-spl.c str-spn.c str-str.c str-subst.c str-tok.c str-trm.c \
+ str-word.c task.c time.c tio.c tre.c tre-ast.c tre-compile.c \
tre-match-backtrack.c tre-match-parallel.c tre-parse.c \
tre-stack.c uri.c utf8.c xma.c $(am__append_1) $(am__append_2)
libqsecmn_la_LDFLAGS = -version-info 1:0:0 -no-undefined
@@ -540,6 +542,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-fcpy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-fnmat.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-incl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-join.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-len.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-pac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-pbrk.Plo@am__quote@
diff --git a/qse/lib/cmn/str-join.c b/qse/lib/cmn/str-join.c
new file mode 100644
index 00000000..e7ae3f18
--- /dev/null
+++ b/qse/lib/cmn/str-join.c
@@ -0,0 +1,77 @@
+/*
+ * $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
+#include
+
+/* ----------------------------------- */
+
+#undef char_t
+#undef strjoin
+#undef strjoinv
+#undef strxjoin
+#undef strxjoinv
+#undef strcpy
+#undef strxcpy
+
+#define char_t qse_mchar_t
+#define strjoin qse_mbsjoin
+#define strjoinv qse_mbsjoinv
+#define strxjoin qse_mbsxjoin
+#define strxjoinv qse_mbsxjoinv
+#define strcpy qse_mbscpy
+#define strxcpy qse_mbsxcpy
+#include "str-join.h"
+
+/* ----------------------------------- */
+
+#undef char_t
+#undef strjoin
+#undef strjoinv
+#undef strxjoin
+#undef strxjoinv
+#undef strcpy
+#undef strxcpy
+
+#define char_t qse_wchar_t
+#define strjoin qse_wcsjoin
+#define strjoinv qse_wcsjoinv
+#define strxjoin qse_wcsxjoin
+#define strxjoinv qse_wcsxjoinv
+#define strcpy qse_wcscpy
+#define strxcpy qse_wcsxcpy
+#include "str-join.h"
+
+#undef char_t
+#undef strjoin
+#undef strjoinv
+#undef strxjoin
+#undef strxjoinv
+#undef strcpy
+#undef strxcpy
+
+#define char_t qse_char_t
+#define strjoin qse_strjoin
+#define strjoinv qse_strjoinv
+#define strxjoin qse_strxjoin
+#define strxjoinv qse_strxjoinv
+#define strcpy qse_strcpy
+#define strxcpy qse_strxcpy
+#include "str-join.h"
diff --git a/qse/lib/cmn/str-join.h b/qse/lib/cmn/str-join.h
new file mode 100644
index 00000000..2e442a22
--- /dev/null
+++ b/qse/lib/cmn/str-join.h
@@ -0,0 +1,86 @@
+/*
+ * $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 .
+ */
+
+#if !defined(char_t) && !defined(strjoin) && !defined(strxjoin)
+# error Never include this file
+#endif
+
+
+qse_size_t strxjoinv (char_t* buf, qse_size_t size, va_list ap)
+{
+ const char_t* p;
+ char_t* ptr = buf;
+ qse_size_t left = size, n;
+
+ while (left > 0)
+ {
+ p = va_arg (ap, const char_t*);
+ if (p == QSE_NULL) break;
+
+ n = strxcpy (ptr, left, p);
+ left -= n; ptr += n;
+ }
+
+ return size - left;
+}
+
+
+qse_size_t strxjoin (char_t* buf, qse_size_t size, ...)
+{
+ va_list ap;
+ qse_size_t n;
+
+ va_start (ap, size);
+ n = strxjoinv (buf, size, ap);
+ va_end (ap);
+
+ return n;
+}
+
+qse_size_t strjoinv (char_t* buf, va_list ap)
+{
+ const char_t* p;
+ char_t* ptr = buf;
+ qse_size_t n;
+
+ while (1)
+ {
+ p = va_arg (ap, const char_t*);
+ if (p == QSE_NULL) break;
+
+ n = strcpy (ptr, p);
+ ptr += n;
+ }
+
+ return ptr - buf;
+}
+
+
+qse_size_t strjoin (char_t* buf, ...)
+{
+ va_list ap;
+ qse_size_t n;
+
+ va_start (ap, buf);
+ n = strjoinv (buf, ap);
+ va_end (ap);
+
+ return n;
+}