diff --git a/qse/cmd/sed/sed.c b/qse/cmd/sed/sed.c
index 2e3c8e93..1ac2be24 100644
--- a/qse/cmd/sed/sed.c
+++ b/qse/cmd/sed/sed.c
@@ -429,6 +429,25 @@ static void unset_intr_run (void)
#endif
}
+static void trace (qse_sed_t* sed, qse_sed_exec_op_t op, const qse_sed_cmd_t* cmd)
+{
+ switch (op)
+ {
+ case QSE_SED_EXEC_READ:
+ qse_printf (QSE_T("reading...\n"));
+ break;
+ case QSE_SED_EXEC_WRITE:
+ qse_printf (QSE_T("wrting...\n"));
+ break;
+ case QSE_SED_EXEC_MATCH:
+ qse_printf (QSE_T("matching...\n"));
+ break;
+ case QSE_SED_EXEC_EXEC:
+ qse_printf (QSE_T("executing...\n"));
+ break;
+ }
+}
+
int sed_main (int argc, qse_char_t* argv[])
{
qse_mmgr_t* mmgr = QSE_NULL;
@@ -499,6 +518,10 @@ int sed_main (int argc, qse_char_t* argv[])
goto oops;
}
+#if 0
+if (g_trace) qse_sed_setexechook (sed, trace);
+#endif
+
if (g_separate && g_infile_pos > 0)
{
qse_sed_iostd_t out;
diff --git a/qse/include/qse/cmn/str.h b/qse/include/qse/cmn/str.h
index 38484fd1..65dbf02a 100644
--- a/qse/include/qse/cmn/str.h
+++ b/qse/include/qse/cmn/str.h
@@ -1,5 +1,5 @@
/*
- * $Id: str.h 556 2011-08-31 15:43:46Z hyunghwan.chung $
+ * $Id: str.h 576 2011-09-23 14:52:22Z hyunghwan.chung $
*
Copyright 2006-2011 Chung, Hyung-Hwan.
This file is part of QSE.
@@ -317,6 +317,34 @@ enum qse_wcstrmx_op_t
# define QSE_STRTRMX_RIGHT QSE_WCSTRMX_RIGHT
#endif
+enum qse_mbsfnmat_flag_t
+{
+ QSE_MBSFNMAT_PATHNAME = (1 << 0),
+ QSE_MBSFNMAT_NOESCAPE = (1 << 1),
+ QSE_MBSFNMAT_PERIOD = (1 << 2),
+ QSE_MBSFNMAT_IGNORECASE = (1 << 3)
+};
+
+enum qse_wcsfnmat_flag_t
+{
+ QSE_WCSFNMAT_PATHNAME = (1 << 0),
+ QSE_WCSFNMAT_NOESCAPE = (1 << 1),
+ QSE_WCSFNMAT_PERIOD = (1 << 2),
+ QSE_WCSFNMAT_IGNORECASE = (1 << 3)
+};
+
+#ifdef QSE_CHAR_IS_MCHAR
+# define QSE_STRFNMAT_PATHNAME QSE_MBSFNMAT_PATHNAME
+# define QSE_STRFNMAT_NOESCAPE QSE_MBSFNMAT_NOESCAPE
+# define QSE_STRFNMAT_PERIOD QSE_MBSFNMAT_PERIOD
+# define QSE_STRFNMAT_IGNORECASE QSE_MBSFNMAT_IGNORECASE
+#else
+# define QSE_STRFNMAT_PATHNAME QSE_WCSFNMAT_PATHNAME
+# define QSE_STRFNMAT_NOESCAPE QSE_WCSFNMAT_NOESCAPE
+# define QSE_STRFNMAT_PERIOD QSE_WCSFNMAT_PERIOD
+# define QSE_STRFNMAT_IGNORECASE QSE_WCSFNMAT_IGNORECASE
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -1489,6 +1517,23 @@ qse_mchar_t* qse_mbspbrk (
const qse_mchar_t* str2
);
+qse_mchar_t* qse_mbsxpbrk (
+ const qse_mchar_t* str1,
+ qse_size_t len,
+ const qse_mchar_t* str2
+);
+
+qse_mchar_t* qse_mbsrpbrk (
+ const qse_mchar_t* str1,
+ const qse_mchar_t* str2
+);
+
+qse_mchar_t* qse_mbsxrpbrk (
+ const qse_mchar_t* str1,
+ qse_size_t len,
+ const qse_mchar_t* str2
+);
+
/*
* The qse_wcspbrk() function searches @a str1 for the first occurrence of
* a character in @a str2.
@@ -1500,10 +1545,33 @@ qse_wchar_t* qse_wcspbrk (
const qse_wchar_t* str2
);
+qse_wchar_t* qse_wcsxpbrk (
+ const qse_wchar_t* str1,
+ qse_size_t len,
+ const qse_wchar_t* str2
+);
+
+qse_wchar_t* qse_wcsrpbrk (
+ const qse_wchar_t* str1,
+ const qse_wchar_t* str2
+);
+
+qse_wchar_t* qse_wcsxrpbrk (
+ const qse_wchar_t* str1,
+ qse_size_t len,
+ const qse_wchar_t* str2
+);
+
#ifdef QSE_CHAR_IS_MCHAR
-# define qse_strpbrk(str1,str2) qse_mbspbrk(str1,str2)
+# define qse_strpbrk(str1,str2) qse_mbspbrk(str1,str2)
+# define qse_strxpbrk(str1,len,str2) qse_mbsxpbrk(str1,len,str2)
+# define qse_strrpbrk(str1,str2) qse_mbsrpbrk(str1,str2)
+# define qse_strxrpbrk(str1,len,str2) qse_mbsxrpbrk(str1,len,str2)
#else
-# define qse_strpbrk(str1,str2) qse_wcspbrk(str1,str2)
+# define qse_strpbrk(str1,str2) qse_wcspbrk(str1,str2)
+# define qse_strxpbrk(str1,len,str2) qse_wcsxpbrk(str1,len,str2)
+# define qse_strrpbrk(str1,str2) qse_wcsrpbrk(str1,str2)
+# define qse_strxrpbrk(str1,len,str2) qse_wcsxrpbrk(str1,len,str2)
#endif
/*
@@ -2101,6 +2169,74 @@ qse_size_t qse_wcsxpac (
# define qse_strxpac(str,len) qse_wcsxpac(str,len)
#endif
+int qse_mbsfnmat (
+ const qse_mchar_t* str,
+ const qse_mchar_t* ptn,
+ int flags
+);
+
+int qse_mbsxfnmat (
+ const qse_mchar_t* str,
+ qse_size_t slen,
+ const qse_mchar_t* ptn,
+ int flags
+);
+
+int qse_mbsnfnmat (
+ const qse_mchar_t* str,
+ const qse_mchar_t* ptn,
+ qse_size_t plen,
+ int flags
+);
+
+int qse_mbsxnfnmat (
+ const qse_mchar_t* str,
+ qse_size_t slen,
+ const qse_mchar_t* ptn,
+ qse_size_t plen,
+ int flags
+);
+
+int qse_wcsfnmat (
+ const qse_wchar_t* str,
+ const qse_wchar_t* ptn,
+ int flags
+);
+
+int qse_wcsxfnmat (
+ const qse_wchar_t* str,
+ qse_size_t slen,
+ const qse_wchar_t* ptn,
+ int flags
+);
+
+int qse_wcsnfnmat (
+ const qse_wchar_t* str,
+ const qse_wchar_t* ptn,
+ qse_size_t plen,
+ int flags
+);
+
+int qse_wcsxnfnmat (
+ const qse_wchar_t* str,
+ qse_size_t slen,
+ const qse_wchar_t* ptn,
+ qse_size_t plen,
+ int flags
+);
+
+#ifdef QSE_CHAR_IS_MCHAR
+# define qse_strfnmat(str,ptn,flags) qse_mbsfnmat(str,ptn,flags)
+# define qse_strxfnmat(str,slen,ptn,flags) qse_mbsxfnmat(str,slen,ptn,flags)
+# define qse_strnfnmat(str,ptn,plen,flags) qse_mbsnfnmat(str,ptn,plen,flags)
+# define qse_strxnfnmat(str,slen,ptn,plen,flags) qse_mbsxnfnmat(str,slen,ptn,plen,flags)
+#else
+# define qse_strfnmat(str,ptn,flags) qse_wcsfnmat(str,ptn,flags)
+# define qse_strxfnmat(str,slen,ptn,flags) qse_wcsxfnmat(str,slen,ptn,flags)
+# define qse_strnfnmat(str,ptn,plen,flags) qse_wcsnfnmat(str,ptn,plen,flags)
+# define qse_strxnfnmat(str,slen,ptn,plen,flags) qse_wcsxnfnmat(str,slen,ptn,plen,flags)
+#endif
+
/**
* The qse_mbstowcslen() function scans a null-terminated multibyte string
* to calculate the number of wide characters it can be converted to.
diff --git a/qse/include/qse/sed/sed.h b/qse/include/qse/sed/sed.h
index 73c29bc3..02118c10 100644
--- a/qse/include/qse/sed/sed.h
+++ b/qse/include/qse/sed/sed.h
@@ -1,5 +1,5 @@
/*
- * $Id: sed.h 570 2011-09-20 04:40:45Z hyunghwan.chung $
+ * $Id: sed.h 576 2011-09-23 14:52:22Z hyunghwan.chung $
*
Copyright 2006-2011 Chung, Hyung-Hwan.
This file is part of QSE.
@@ -65,6 +65,8 @@
*/
typedef struct qse_sed_t qse_sed_t;
+typedef struct qse_sed_cmd_t qse_sed_cmd_t;
+
/**
* The qse_sed_loc_t defines a structure to store location information.
*/
@@ -193,6 +195,21 @@ typedef int (*qse_sed_lformatter_t) (
int (*cwriter) (qse_sed_t*, qse_char_t)
);
+enum qse_sed_exec_op_t
+{
+ QSE_SED_EXEC_READ,
+ QSE_SED_EXEC_WRITE,
+ QSE_SED_EXEC_MATCH,
+ QSE_SED_EXEC_EXEC
+};
+typedef enum qse_sed_exec_op_t qse_sed_exec_op_t;
+
+typedef void (*qse_sed_exec_hook_t) (
+ qse_sed_t* sed,
+ qse_sed_exec_op_t op,
+ const qse_sed_cmd_t* cmd
+);
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -415,6 +432,15 @@ void qse_sed_setlinnum (
qse_size_t num /**< a line number */
);
+qse_sed_exec_hook_t qse_sed_getexechook (
+ qse_sed_t* sed
+);
+
+void qse_sed_setexechook (
+ qse_sed_t* sed,
+ qse_sed_exec_hook_t hook
+);
+
#ifdef __cplusplus
}
#endif
diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am
index 424f116c..33eb8900 100644
--- a/qse/lib/cmn/Makefile.am
+++ b/qse/lib/cmn/Makefile.am
@@ -47,6 +47,7 @@ libqsecmn_la_SOURCES = \
str-end.c \
str-excl.c \
str-fcpy.c \
+ str-fnmat.c \
str-incl.c \
str-len.c \
str-pac.c \
diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in
index 2896e30d..a394ba91 100644
--- a/qse/lib/cmn/Makefile.in
+++ b/qse/lib/cmn/Makefile.in
@@ -79,12 +79,13 @@ am_libqsecmn_la_OBJECTS = alg-search.lo alg-sort.lo assert.lo chr.lo \
rex.lo sio.lo sll.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-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 stdio.lo xma.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 stdio.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) \
@@ -312,6 +313,7 @@ libqsecmn_la_SOURCES = \
str-end.c \
str-excl.c \
str-fcpy.c \
+ str-fnmat.c \
str-incl.c \
str-len.c \
str-pac.c \
@@ -469,6 +471,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-end.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-excl.Plo@am__quote@
@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-len.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-pac.Plo@am__quote@
diff --git a/qse/lib/cmn/str-fnmat.c b/qse/lib/cmn/str-fnmat.c
new file mode 100644
index 00000000..cdfe086b
--- /dev/null
+++ b/qse/lib/cmn/str-fnmat.c
@@ -0,0 +1,692 @@
+/*
+ * $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
+#include
+
+/* ------------------------------------------------------------------------- */
+/* | MBS VERSION | */
+/* ------------------------------------------------------------------------- */
+
+/* separator to use in a pattern.
+ * this also matches a backslash in non-unix OS where a blackslash
+ * is used as a path separator. MBS_SEPCHS defines OS path separators. */
+#define MBS_SEP QSE_MT('/')
+#define MBS_ESC QSE_MT('\\')
+#define MBS_DOT QSE_MT('.')
+
+#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
+# define MBS_ISSEPCH(c) ((c) == QSE_MT('/') || (c) == QSE_MT('\\'))
+# define MBS_SEPCHS QSE_MT("/\\")
+#else
+# define MBS_ISSEPCH(c) ((c) == QSE_MT('/'))
+# define MBS_SEPCHS QSE_MT("/")
+#endif
+
+static int __mbsxnfnmat (
+ const qse_mchar_t* str, qse_size_t slen,
+ const qse_mchar_t* ptn, qse_size_t plen, int flags, int no_first_period)
+{
+ const qse_mchar_t* sp = str;
+ const qse_mchar_t* pp = ptn;
+ const qse_mchar_t* se = str + slen;
+ const qse_mchar_t* pe = ptn + plen;
+ qse_mchar_t sc, pc, pc2;
+
+ while (1)
+ {
+ if (pp < pe && *pp == MBS_ESC &&
+ !(flags & QSE_MBSFNMAT_NOESCAPE))
+ {
+ /* pattern is escaped and escaping is allowed. */
+
+ if ((++pp) >= pe)
+ {
+ /*
+ * the last character of the pattern is an MBS_ESC.
+ * matching is performed as if the end of the pattern is
+ * reached just without an MBS_ESC.
+ */
+ if (sp < se) return 0;
+ return 1;
+ }
+
+ if (sp >= se) return 0; /* premature string termination */
+
+ sc = *sp; pc = *pp; /* pc is just a normal character */
+ if ((flags & QSE_MBSFNMAT_IGNORECASE) != 0)
+ {
+ /* make characters to lower-case */
+ sc = QSE_TOMLOWER(sc);
+ pc = QSE_TOMLOWER(pc);
+ }
+
+ if (sc != pc) return 0;
+ sp++; pp++;
+ continue;
+ }
+ if (pp >= pe)
+ {
+ /*
+ * the end of the pattern has been reached.
+ * the string must terminate too.
+ */
+ return sp >= se;
+ }
+
+ if (sp >= se)
+ {
+ /* the string terminats prematurely */
+ while (pp < pe && *pp == QSE_MT('*')) pp++;
+ return pp >= pe;
+ }
+
+ sc = *sp; pc = *pp;
+
+ if (sc == MBS_DOT && (flags & QSE_MBSFNMAT_PERIOD))
+ {
+ /*
+ * a leading period in the staring must match
+ * a period in the pattern explicitly
+ */
+ if ((!no_first_period && sp == str) ||
+ (MBS_ISSEPCH(sp[-1]) && (flags & QSE_MBSFNMAT_PATHNAME)))
+ {
+ if (pc != MBS_DOT) return 0;
+ sp++; pp++;
+ continue;
+ }
+ }
+ else if (MBS_ISSEPCH(sc) && (flags & QSE_MBSFNMAT_PATHNAME))
+ {
+ while (pc == QSE_MT('*'))
+ {
+ if ((++pp) >= pe) return 0;
+ pc = *pp;
+ }
+
+ /* a path separator must be matched explicitly */
+ if (pc != MBS_SEP) return 0;
+ sp++; pp++;
+ continue;
+ }
+
+ /* the handling of special pattern characters begins here */
+ if (pc == QSE_MT('?'))
+ {
+ /* match any single character */
+ sp++; pp++;
+ }
+ else if (pc == QSE_MT('*'))
+ {
+ /* match zero or more characters */
+
+ /* compact asterisks */
+ do { pp++; } while (pp < pe && *pp == QSE_MT('*'));
+
+ if (pp >= pe)
+ {
+ /*
+ * if the last character in the pattern is an asterisk,
+ * the string should not have any directory separators
+ * when QSE_MBSFNMAT_PATHNAME is set.
+ */
+ if (flags & QSE_MBSFNMAT_PATHNAME)
+ {
+ if (qse_mbsxpbrk(sp, se-sp, MBS_SEPCHS) != QSE_NULL) return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ do
+ {
+ if (__mbsxnfnmat(sp, se - sp, pp, pe - pp, flags, 1))
+ {
+ return 1;
+ }
+
+ if (MBS_ISSEPCH(*sp) &&
+ (flags & QSE_MBSFNMAT_PATHNAME)) break;
+
+ sp++;
+ }
+ while (sp < se);
+
+ return 0;
+ }
+ }
+ else if (pc == QSE_MT('['))
+ {
+ /* match range */
+ int negate = 0;
+ int matched = 0;
+
+ if ((++pp) >= pe) return 0;
+ if (*pp == QSE_MT('!')) { negate = 1; pp++; }
+
+ while (pp < pe && *pp != QSE_MT(']'))
+ {
+ if (*pp == QSE_MT('['))
+ {
+ qse_size_t pl = pe - pp;
+
+ if (pl >= 10)
+ {
+ if (qse_mbszcmp(pp, QSE_MT("[:xdigit:]"), 10) == 0)
+ {
+ matched = QSE_ISMXDIGIT(sc);
+ pp += 10; continue;
+ }
+ }
+
+ if (pl >= 9)
+ {
+ if (qse_mbszcmp(pp, QSE_MT("[:upper:]"), 9) == 0)
+ {
+ matched = QSE_ISMUPPER(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:lower:]"), 9) == 0)
+ {
+ matched = QSE_ISMLOWER(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:alpha:]"), 9) == 0)
+ {
+ matched = QSE_ISMALPHA(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:digit:]"), 9) == 0)
+ {
+ matched = QSE_ISMDIGIT(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:alnum:]"), 9) == 0)
+ {
+ matched = QSE_ISMALNUM(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:space:]"), 9) == 0)
+ {
+ matched = QSE_ISMSPACE(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:print:]"), 9) == 0)
+ {
+ matched = QSE_ISMPRINT(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:graph:]"), 9) == 0)
+ {
+ matched = QSE_ISMGRAPH(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:cntrl:]"), 9) == 0)
+ {
+ matched = QSE_ISMCNTRL(sc);
+ pp += 9; continue;
+ }
+ else if (qse_mbszcmp(pp, QSE_MT("[:punct:]"), 9) == 0)
+ {
+ matched = QSE_ISMPUNCT(sc);
+ pp += 9; continue;
+ }
+ }
+
+ /*
+ * characters in an invalid class name are
+ * just treated as normal characters
+ */
+ }
+
+ if (*pp == MBS_ESC &&
+ !(flags & QSE_MBSFNMAT_NOESCAPE)) pp++;
+ else if (*pp == QSE_MT(']')) break;
+
+ if (pp >= pe) break;
+
+ pc = *pp;
+ if ((flags & QSE_MBSFNMAT_IGNORECASE) != 0)
+ {
+ sc = QSE_TOMLOWER(sc);
+ pc = QSE_TOMLOWER(pc);
+ }
+
+ if (pp + 1 < pe && pp[1] == QSE_MT('-'))
+ {
+ pp += 2; /* move the a character next to a dash */
+
+ if (pp >= pe)
+ {
+ if (sc >= pc) matched = 1;
+ break;
+ }
+
+ if (*pp == MBS_ESC &&
+ !(flags & QSE_MBSFNMAT_NOESCAPE))
+ {
+ if ((++pp) >= pe)
+ {
+ if (sc >= pc) matched = 1;
+ break;
+ }
+ }
+ else if (*pp == QSE_MT(']'))
+ {
+ if (sc >= pc) matched = 1;
+ break;
+ }
+
+ pc2 = *pp;
+ if ((flags & QSE_MBSFNMAT_IGNORECASE) != 0)
+ pc2 = QSE_TOMLOWER(pc2);
+
+ if (sc >= pc && sc <= pc2) matched = 1;
+ pp++;
+ }
+ else
+ {
+ if (sc == pc) matched = 1;
+ pp++;
+ }
+ }
+
+ if (negate) matched = !matched;
+ if (!matched) return 0;
+ sp++; if (pp < pe) pp++;
+ }
+ else
+ {
+ /* a normal character */
+ if ((flags & QSE_MBSFNMAT_IGNORECASE) != 0)
+ {
+ sc = QSE_TOMLOWER(sc);
+ pc = QSE_TOMLOWER(pc);
+ }
+
+ if (sc != pc) return 0;
+ sp++; pp++;
+ }
+ }
+
+ /* will never reach here. but make some immature compilers happy... */
+ return 0;
+}
+
+int qse_mbsfnmat (const qse_mchar_t* str, const qse_mchar_t* ptn, int flags)
+{
+ return __mbsxnfnmat (
+ str, qse_mbslen(str), ptn, qse_mbslen(ptn), flags, 0);
+}
+
+int qse_mbsxfnmat (
+ const qse_mchar_t* str, qse_size_t slen, const qse_mchar_t* ptn, int flags)
+{
+ return __mbsxnfnmat (str, slen, ptn, qse_mbslen(ptn), flags, 0);
+}
+
+int qse_mbsnfnmat (
+ const qse_mchar_t* str, const qse_mchar_t* ptn, qse_size_t plen, int flags)
+{
+ return __mbsxnfnmat (str, qse_mbslen(str), ptn, plen, flags, 0);
+}
+
+int qse_mbsxnfnmat (
+ const qse_mchar_t* str, qse_size_t slen,
+ const qse_mchar_t* ptn, qse_size_t plen, int flags)
+{
+ return __mbsxnfnmat (str, slen, ptn, plen, flags, 0);
+}
+
+/* ------------------------------------------------------------------------- */
+/* | WCS VERSION | */
+/* ------------------------------------------------------------------------- */
+
+/* separator to use in a pattern.
+ * this also matches a backslash in non-unix OS where a blackslash
+ * is used as a path separator. WCS_SEPCHS defines OS path separators. */
+#define WCS_SEP QSE_WT('/')
+#define WCS_ESC QSE_WT('\\')
+#define WCS_DOT QSE_WT('.')
+
+#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
+# define WCS_ISSEPCH(c) ((c) == QSE_WT('/') || (c) == QSE_WT('\\'))
+# define WCS_SEPCHS QSE_WT("/\\")
+#else
+# define WCS_ISSEPCH(c) ((c) == QSE_WT('/'))
+# define WCS_SEPCHS QSE_WT("/")
+#endif
+
+static int __wcsxnfnmat (
+ const qse_wchar_t* str, qse_size_t slen,
+ const qse_wchar_t* ptn, qse_size_t plen, int flags, int no_first_period)
+{
+ const qse_wchar_t* sp = str;
+ const qse_wchar_t* pp = ptn;
+ const qse_wchar_t* se = str + slen;
+ const qse_wchar_t* pe = ptn + plen;
+ qse_wchar_t sc, pc, pc2;
+
+ while (1)
+ {
+ if (pp < pe && *pp == WCS_ESC &&
+ !(flags & QSE_WCSFNMAT_NOESCAPE))
+ {
+ /* pattern is escaped and escaping is allowed. */
+
+ if ((++pp) >= pe)
+ {
+ /*
+ * the last character of the pattern is an WCS_ESC.
+ * matching is performed as if the end of the pattern is
+ * reached just without an WCS_ESC.
+ */
+ if (sp < se) return 0;
+ return 1;
+ }
+
+ if (sp >= se) return 0; /* premature string termination */
+
+ sc = *sp; pc = *pp; /* pc is just a normal character */
+ if ((flags & QSE_WCSFNMAT_IGNORECASE) != 0)
+ {
+ /* make characters to lower-case */
+ sc = QSE_TOWLOWER(sc);
+ pc = QSE_TOWLOWER(pc);
+ }
+
+ if (sc != pc) return 0;
+ sp++; pp++;
+ continue;
+ }
+ if (pp >= pe)
+ {
+ /*
+ * the end of the pattern has been reached.
+ * the string must terminate too.
+ */
+ return sp >= se;
+ }
+
+ if (sp >= se)
+ {
+ /* the string terminats prematurely */
+ while (pp < pe && *pp == QSE_WT('*')) pp++;
+ return pp >= pe;
+ }
+
+ sc = *sp; pc = *pp;
+
+ if (sc == WCS_DOT && (flags & QSE_WCSFNMAT_PERIOD))
+ {
+ /*
+ * a leading period in the staring must match
+ * a period in the pattern explicitly
+ */
+ if ((!no_first_period && sp == str) ||
+ (WCS_ISSEPCH(sp[-1]) && (flags & QSE_WCSFNMAT_PATHNAME)))
+ {
+ if (pc != WCS_DOT) return 0;
+ sp++; pp++;
+ continue;
+ }
+ }
+ else if (WCS_ISSEPCH(sc) && (flags & QSE_WCSFNMAT_PATHNAME))
+ {
+ while (pc == QSE_WT('*'))
+ {
+ if ((++pp) >= pe) return 0;
+ pc = *pp;
+ }
+
+ /* a path separator must be matched explicitly */
+ if (pc != WCS_SEP) return 0;
+ sp++; pp++;
+ continue;
+ }
+
+ /* the handling of special pattern characters begins here */
+ if (pc == QSE_WT('?'))
+ {
+ /* match any single character */
+ sp++; pp++;
+ }
+ else if (pc == QSE_WT('*'))
+ {
+ /* match zero or more characters */
+
+ /* compact asterisks */
+ do { pp++; } while (pp < pe && *pp == QSE_WT('*'));
+
+ if (pp >= pe)
+ {
+ /*
+ * if the last character in the pattern is an asterisk,
+ * the string should not have any directory separators
+ * when QSE_WCSFNMAT_PATHNAME is set.
+ */
+ if (flags & QSE_WCSFNMAT_PATHNAME)
+ {
+ if (qse_wcsxpbrk(sp, se-sp, WCS_SEPCHS) != QSE_NULL) return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ do
+ {
+ if (__wcsxnfnmat(sp, se - sp, pp, pe - pp, flags, 1))
+ {
+ return 1;
+ }
+
+ if (WCS_ISSEPCH(*sp) &&
+ (flags & QSE_WCSFNMAT_PATHNAME)) break;
+
+ sp++;
+ }
+ while (sp < se);
+
+ return 0;
+ }
+ }
+ else if (pc == QSE_WT('['))
+ {
+ /* match range */
+ int negate = 0;
+ int matched = 0;
+
+ if ((++pp) >= pe) return 0;
+ if (*pp == QSE_WT('!')) { negate = 1; pp++; }
+
+ while (pp < pe && *pp != QSE_WT(']'))
+ {
+ if (*pp == QSE_WT('['))
+ {
+ qse_size_t pl = pe - pp;
+
+ if (pl >= 10)
+ {
+ if (qse_wcszcmp(pp, QSE_WT("[:xdigit:]"), 10) == 0)
+ {
+ matched = QSE_ISWXDIGIT(sc);
+ pp += 10; continue;
+ }
+ }
+
+ if (pl >= 9)
+ {
+ if (qse_wcszcmp(pp, QSE_WT("[:upper:]"), 9) == 0)
+ {
+ matched = QSE_ISWUPPER(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:lower:]"), 9) == 0)
+ {
+ matched = QSE_ISWLOWER(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:alpha:]"), 9) == 0)
+ {
+ matched = QSE_ISWALPHA(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:digit:]"), 9) == 0)
+ {
+ matched = QSE_ISWDIGIT(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:alnum:]"), 9) == 0)
+ {
+ matched = QSE_ISWALNUM(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:space:]"), 9) == 0)
+ {
+ matched = QSE_ISWSPACE(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:print:]"), 9) == 0)
+ {
+ matched = QSE_ISWPRINT(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:graph:]"), 9) == 0)
+ {
+ matched = QSE_ISWGRAPH(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:cntrl:]"), 9) == 0)
+ {
+ matched = QSE_ISWCNTRL(sc);
+ pp += 9; continue;
+ }
+ else if (qse_wcszcmp(pp, QSE_WT("[:punct:]"), 9) == 0)
+ {
+ matched = QSE_ISWPUNCT(sc);
+ pp += 9; continue;
+ }
+ }
+
+ /*
+ * characters in an invalid class name are
+ * just treated as normal characters
+ */
+ }
+
+ if (*pp == WCS_ESC &&
+ !(flags & QSE_WCSFNMAT_NOESCAPE)) pp++;
+ else if (*pp == QSE_WT(']')) break;
+
+ if (pp >= pe) break;
+
+ pc = *pp;
+ if ((flags & QSE_WCSFNMAT_IGNORECASE) != 0)
+ {
+ sc = QSE_TOWLOWER(sc);
+ pc = QSE_TOWLOWER(pc);
+ }
+
+ if (pp + 1 < pe && pp[1] == QSE_WT('-'))
+ {
+ pp += 2; /* move the a character next to a dash */
+
+ if (pp >= pe)
+ {
+ if (sc >= pc) matched = 1;
+ break;
+ }
+
+ if (*pp == WCS_ESC &&
+ !(flags & QSE_WCSFNMAT_NOESCAPE))
+ {
+ if ((++pp) >= pe)
+ {
+ if (sc >= pc) matched = 1;
+ break;
+ }
+ }
+ else if (*pp == QSE_WT(']'))
+ {
+ if (sc >= pc) matched = 1;
+ break;
+ }
+
+ pc2 = *pp;
+ if ((flags & QSE_WCSFNMAT_IGNORECASE) != 0)
+ pc2 = QSE_TOWLOWER(pc2);
+
+ if (sc >= pc && sc <= pc2) matched = 1;
+ pp++;
+ }
+ else
+ {
+ if (sc == pc) matched = 1;
+ pp++;
+ }
+ }
+
+ if (negate) matched = !matched;
+ if (!matched) return 0;
+ sp++; if (pp < pe) pp++;
+ }
+ else
+ {
+ /* a normal character */
+ if ((flags & QSE_WCSFNMAT_IGNORECASE) != 0)
+ {
+ sc = QSE_TOWLOWER(sc);
+ pc = QSE_TOWLOWER(pc);
+ }
+
+ if (sc != pc) return 0;
+ sp++; pp++;
+ }
+ }
+
+ /* will never reach here. but make some immature compilers happy... */
+ return 0;
+}
+
+int qse_wcsfnmat (const qse_wchar_t* str, const qse_wchar_t* ptn, int flags)
+{
+ return __wcsxnfnmat (
+ str, qse_wcslen(str), ptn, qse_wcslen(ptn), flags, 0);
+}
+
+int qse_wcsxfnmat (
+ const qse_wchar_t* str, qse_size_t slen, const qse_wchar_t* ptn, int flags)
+{
+ return __wcsxnfnmat (str, slen, ptn, qse_wcslen(ptn), flags, 0);
+}
+
+int qse_wcsnfnmat (
+ const qse_wchar_t* str, const qse_wchar_t* ptn, qse_size_t plen, int flags)
+{
+ return __wcsxnfnmat (str, qse_wcslen(str), ptn, plen, flags, 0);
+}
+
+int qse_wcsxnfnmat (
+ const qse_wchar_t* str, qse_size_t slen,
+ const qse_wchar_t* ptn, qse_size_t plen, int flags)
+{
+ return __wcsxnfnmat (str, slen, ptn, plen, flags, 0);
+}
diff --git a/qse/lib/cmn/str-pbrk.c b/qse/lib/cmn/str-pbrk.c
index 6f050467..a84130ed 100644
--- a/qse/lib/cmn/str-pbrk.c
+++ b/qse/lib/cmn/str-pbrk.c
@@ -1,5 +1,5 @@
/*
- * $Id: str-pbrk.c 556 2011-08-31 15:43:46Z hyunghwan.chung $
+ * $Id: str-pbrk.c 576 2011-09-23 14:52:22Z hyunghwan.chung $
*
Copyright 2006-2011 Chung, Hyung-Hwan.
This file is part of QSE.
@@ -35,6 +35,61 @@ qse_mchar_t* qse_mbspbrk (const qse_mchar_t* str1, const qse_mchar_t* str2)
return QSE_NULL;
}
+qse_mchar_t* qse_mbsxpbrk (
+ const qse_mchar_t* str1, qse_size_t len, const qse_mchar_t* str2)
+{
+ const qse_mchar_t* p1, * p2;
+ const qse_mchar_t* e1 = str1 + len;
+
+ for (p1 = str1; p1 < e1; p1++)
+ {
+ for (p2 = str2; *p2 != QSE_MT('\0'); p2++)
+ {
+ if (*p2 == *p1) return (qse_mchar_t*)p1;
+ }
+ }
+
+ return QSE_NULL;
+}
+
+
+qse_mchar_t* qse_mbsrpbrk (const qse_mchar_t* str1, const qse_mchar_t* str2)
+{
+ const qse_mchar_t* p1, * p2;
+
+ for (p1 = str1; *p1 != QSE_MT('\0'); p1++);
+
+ while (p1 > str1)
+ {
+ p1--;
+ for (p2 = str2; *p2 != QSE_MT('\0'); p2++)
+ {
+ if (*p2 == *p1) return (qse_mchar_t*)p1;
+ }
+ }
+
+ return QSE_NULL;
+}
+
+qse_mchar_t* qse_mbsxrpbrk (const qse_mchar_t* str1, qse_size_t len, const qse_mchar_t* str2)
+{
+ const qse_mchar_t* p1, * p2;
+
+ p1 = str1 + len;
+
+ while (p1 > str1)
+ {
+ p1--;
+ for (p2 = str2; *p2 != QSE_MT('\0'); p2++)
+ {
+ if (*p2 == *p1) return (qse_mchar_t*)p1;
+ }
+ }
+
+ return QSE_NULL;
+}
+
+
qse_wchar_t* qse_wcspbrk (const qse_wchar_t* str1, const qse_wchar_t* str2)
{
const qse_wchar_t* p1, * p2;
@@ -50,3 +105,56 @@ qse_wchar_t* qse_wcspbrk (const qse_wchar_t* str1, const qse_wchar_t* str2)
return QSE_NULL;
}
+qse_wchar_t* qse_wcsxpbrk (
+ const qse_wchar_t* str1, qse_size_t len, const qse_wchar_t* str2)
+{
+ const qse_wchar_t* p1, * p2;
+ const qse_wchar_t* e1 = str1 + len;
+
+ for (p1 = str1; p1 < e1; p1++)
+ {
+ for (p2 = str2; *p2 != QSE_WT('\0'); p2++)
+ {
+ if (*p2 == *p1) return (qse_wchar_t*)p1;
+ }
+ }
+
+ return QSE_NULL;
+}
+
+
+qse_wchar_t* qse_wcsrpbrk (const qse_wchar_t* str1, const qse_wchar_t* str2)
+{
+ const qse_wchar_t* p1, * p2;
+
+ for (p1 = str1; *p1 != QSE_WT('\0'); p1++);
+
+ while (p1 > str1)
+ {
+ p1--;
+ for (p2 = str2; *p2 != QSE_WT('\0'); p2++)
+ {
+ if (*p2 == *p1) return (qse_wchar_t*)p1;
+ }
+ }
+
+ return QSE_NULL;
+}
+
+qse_wchar_t* qse_wcsxrpbrk (const qse_wchar_t* str1, qse_size_t len, const qse_wchar_t* str2)
+{
+ const qse_wchar_t* p1, * p2;
+
+ p1 = str1 + len;
+
+ while (p1 > str1)
+ {
+ p1--;
+ for (p2 = str2; *p2 != QSE_WT('\0'); p2++)
+ {
+ if (*p2 == *p1) return (qse_wchar_t*)p1;
+ }
+ }
+
+ return QSE_NULL;
+}
diff --git a/qse/lib/sed/sed.c b/qse/lib/sed/sed.c
index 78b82acb..74058ea3 100644
--- a/qse/lib/sed/sed.c
+++ b/qse/lib/sed/sed.c
@@ -1,5 +1,5 @@
/*
- * $Id: sed.c 575 2011-09-22 07:07:18Z hyunghwan.chung $
+ * $Id: sed.c 576 2011-09-23 14:52:22Z hyunghwan.chung $
*
Copyright 2006-2011 Chung, Hyung-Hwan.
This file is part of QSE.
@@ -3241,6 +3241,8 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_fun_t inf, qse_sed_io_fun_t outf)
while (!sed->e.stopreq)
{
+ if (sed->e.hook) sed->e.hook (sed, QSE_SED_EXEC_READ, QSE_NULL);
+
n = read_line (sed, 0);
if (n <= -1) { ret = -1; goto done; }
if (n == 0) goto done;
@@ -3249,7 +3251,7 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_fun_t inf, qse_sed_io_fun_t outf)
{
/* the first command block contains at least 1 command
* to execute. an empty script like ' ' has no commands,
- * so this block is skipped. */
+ * so we execute no commands */
qse_sed_cmd_t* c, * j;
@@ -3258,6 +3260,8 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_fun_t inf, qse_sed_io_fun_t outf)
while (c != &sed->cmd.over)
{
+ if (sed->e.hook) sed->e.hook (sed, QSE_SED_EXEC_MATCH, c);
+
n = match_address (sed, c);
if (n <= -1) { ret = -1; goto done; }
@@ -3268,6 +3272,8 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_fun_t inf, qse_sed_io_fun_t outf)
continue;
}
+ if (sed->e.hook) sed->e.hook (sed, QSE_SED_EXEC_EXEC, c);
+
j = exec_cmd (sed, c);
if (j == QSE_NULL) { ret = -1; goto done; }
if (j == &sed->cmd.quit_quiet) goto done;
@@ -3284,6 +3290,7 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_fun_t inf, qse_sed_io_fun_t outf)
}
}
+ if (sed->e.hook) sed->e.hook (sed, QSE_SED_EXEC_WRITE, QSE_NULL);
if (emit_output (sed, 0) <= -1) { ret = -1; goto done; }
}
@@ -3327,3 +3334,13 @@ void qse_sed_setlinnum (qse_sed_t* sed, qse_size_t num)
{
sed->e.in.num = num;
}
+
+qse_sed_exec_hook_t qse_sed_getexechook (qse_sed_t* sed)
+{
+ return sed->e.hook;
+}
+
+void qse_sed_setexechook (qse_sed_t* sed, qse_sed_exec_hook_t hook)
+{
+ sed->e.hook = hook;
+}
diff --git a/qse/lib/sed/sed.h b/qse/lib/sed/sed.h
index a4c0f9f7..557a3bb2 100644
--- a/qse/lib/sed/sed.h
+++ b/qse/lib/sed/sed.h
@@ -1,5 +1,5 @@
/*
- * $Id: sed.h 572 2011-09-21 05:10:09Z hyunghwan.chung $
+ * $Id: sed.h 576 2011-09-23 14:52:22Z hyunghwan.chung $
*
Copyright 2006-2011 Chung, Hyung-Hwan.
This file is part of QSE.
@@ -27,7 +27,6 @@
#define QSE_MAP_AS_RBT
#include
-
/*
* Define USE_REX to use rex.h on behalf of tre.h
* rex.h currently does not support backreference.
@@ -45,7 +44,6 @@ typedef enum qse_sed_depth_t qse_sed_depth_t;
#define QSE_SED_CMD_QUIT QSE_T('q')
typedef struct qse_sed_adr_t qse_sed_adr_t;
-typedef struct qse_sed_cmd_t qse_sed_cmd_t;
typedef struct qse_sed_cmd_blk_t qse_sed_cmd_blk_t;
struct qse_sed_adr_t
@@ -274,6 +272,9 @@ struct qse_sed_t
/** stop requested */
int stopreq;
+
+ /** hook function */
+ qse_sed_exec_hook_t hook;
} e;
};
diff --git a/qse/samples/cmn/str.c b/qse/samples/cmn/str.c
index 29fbc630..45e312a6 100644
--- a/qse/samples/cmn/str.c
+++ b/qse/samples/cmn/str.c
@@ -586,6 +586,59 @@ static int test14 (void)
return 0;
}
+static int test15 (void)
+{
+ const qse_char_t* x = QSE_T("this is good");
+
+ qse_printf (QSE_T("[%s]\n"), qse_strpbrk (x, QSE_T("si")));
+ qse_printf (QSE_T("[%s]\n"), qse_strrpbrk (x, QSE_T("si")));
+ qse_printf (QSE_T("[%s]\n"), qse_strpbrk (x, QSE_T("d")));
+ qse_printf (QSE_T("[%s]\n"), qse_strrpbrk (x, QSE_T("d")));
+ qse_printf (QSE_T("[%s]\n"), qse_strpbrk (x, QSE_T("t")));
+ qse_printf (QSE_T("[%s]\n"), qse_strrpbrk (x, QSE_T("t")));
+ return 0;
+}
+
+static int test16 (void)
+{
+ const qse_char_t* ptn[] =
+ {
+ QSE_T("*.c"),
+ QSE_T("h??lo.???"),
+ QSE_T("[a-z]*.cpp")
+ };
+
+ const qse_char_t* name[] =
+ {
+ QSE_T("hello.c"),
+ QSE_T("hello.cpp"),
+ QSE_T("heLLo.Cpp"),
+ QSE_T("/tmp/hello.c"),
+ QSE_T("/tmp/Hello.c")
+ };
+
+ int i, j;
+
+
+ qse_printf (QSE_T("flags => 0\n"));
+ for (i = 0; i < QSE_COUNTOF(ptn); i++)
+ for (j = 0; j < QSE_COUNTOF(name); j++)
+ qse_printf (QSE_T("[%s] [%s] %d\n"), ptn[i], name[j], qse_strfnmat (name[j], ptn[i], 0));
+
+ qse_printf (QSE_T("flags => QSE_STRFNMAT_PATHNAME\n"));
+ for (i = 0; i < QSE_COUNTOF(ptn); i++)
+ for (j = 0; j < QSE_COUNTOF(name); j++)
+ qse_printf (QSE_T("[%s] [%s] %d\n"), ptn[i], name[j], qse_strfnmat (name[j], ptn[i], QSE_STRFNMAT_PATHNAME));
+
+ qse_printf (QSE_T("flags => QSE_STRFNMAT_PATHNAME | QSE_STRFNMAT_IGNORECASE\n"));
+ for (i = 0; i < QSE_COUNTOF(ptn); i++)
+ for (j = 0; j < QSE_COUNTOF(name); j++)
+ qse_printf (QSE_T("[%s] [%s] %d\n"), ptn[i], name[j], qse_strfnmat (name[j], ptn[i], QSE_STRFNMAT_PATHNAME | QSE_STRFNMAT_IGNORECASE));
+
+
+ return 0;
+}
+
int main ()
{
@@ -609,6 +662,8 @@ int main ()
R (test12);
R (test13);
R (test14);
+ R (test15);
+ R (test16);
return 0;
}