added qse_globmbs() and qse_globwcs()
This commit is contained in:
		| @ -35,12 +35,17 @@ | |||||||
|  * in a path name. |  * in a path name. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| typedef int (*qse_glob_cbimpl_t) ( | typedef int (*qse_glob_mbscbimpl_t) ( | ||||||
| 	const qse_cstr_t* path, | 	const qse_mcstr_t* path, | ||||||
| 	void*              cbctx | 	void*              cbctx | ||||||
| ); | ); | ||||||
|  |  | ||||||
| enum qse_glob_flags_t | typedef int (*qse_glob_wcscbimpl_t) ( | ||||||
|  | 	const qse_wcstr_t* path, | ||||||
|  | 	void*              cbctx | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | enum qse_glob_flag_t | ||||||
| { | { | ||||||
| 	/** Don't use the backslash as an escape charcter. | 	/** Don't use the backslash as an escape charcter. | ||||||
| 	 *  This option is on in Win32/OS2/DOS. */ | 	 *  This option is on in Win32/OS2/DOS. */ | ||||||
| @ -58,30 +63,58 @@ enum qse_glob_flags_t | |||||||
|  |  | ||||||
| 	/** Exclude special entries from matching.  | 	/** Exclude special entries from matching.  | ||||||
| 	  * Special entries include . and .. */ | 	  * Special entries include . and .. */ | ||||||
| 	QSE_GLOB_SKIPSPCDIR  = (1 << 4) | 	QSE_GLOB_SKIPSPCDIR  = (1 << 4), | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	  * bitsise-ORed of all valid enumerators | ||||||
|  | 	  */ | ||||||
|  | 	QSE_GLOB_ALL = (QSE_GLOB_NOESCAPE | QSE_GLOB_PERIOD | | ||||||
|  | 	                QSE_GLOB_IGNORECASE | QSE_GLOB_TOLERANT | | ||||||
|  | 	                QSE_GLOB_SKIPSPCDIR) | ||||||
| }; | }; | ||||||
|  | typedef enum qse_glob_flag_t qse_glob_flag_t; | ||||||
|  |  | ||||||
| #if defined(__cplusplus) | #if defined(__cplusplus) | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * The qse_glob() function finds path names matchin the \a pattern. |  * The qse_globmbs() function finds path names matchin the \a pattern. | ||||||
|  * It calls the call-back function \a cbimpl for each path name found. |  * It calls the call-back function \a cbimpl for each path name found. | ||||||
|  *  |  *  | ||||||
|  * \return -1 on failure, 0 on no match, 1 if matches are found. |  * \return -1 on failure, 0 on no match, 1 if matches are found. | ||||||
|  */ |  */ | ||||||
| QSE_EXPORT int qse_glob ( | QSE_EXPORT int qse_globmbs ( | ||||||
| 	const qse_char_t*  pattern, | 	const qse_mchar_t*   pattern, | ||||||
| 	qse_glob_cbimpl_t  cbimpl, | 	qse_glob_mbscbimpl_t cbimpl, | ||||||
| 	void*                cbctx, | 	void*                cbctx, | ||||||
| 	int                  flags, | 	int                  flags, | ||||||
| 	qse_mmgr_t*          mmgr, | 	qse_mmgr_t*          mmgr, | ||||||
| 	qse_cmgr_t*          cmgr | 	qse_cmgr_t*          cmgr | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | QSE_EXPORT int qse_globwcs ( | ||||||
|  | 	const qse_wchar_t*   pattern, | ||||||
|  | 	qse_glob_wcscbimpl_t cbimpl, | ||||||
|  | 	void*                cbctx, | ||||||
|  | 	int                  flags, | ||||||
|  | 	qse_mmgr_t*          mmgr, | ||||||
|  | 	qse_cmgr_t*          cmgr | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | #if defined(QSE_CHAR_IS_MCHAR) | ||||||
|  | 	typedef qse_glob_mbscbimpl_t qse_glob_cbimpl_t; | ||||||
|  | #	define qse_glob(pattern,cbimpl,cbctx,flags,mmgr,cmgr) qse_globmbs(pattern,cbimpl,cbctx,flags,mmgr,cmgr) | ||||||
|  | 	 | ||||||
|  | #else | ||||||
|  | 	typedef qse_glob_wcscbimpl_t qse_glob_cbimpl_t; | ||||||
|  | #	define qse_glob(pattern,cbimpl,cbctx,flags,mmgr,cmgr) qse_globwcs(pattern,cbimpl,cbctx,flags,mmgr,cmgr) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if defined(__cplusplus) | #if defined(__cplusplus) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | |||||||
| @ -50,6 +50,12 @@ enum qse_canonpath_flag_t | |||||||
| #	define QSE_ISPATHMBSEP(c) ((c) == QSE_MT('/') || (c) == QSE_MT('\\')) | #	define QSE_ISPATHMBSEP(c) ((c) == QSE_MT('/') || (c) == QSE_MT('\\')) | ||||||
| #	define QSE_ISPATHWCSEP(c) ((c) == QSE_WT('/') || (c) == QSE_WT('\\')) | #	define QSE_ISPATHWCSEP(c) ((c) == QSE_WT('/') || (c) == QSE_WT('\\')) | ||||||
|  |  | ||||||
|  | #else | ||||||
|  | #	define QSE_ISPATHMBSEP(c) ((c) == QSE_MT('/')) | ||||||
|  | #	define QSE_ISPATHWCSEP(c) ((c) == QSE_WT('/')) | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #define QSE_ISPATHMBDRIVE(s) \ | #define QSE_ISPATHMBDRIVE(s) \ | ||||||
| 	(((s[0] >= QSE_MT('A') && s[0] <= QSE_MT('Z')) || \ | 	(((s[0] >= QSE_MT('A') && s[0] <= QSE_MT('Z')) || \ | ||||||
| 	  (s[0] >= QSE_MT('a') && s[0] <= QSE_MT('z'))) && \ | 	  (s[0] >= QSE_MT('a') && s[0] <= QSE_MT('z'))) && \ | ||||||
| @ -59,13 +65,6 @@ enum qse_canonpath_flag_t | |||||||
| 	  (s[0] >= QSE_WT('a') && s[0] <= QSE_WT('z'))) && \ | 	  (s[0] >= QSE_WT('a') && s[0] <= QSE_WT('z'))) && \ | ||||||
| 	 s[1] == QSE_WT(':')) | 	 s[1] == QSE_WT(':')) | ||||||
|  |  | ||||||
| #else |  | ||||||
| #	define QSE_ISPATHMBSEP(c) ((c) == QSE_MT('/')) |  | ||||||
| #	define QSE_ISPATHWCSEP(c) ((c) == QSE_WT('/')) |  | ||||||
|  |  | ||||||
| 	/* QSE_ISPATHMBDRIVE() and QSE_ISPATHWCDRIVE() are not defined for this platform */ |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #define QSE_ISPATHMBSEPORNIL(c) (QSE_ISPATHMBSEP(c) || (c) == QSE_MT('\0')) | #define QSE_ISPATHMBSEPORNIL(c) (QSE_ISPATHMBSEP(c) || (c) == QSE_MT('\0')) | ||||||
| #define QSE_ISPATHWCSEPORNIL(c) (QSE_ISPATHWCSEP(c) || (c) == QSE_WT('\0')) | #define QSE_ISPATHWCSEPORNIL(c) (QSE_ISPATHWCSEP(c) || (c) == QSE_WT('\0')) | ||||||
|  |  | ||||||
|  | |||||||
| @ -3259,12 +3259,12 @@ QSE_EXPORT qse_size_t qse_wcs_fmt ( | |||||||
| ); | ); | ||||||
|  |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) | #if defined(QSE_CHAR_IS_MCHAR) | ||||||
| #	define qse_str_setmmgr(str,mmgr)    qse_mbs_wetmmgr(str,mmgr) |  | ||||||
| #	define qse_str_getmmgr(str)         qse_mbs_getmmgr(str) |  | ||||||
| #	define qse_str_open(mmgr,ext,capa)  qse_mbs_open(mmgr,ext,capa) | #	define qse_str_open(mmgr,ext,capa)  qse_mbs_open(mmgr,ext,capa) | ||||||
| #	define qse_str_close(str)           qse_mbs_close(str) | #	define qse_str_close(str)           qse_mbs_close(str) | ||||||
| #	define qse_str_init(str,mmgr,capa)  qse_mbs_init(str,mmgr,capa) | #	define qse_str_init(str,mmgr,capa)  qse_mbs_init(str,mmgr,capa) | ||||||
| #	define qse_str_fini(str)            qse_mbs_fini(str) | #	define qse_str_fini(str)            qse_mbs_fini(str) | ||||||
|  | #	define qse_str_setmmgr(str,mmgr)    qse_mbs_setmmgr(str,mmgr) | ||||||
|  | #	define qse_str_getmmgr(str)         qse_mbs_getmmgr(str) | ||||||
| #	define qse_str_yield(str,buf,ncapa) qse_mbs_yield(str,buf,ncapa) | #	define qse_str_yield(str,buf,ncapa) qse_mbs_yield(str,buf,ncapa) | ||||||
| #	define qse_str_yieldptr(str,ncapa)  qse_mbs_yieldptr(str,ncapa) | #	define qse_str_yieldptr(str,ncapa)  qse_mbs_yieldptr(str,ncapa) | ||||||
| #	define qse_str_getsizer(str)        qse_mbs_getsizer(str) | #	define qse_str_getsizer(str)        qse_mbs_getsizer(str) | ||||||
| @ -3291,12 +3291,12 @@ QSE_EXPORT qse_size_t qse_wcs_fmt ( | |||||||
| #	define qse_str_fmt                  qse_mbs_fmt | #	define qse_str_fmt                  qse_mbs_fmt | ||||||
| #	define qse_str_vfmt                 qse_mbs_vfmt | #	define qse_str_vfmt                 qse_mbs_vfmt | ||||||
| #else | #else | ||||||
| #	define qse_str_setmmgr(str,mmgr)    qse_wcs_wetmmgr(str,mmgr) |  | ||||||
| #	define qse_str_getmmgr(str)         qse_wcs_getmmgr(str) |  | ||||||
| #	define qse_str_open(mmgr,ext,capa)  qse_wcs_open(mmgr,ext,capa) | #	define qse_str_open(mmgr,ext,capa)  qse_wcs_open(mmgr,ext,capa) | ||||||
| #	define qse_str_close(str)           qse_wcs_close(str) | #	define qse_str_close(str)           qse_wcs_close(str) | ||||||
| #	define qse_str_init(str,mmgr,capa)  qse_wcs_init(str,mmgr,capa) | #	define qse_str_init(str,mmgr,capa)  qse_wcs_init(str,mmgr,capa) | ||||||
| #	define qse_str_fini(str)            qse_wcs_fini(str) | #	define qse_str_fini(str)            qse_wcs_fini(str) | ||||||
|  | #	define qse_str_setmmgr(str,mmgr)    qse_wcs_setmmgr(str,mmgr) | ||||||
|  | #	define qse_str_getmmgr(str)         qse_wcs_getmmgr(str) | ||||||
| #	define qse_str_yield(str,buf,ncapa) qse_wcs_yield(str,buf,ncapa) | #	define qse_str_yield(str,buf,ncapa) qse_wcs_yield(str,buf,ncapa) | ||||||
| #	define qse_str_yieldptr(str,ncapa)  qse_wcs_yieldptr(str,ncapa) | #	define qse_str_yieldptr(str,ncapa)  qse_wcs_yieldptr(str,ncapa) | ||||||
| #	define qse_str_getsizer(str)        qse_wcs_getsizer(str) | #	define qse_str_getsizer(str)        qse_wcs_getsizer(str) | ||||||
| @ -3324,7 +3324,6 @@ QSE_EXPORT qse_size_t qse_wcs_fmt ( | |||||||
| #	define qse_str_vfmt                 qse_wcs_vfmt | #	define qse_str_vfmt                 qse_wcs_vfmt | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(__cplusplus) | #if defined(__cplusplus) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ noinst_HEADERS = \ | |||||||
| 	fmt-intmax.h \ | 	fmt-intmax.h \ | ||||||
| 	fmt-out.h \ | 	fmt-out.h \ | ||||||
| 	fs.h \ | 	fs.h \ | ||||||
|  | 	glob.h \ | ||||||
| 	mem.h \ | 	mem.h \ | ||||||
| 	str-dyn.h \ | 	str-dyn.h \ | ||||||
| 	str-fcpy.h \ | 	str-fcpy.h \ | ||||||
|  | |||||||
| @ -397,6 +397,7 @@ noinst_HEADERS = \ | |||||||
| 	fmt-intmax.h \ | 	fmt-intmax.h \ | ||||||
| 	fmt-out.h \ | 	fmt-out.h \ | ||||||
| 	fs.h \ | 	fs.h \ | ||||||
|  | 	glob.h \ | ||||||
| 	mem.h \ | 	mem.h \ | ||||||
| 	str-dyn.h \ | 	str-dyn.h \ | ||||||
| 	str-fcpy.h \ | 	str-fcpy.h \ | ||||||
|  | |||||||
| @ -46,596 +46,158 @@ | |||||||
| #	include "syscall.h" | #	include "syscall.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #define NO_RECURSION 1 | ||||||
|  |  | ||||||
|  | enum segment_type_t | ||||||
|  | { | ||||||
|  | 	NONE, | ||||||
|  | 	ROOT, | ||||||
|  | 	NORMAL | ||||||
|  | }; | ||||||
|  | typedef enum segment_type_t segment_type_t; | ||||||
|  |  | ||||||
| #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) | #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) | ||||||
| 	/* i don't support escaping in these systems */ | 	/* i don't support escaping in these systems */ | ||||||
| #	define IS_ESC(c) (0) | #	define IS_ESC_MBS(c) (0) | ||||||
|  | #	define IS_ESC_WCS(c) (0) | ||||||
| #else | #else | ||||||
| #	define IS_ESC(c) ((c) == QSE_T('\\')) | #	define IS_ESC_MBS(c) ((c) == QSE_MT('\\')) | ||||||
|  | #	define IS_ESC_WCS(c) ((c) == QSE_WT('\\')) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #define IS_SEP(c) QSE_ISPATHSEP(c) | #define IS_NIL_MBS(c) ((c) == QSE_MT('\0')) | ||||||
|  | #define IS_NIL_WCS(c) ((c) == QSE_WT('\0')) | ||||||
| #define IS_NIL(c) ((c) == QSE_T('\0')) |  | ||||||
| #define IS_SEP_OR_NIL(c) (IS_SEP(c) || IS_NIL(c)) |  | ||||||
|  |  | ||||||
| /* only for win32/os2/dos */ |  | ||||||
| #define IS_DRIVE(s) \ |  | ||||||
|      (((s[0] >= QSE_T('A') && s[0] <= QSE_T('Z')) || \ |  | ||||||
|        (s[0] >= QSE_T('a') && s[0] <= QSE_T('z'))) && \ |  | ||||||
|       s[1] == QSE_T(':')) |  | ||||||
|  |  | ||||||
| /* this macro only checks for top-level wild-cards among these. | /* this macro only checks for top-level wild-cards among these. | ||||||
|  *  *, ?, [], !, -   |  *  *, ?, [], !, -   | ||||||
|  * see str-fnmat.c for more wild-card letters |  * see str-fnmat.c for more wild-card letters | ||||||
|  */ |  */ | ||||||
| #define IS_WILD(c) ((c) == QSE_T('*') || (c) == QSE_T('?') || (c) == QSE_T('[')) | #define IS_WILD_MBS(c) ((c) == QSE_MT('*') || (c) == QSE_MT('?') || (c) == QSE_MT('[')) | ||||||
|  | #define IS_WILD_WCS(c) ((c) == QSE_WT('*') || (c) == QSE_WT('?') || (c) == QSE_WT('[')) | ||||||
|  |  | ||||||
| #define NO_RECURSION 1 |  | ||||||
|  |  | ||||||
| #if defined(NO_RECURSION) |  | ||||||
| typedef struct stack_node_t stack_node_t; | /* -------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | #define glob qse_globmbs | ||||||
|  | #define cbimpl_t qse_glob_mbscbimpl_t | ||||||
|  | #define glob_t mbs_glob_t | ||||||
|  | #define segment_t mbs_segment_t | ||||||
|  | #define stack_node_t mbs_stack_node_t | ||||||
|  | #define char_t qse_mchar_t | ||||||
|  | #define cstr_t qse_mcstr_t | ||||||
|  | #define T(x) QSE_MT(x) | ||||||
|  | #define IS_ESC(x) IS_ESC_MBS(x) | ||||||
|  | #define IS_DRIVE(x) QSE_ISPATHMBDRIVE(x) | ||||||
|  | #define IS_SEP(x) QSE_ISPATHMBSEP(x) | ||||||
|  | #define IS_SEP_OR_NIL(x) QSE_ISPATHMBSEPORNIL(x) | ||||||
|  | #define IS_NIL(x) IS_NIL_MBS(x) | ||||||
|  | #define IS_WILD(x) IS_WILD_MBS(x) | ||||||
|  | #define str_t qse_mbs_t | ||||||
|  | #define str_open qse_mbs_open | ||||||
|  | #define str_close qse_mbs_close | ||||||
|  | #define str_init qse_mbs_init | ||||||
|  | #define str_fini qse_mbs_fini | ||||||
|  | #define str_cat qse_mbs_cat | ||||||
|  | #define str_ccat qse_mbs_ccat | ||||||
|  | #define str_ncat qse_mbs_ncat | ||||||
|  | #define str_setcapa qse_mbs_setcapa | ||||||
|  | #define str_setlen qse_mbs_setlen | ||||||
|  | #define STR_CAPA(x) QSE_MBS_CAPA(x) | ||||||
|  | #define STR_LEN(x) QSE_MBS_LEN(x) | ||||||
|  | #define STR_PTR(x) QSE_MBS_PTR(x) | ||||||
|  | #define STR_XSTR(x) QSE_MBS_XSTR(x) | ||||||
|  | #define STR_CPTR(x,y) QSE_MBS_CPTR(x,y) | ||||||
|  | #define strnfnmat qse_mbsnfnmat | ||||||
|  | #define DIR_CHAR_FLAGS QSE_DIR_MBSPATH | ||||||
|  | #define path_exists mbs_path_exists | ||||||
|  | #define search      mbs_search | ||||||
|  | #define get_next_segment mbs_get_next_segment | ||||||
|  | #define handle_non_wild_segments mbs_handle_non_wild_segments | ||||||
|  | #define CHAR_IS_MCHAR  | ||||||
|  | #undef DECLARE_MBUF | ||||||
|  | #include "glob.h" | ||||||
|  |  | ||||||
|  | /* -------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | #undef glob | ||||||
|  | #undef cbimpl_t | ||||||
|  | #undef glob_t | ||||||
|  | #undef segment_t | ||||||
|  | #undef stack_node_t | ||||||
|  | #undef char_t | ||||||
|  | #undef cstr_t | ||||||
|  | #undef T | ||||||
|  | #undef IS_ESC | ||||||
|  | #undef IS_DRIVE | ||||||
|  | #undef IS_SEP | ||||||
|  | #undef IS_SEP_OR_NIL | ||||||
|  | #undef IS_NIL | ||||||
|  | #undef IS_WILD | ||||||
|  | #undef str_t | ||||||
|  | #undef str_open | ||||||
|  | #undef str_close | ||||||
|  | #undef str_init | ||||||
|  | #undef str_fini | ||||||
|  | #undef str_cat | ||||||
|  | #undef str_ccat | ||||||
|  | #undef str_ncat | ||||||
|  | #undef str_setcapa | ||||||
|  | #undef str_setlen | ||||||
|  | #undef STR_CAPA | ||||||
|  | #undef STR_LEN | ||||||
|  | #undef STR_PTR | ||||||
|  | #undef STR_XSTR | ||||||
|  | #undef STR_CPTR | ||||||
|  | #undef strnfnmat | ||||||
|  | #undef DIR_CHAR_FLAGS | ||||||
|  | #undef path_exists | ||||||
|  | #undef search | ||||||
|  | #undef get_next_segment | ||||||
|  | #undef handle_non_wild_segments | ||||||
|  | #undef CHAR_IS_MCHAR  | ||||||
|  | #undef DECLARE_MBUF | ||||||
|  |  | ||||||
|  | /* -------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | #define glob qse_globwcs | ||||||
|  | #define cbimpl_t qse_glob_wcscbimpl_t | ||||||
|  | #define glob_t wcs_glob_t | ||||||
|  | #define segment_t wcs_segment_t | ||||||
|  | #define stack_node_t wcs_stack_node_t | ||||||
|  | #define char_t qse_wchar_t | ||||||
|  | #define cstr_t qse_wcstr_t | ||||||
|  | #define T(x) QSE_WT(x) | ||||||
|  | #define IS_ESC(x) IS_ESC_WCS(x) | ||||||
|  | #define IS_DRIVE(x) QSE_ISPATHWCDRIVE(x) | ||||||
|  | #define IS_SEP(x) QSE_ISPATHWCSEP(x) | ||||||
|  | #define IS_SEP_OR_NIL(x) QSE_ISPATHWCSEPORNIL(x) | ||||||
|  | #define IS_NIL(x) IS_NIL_WCS(x) | ||||||
|  | #define IS_WILD(x) IS_WILD_WCS(x) | ||||||
|  | #define str_t qse_wcs_t | ||||||
|  | #define str_open qse_wcs_open | ||||||
|  | #define str_close qse_wcs_close | ||||||
|  | #define str_init qse_wcs_init | ||||||
|  | #define str_fini qse_wcs_fini | ||||||
|  | #define str_cat qse_wcs_cat | ||||||
|  | #define str_ccat qse_wcs_ccat | ||||||
|  | #define str_ncat qse_wcs_ncat | ||||||
|  | #define str_setcapa qse_wcs_setcapa | ||||||
|  | #define str_setlen qse_wcs_setlen | ||||||
|  | #define STR_CAPA(x) QSE_WCS_CAPA(x) | ||||||
|  | #define STR_LEN(x) QSE_WCS_LEN(x) | ||||||
|  | #define STR_PTR(x) QSE_WCS_PTR(x) | ||||||
|  | #define STR_XSTR(x) QSE_WCS_XSTR(x) | ||||||
|  | #define STR_CPTR(x,y) QSE_WCS_CPTR(x,y) | ||||||
|  |  | ||||||
|  | #define strnfnmat qse_wcsnfnmat | ||||||
|  | #define DIR_CHAR_FLAGS QSE_DIR_WCSPATH | ||||||
|  | #define path_exists wcs_path_exists | ||||||
|  | #define search      wcs_search | ||||||
|  | #define get_next_segment wcs_get_next_segment | ||||||
|  | #define handle_non_wild_segments wcs_handle_non_wild_segments | ||||||
|  | #undef CHAR_IS_MCHAR  | ||||||
|  | #if !defined(_WIN32)  | ||||||
|  | #	define DECLARE_MBUF 1 | ||||||
| #endif | #endif | ||||||
|  | #include "glob.h" | ||||||
| struct glob_t |  | ||||||
| { |  | ||||||
| 	qse_glob_cbimpl_t cbimpl; |  | ||||||
| 	void* cbctx; |  | ||||||
|  |  | ||||||
| 	qse_mmgr_t* mmgr; |  | ||||||
| 	qse_cmgr_t* cmgr; |  | ||||||
| 	int flags; |  | ||||||
|  |  | ||||||
| 	qse_str_t path; |  | ||||||
| 	qse_str_t tbuf; /* temporary buffer */ |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) || defined(_WIN32) |  | ||||||
| 	/* nothing */ |  | ||||||
| #else |  | ||||||
| 	qse_mbs_t mbuf; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	int expanded; |  | ||||||
| 	int fnmat_flags; |  | ||||||
|  |  | ||||||
| #if defined(NO_RECURSION) |  | ||||||
| 	stack_node_t* stack; |  | ||||||
| 	stack_node_t* free; |  | ||||||
| #endif |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| typedef struct glob_t glob_t; |  | ||||||
|  |  | ||||||
| static qse_mchar_t* wcs_to_mbuf (glob_t* g, const qse_wchar_t* wcs, qse_mbs_t* mbs) |  | ||||||
| { |  | ||||||
| 	qse_size_t ml, wl; |  | ||||||
|  |  | ||||||
| 	if (qse_wcstombswithcmgr (wcs, &wl, QSE_NULL, &ml, g->cmgr) <= -1 || |  | ||||||
| 	    qse_mbs_setlen (mbs, ml) == (qse_size_t)-1) return QSE_NULL; |  | ||||||
|  |  | ||||||
| 	qse_wcstombswithcmgr (wcs, &wl, QSE_MBS_PTR(mbs), &ml, g->cmgr); |  | ||||||
| 	return QSE_MBS_PTR(mbs); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int path_exists (glob_t* g, const qse_char_t* name) |  | ||||||
| { |  | ||||||
| #if defined(_WIN32) |  | ||||||
|  |  | ||||||
| 	/* ------------------------------------------------------------------- */ |  | ||||||
| 	#if !defined(INVALID_FILE_ATTRIBUTES) |  | ||||||
| 	#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) |  | ||||||
| 	#endif |  | ||||||
| 	return (GetFileAttributes(name) != INVALID_FILE_ATTRIBUTES)? 1: 0; |  | ||||||
| 	/* ------------------------------------------------------------------- */ |  | ||||||
|  |  | ||||||
| #elif defined(__OS2__) |  | ||||||
|  |  | ||||||
| 	/* ------------------------------------------------------------------- */ |  | ||||||
| 	FILESTATUS3 fs; |  | ||||||
| 	APIRET rc; |  | ||||||
| 	const qse_mchar_t* mptr; |  | ||||||
|  |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) |  | ||||||
| 	mptr = name; |  | ||||||
| #else |  | ||||||
| 	mptr = wcs_to_mbuf (g, name, &g->mbuf); |  | ||||||
| 	if (mptr == QSE_NULL) return -1; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	rc = DosQueryPathInfo (mptr, FIL_STANDARD, &fs, QSE_SIZEOF(fs)); |  | ||||||
|  |  | ||||||
| 	return (rc == NO_ERROR)? 1: |  | ||||||
| 	       (rc == ERROR_PATH_NOT_FOUND)? 0: -1; |  | ||||||
| 	/* ------------------------------------------------------------------- */ |  | ||||||
|  |  | ||||||
| #elif defined(__DOS__) |  | ||||||
|  |  | ||||||
| 	/* ------------------------------------------------------------------- */ |  | ||||||
| 	unsigned int x, attr; |  | ||||||
| 	const qse_mchar_t* mptr; |  | ||||||
|  |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) |  | ||||||
| 	mptr = name; |  | ||||||
| #else |  | ||||||
| 	mptr = wcs_to_mbuf (g, name, &g->mbuf); |  | ||||||
| 	if (mptr == QSE_NULL) return -1; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	x = _dos_getfileattr (mptr, &attr); |  | ||||||
| 	return (x == 0)? 1:  |  | ||||||
| 	       (errno == ENOENT)? 0: -1; |  | ||||||
| 	/* ------------------------------------------------------------------- */ |  | ||||||
|  |  | ||||||
| #elif defined(macintosh) |  | ||||||
| 	HFileInfo fpb; |  | ||||||
| 	const qse_mchar_t* mptr; |  | ||||||
|  |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) |  | ||||||
| 	mptr = name; |  | ||||||
| #else |  | ||||||
| 	mptr = wcs_to_mbuf (g, name, &g->mbuf); |  | ||||||
| 	if (mptr == QSE_NULL) return -1; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	QSE_MEMSET (&fpb, 0, QSE_SIZEOF(fpb)); |  | ||||||
| 	fpb.ioNamePtr = (unsigned char*)mptr; |  | ||||||
| 	 |  | ||||||
| 	return (PBGetCatInfoSync ((CInfoPBRec*)&fpb) == noErr)? 1: 0; |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| 	/* ------------------------------------------------------------------- */ |  | ||||||
| #if defined(HAVE_LSTAT) |  | ||||||
| 	qse_lstat_t st; |  | ||||||
| #else |  | ||||||
| 	qse_stat_t st; |  | ||||||
| #endif |  | ||||||
| 	const qse_mchar_t* mptr; |  | ||||||
|  |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) |  | ||||||
| 	mptr = name; |  | ||||||
| #else |  | ||||||
| 	mptr = wcs_to_mbuf (g, name, &g->mbuf); |  | ||||||
| 	if (mptr == QSE_NULL) return -1; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(HAVE_LSTAT) |  | ||||||
| 	return (QSE_LSTAT (mptr, &st) <= -1)? 0: 1; |  | ||||||
| #else |  | ||||||
| 	/* use stat() if no lstat() is available. */ |  | ||||||
| 	return (QSE_STAT (mptr, &st) <= -1)? 0: 1; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	/* ------------------------------------------------------------------- */ |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| struct segment_t |  | ||||||
| { |  | ||||||
| 	enum |  | ||||||
| 	{ |  | ||||||
| 		NONE, |  | ||||||
| 		ROOT, |  | ||||||
| 		NORMAL |  | ||||||
| 	} type; |  | ||||||
|  |  | ||||||
| 	const qse_char_t* ptr; |  | ||||||
| 	qse_size_t        len; |  | ||||||
|  |  | ||||||
| 	qse_char_t sep; /* preceeding separator */ |  | ||||||
| 	unsigned int wild: 1;  /* indicate that it contains wildcards */ |  | ||||||
| 	unsigned int esc: 1;  /* indicate that it contains escaped letters */ |  | ||||||
| 	unsigned int next: 1;  /* indicate that it has the following segment */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| typedef struct segment_t segment_t; |  | ||||||
|  |  | ||||||
| static int get_next_segment (glob_t* g, segment_t* seg) |  | ||||||
| { |  | ||||||
| 	if (seg->type == NONE) |  | ||||||
| 	{ |  | ||||||
| 		/* seg->ptr must point to the beginning of the pattern |  | ||||||
| 		 * and seg->len must be zero when seg->type is NONE. */ |  | ||||||
| 		if (IS_NIL(seg->ptr[0])) |  | ||||||
| 		{ |  | ||||||
| 			/* nothing to do */ |  | ||||||
| 		} |  | ||||||
| 		else if (IS_SEP(seg->ptr[0])) |  | ||||||
| 		{ |  | ||||||
| 			seg->type = ROOT; |  | ||||||
| 			seg->len = 1; |  | ||||||
| 			seg->next = IS_NIL(seg->ptr[1])? 0: 1; |  | ||||||
| 			seg->sep = QSE_T('\0'); |  | ||||||
| 			seg->wild = 0; |  | ||||||
| 			seg->esc = 0; |  | ||||||
| 		} |  | ||||||
| 	#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) |  | ||||||
| 		else if (IS_DRIVE(seg->ptr)) |  | ||||||
| 		{ |  | ||||||
| 			seg->type = ROOT; |  | ||||||
| 			seg->len = 2; |  | ||||||
| 			if (IS_SEP(seg->ptr[2])) seg->len++; |  | ||||||
| 			seg->next = IS_NIL(seg->ptr[seg->len])? 0: 1; |  | ||||||
| 			seg->sep = QSE_T('\0'); |  | ||||||
| 			seg->wild = 0; |  | ||||||
| 			seg->esc = 0; |  | ||||||
| 		} |  | ||||||
| 	#endif |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			int escaped = 0; |  | ||||||
| 			seg->type = NORMAL; |  | ||||||
| 			seg->sep = QSE_T('\0'); |  | ||||||
| 			seg->wild = 0; |  | ||||||
| 			seg->esc = 0; |  | ||||||
| 			do |  | ||||||
| 			{ |  | ||||||
| 				if (escaped) escaped = 0; |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					if (IS_ESC(seg->ptr[seg->len]))  |  | ||||||
| 					{ |  | ||||||
| 						escaped = 1; |  | ||||||
| 						seg->esc = 1; |  | ||||||
| 					} |  | ||||||
| 					else if (IS_WILD(seg->ptr[seg->len])) seg->wild = 1; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				seg->len++; |  | ||||||
| 			} |  | ||||||
| 			while (!IS_SEP_OR_NIL(seg->ptr[seg->len])); |  | ||||||
| 			seg->next = IS_NIL(seg->ptr[seg->len])? 0: 1; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	else if (seg->type == ROOT) |  | ||||||
| 	{ |  | ||||||
| 		int escaped = 0; |  | ||||||
| 		seg->type = NORMAL; |  | ||||||
| 		seg->ptr = &seg->ptr[seg->len]; |  | ||||||
| 		seg->len = 0; |  | ||||||
| 		seg->sep = QSE_T('\0'); |  | ||||||
| 		seg->wild = 0; |  | ||||||
| 		seg->esc = 0; |  | ||||||
|  |  | ||||||
| 		while (!IS_SEP_OR_NIL(seg->ptr[seg->len]))  |  | ||||||
| 		{ |  | ||||||
| 			if (escaped) escaped = 0; |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				if (IS_ESC(seg->ptr[seg->len]))  |  | ||||||
| 				{ |  | ||||||
| 					escaped = 1; |  | ||||||
| 					seg->esc = 1; |  | ||||||
| 				} |  | ||||||
| 				else if (IS_WILD(seg->ptr[seg->len])) seg->wild = 1; |  | ||||||
| 			} |  | ||||||
| 			seg->len++; |  | ||||||
| 		} |  | ||||||
| 		seg->next = IS_NIL(seg->ptr[seg->len])? 0: 1; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		QSE_ASSERT (seg->type == NORMAL); |  | ||||||
|  |  | ||||||
| 		seg->ptr = &seg->ptr[seg->len + 1]; |  | ||||||
| 		seg->len = 0; |  | ||||||
| 		seg->wild = 0; |  | ||||||
| 		seg->esc = 0; |  | ||||||
| 		if (IS_NIL(seg->ptr[-1]))  |  | ||||||
| 		{ |  | ||||||
| 			seg->type = NONE; |  | ||||||
| 			seg->next = 0; |  | ||||||
| 			seg->sep = QSE_T('\0'); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			int escaped = 0; |  | ||||||
| 			seg->sep = seg->ptr[-1]; |  | ||||||
| 			while (!IS_SEP_OR_NIL(seg->ptr[seg->len]))  |  | ||||||
| 			{ |  | ||||||
| 				if (escaped) escaped = 0; |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					if (IS_ESC(seg->ptr[seg->len]))  |  | ||||||
| 					{ |  | ||||||
| 						escaped = 1; |  | ||||||
| 						seg->esc = 1; |  | ||||||
| 					} |  | ||||||
| 					else if (IS_WILD(seg->ptr[seg->len])) seg->wild = 1; |  | ||||||
| 				} |  | ||||||
| 				seg->len++; |  | ||||||
| 			} |  | ||||||
| 			seg->next = IS_NIL(seg->ptr[seg->len])? 0: 1; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return seg->type; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int handle_non_wild_segments (glob_t* g, segment_t* seg) |  | ||||||
| { |  | ||||||
| 	while (get_next_segment(g, seg) != NONE && !seg->wild) |  | ||||||
| 	{ |  | ||||||
| 		QSE_ASSERT (seg->type != NONE && !seg->wild); |  | ||||||
|  |  | ||||||
| 		if (seg->sep && qse_str_ccat (&g->path, seg->sep) == (qse_size_t)-1) return -1; |  | ||||||
| 		if (seg->esc) |  | ||||||
| 		{ |  | ||||||
| 			/* if the segment contains escape sequences, |  | ||||||
| 			 * strip the escape letters off the segment */ |  | ||||||
|  |  | ||||||
| 			qse_cstr_t tmp; |  | ||||||
| 			qse_size_t i; |  | ||||||
| 			int escaped = 0; |  | ||||||
|  |  | ||||||
| 			if (QSE_STR_CAPA(&g->tbuf) < seg->len && |  | ||||||
| 			    qse_str_setcapa (&g->tbuf, seg->len) == (qse_size_t)-1) return -1; |  | ||||||
|  |  | ||||||
| 			tmp.ptr = QSE_STR_PTR(&g->tbuf); |  | ||||||
| 			tmp.len = 0; |  | ||||||
|  |  | ||||||
| 			/* the following loop drops the last character  |  | ||||||
| 			 * if it is the escape character */ |  | ||||||
| 			for (i = 0; i < seg->len; i++) |  | ||||||
| 			{ |  | ||||||
| 				if (escaped) |  | ||||||
| 				{ |  | ||||||
| 					escaped = 0; |  | ||||||
| 					tmp.ptr[tmp.len++] = seg->ptr[i]; |  | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					if (IS_ESC(seg->ptr[i]))  |  | ||||||
| 						escaped = 1; |  | ||||||
| 					else |  | ||||||
| 						tmp.ptr[tmp.len++] = seg->ptr[i]; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (qse_str_ncat (&g->path, tmp.ptr, tmp.len) == (qse_size_t)-1) return -1; |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			/* if the segmetn doesn't contain escape sequences, |  | ||||||
| 			 * append the segment to the path without special handling */ |  | ||||||
| 			if (qse_str_ncat (&g->path, seg->ptr, seg->len) == (qse_size_t)-1) return -1; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (!seg->next && path_exists(g, QSE_STR_PTR(&g->path)) > 0) |  | ||||||
| 		{ |  | ||||||
| 			/* reached the last segment. match if the path exists */ |  | ||||||
| 			if (g->cbimpl (QSE_STR_XSTR(&g->path), g->cbctx) <= -1) return -1; |  | ||||||
| 			g->expanded = 1; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #if defined(NO_RECURSION) |  | ||||||
| struct stack_node_t |  | ||||||
| { |  | ||||||
| 	qse_size_t tmp; |  | ||||||
| 	qse_size_t tmp2; |  | ||||||
| 	qse_dir_t* dp; |  | ||||||
| 	segment_t seg; |  | ||||||
|  |  | ||||||
| 	stack_node_t* next; |  | ||||||
| }; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| static int search (glob_t* g, segment_t* seg) |  | ||||||
| { |  | ||||||
| 	qse_dir_t* dp; |  | ||||||
| 	qse_size_t tmp, tmp2; |  | ||||||
| 	qse_dir_ent_t ent; |  | ||||||
| 	int x; |  | ||||||
|  |  | ||||||
| #if defined(NO_RECURSION) |  | ||||||
| 	stack_node_t* r; |  | ||||||
|  |  | ||||||
| entry: |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	dp = QSE_NULL; |  | ||||||
|  |  | ||||||
| 	if (handle_non_wild_segments (g, seg) <= -1) goto oops; |  | ||||||
|  |  | ||||||
| 	if (seg->wild) |  | ||||||
| 	{ |  | ||||||
| 		int dir_flags = 0; |  | ||||||
| 		if (g->flags & QSE_GLOB_SKIPSPCDIR) dir_flags |= QSE_DIR_SKIPSPCDIR; |  | ||||||
|  |  | ||||||
| 		dp = qse_dir_open ( |  | ||||||
| 			g->mmgr, 0, QSE_STR_PTR(&g->path), |  | ||||||
| 			dir_flags, QSE_NULL); |  | ||||||
| 		if (dp) |  | ||||||
| 		{ |  | ||||||
| 			tmp = QSE_STR_LEN(&g->path); |  | ||||||
|  |  | ||||||
| 			if (seg->sep && qse_str_ccat (&g->path, seg->sep) == (qse_size_t)-1) goto oops; |  | ||||||
| 			tmp2 = QSE_STR_LEN(&g->path); |  | ||||||
|  |  | ||||||
| 			while (1) |  | ||||||
| 			{ |  | ||||||
| 				qse_str_setlen (&g->path, tmp2); |  | ||||||
|  |  | ||||||
| 				x = qse_dir_read (dp, &ent); |  | ||||||
| 				if (x <= -1)  |  | ||||||
| 				{ |  | ||||||
| 					if (g->flags & QSE_GLOB_TOLERANT) break; |  | ||||||
| 					else goto oops; |  | ||||||
| 				} |  | ||||||
| 				if (x == 0) break; |  | ||||||
|  |  | ||||||
| 				if (qse_str_cat (&g->path, ent.name) == (qse_size_t)-1) goto oops; |  | ||||||
|  |  | ||||||
| 				if (qse_strnfnmat (QSE_STR_CPTR(&g->path,tmp2), seg->ptr, seg->len, g->fnmat_flags) > 0) |  | ||||||
| 				{ |  | ||||||
| 					if (seg->next) |  | ||||||
| 					{ |  | ||||||
| 				#if defined(NO_RECURSION) |  | ||||||
| 						if (g->free)  |  | ||||||
| 						{ |  | ||||||
| 							r = g->free; |  | ||||||
| 							g->free = r->next; |  | ||||||
| 						} |  | ||||||
| 						else |  | ||||||
| 						{ |  | ||||||
| 							r = QSE_MMGR_ALLOC (g->mmgr, QSE_SIZEOF(*r)); |  | ||||||
| 							if (r == QSE_NULL) goto oops; |  | ||||||
| 						} |  | ||||||
| 						 |  | ||||||
| 						/* push key variables that must be restored  |  | ||||||
| 						 * into the stack. */ |  | ||||||
| 						r->tmp = tmp; |  | ||||||
| 						r->tmp2 = tmp2; |  | ||||||
| 						r->dp = dp; |  | ||||||
| 						r->seg = *seg; |  | ||||||
|  |  | ||||||
| 						r->next = g->stack; |  | ||||||
| 						g->stack = r; |  | ||||||
|  |  | ||||||
| 						/* move to the function entry point as if |  | ||||||
| 						 * a recursive call has been made */ |  | ||||||
| 						goto entry; |  | ||||||
|  |  | ||||||
| 					resume: |  | ||||||
| 						; |  | ||||||
|  |  | ||||||
| 				#else |  | ||||||
| 						segment_t save; |  | ||||||
| 						int x; |  | ||||||
|  |  | ||||||
| 						save = *seg; |  | ||||||
| 						x = search (g, seg); |  | ||||||
| 						*seg = save; |  | ||||||
| 						if (x <= -1) goto oops; |  | ||||||
| 				#endif |  | ||||||
| 					} |  | ||||||
| 					else |  | ||||||
| 					{ |  | ||||||
| 						if (g->cbimpl (QSE_STR_XSTR(&g->path), g->cbctx) <= -1) goto oops; |  | ||||||
| 						g->expanded = 1; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			qse_str_setlen (&g->path, tmp); |  | ||||||
| 			qse_dir_close (dp); dp = QSE_NULL; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	QSE_ASSERT (dp == QSE_NULL); |  | ||||||
|  |  | ||||||
| #if defined(NO_RECURSION) |  | ||||||
| 	if (g->stack) |  | ||||||
| 	{ |  | ||||||
| 		/* the stack is not empty. the emulated recusive call |  | ||||||
| 		 * must have been made. restore the variables pushed |  | ||||||
| 		 * and jump to the resumption point */ |  | ||||||
| 		r = g->stack; |  | ||||||
| 		g->stack = r->next; |  | ||||||
|  |  | ||||||
| 		tmp = r->tmp; |  | ||||||
| 		tmp2 = r->tmp2; |  | ||||||
| 		dp = r->dp; |  | ||||||
| 		*seg = r->seg; |  | ||||||
|  |  | ||||||
| 		/* link the stack node to the free list  |  | ||||||
| 		 * instead of freeing it here */ |  | ||||||
| 		r->next = g->free; |  | ||||||
| 		g->free = r; |  | ||||||
|  |  | ||||||
| 		goto resume; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	while (g->free) |  | ||||||
| 	{ |  | ||||||
| 		/* destory the free list */ |  | ||||||
| 		r = g->free; |  | ||||||
| 		g->free = r->next; |  | ||||||
| 		QSE_MMGR_FREE (g->mmgr, r); |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	return 0; |  | ||||||
|  |  | ||||||
| oops: |  | ||||||
| 	if (dp) qse_dir_close (dp); |  | ||||||
|  |  | ||||||
| #if defined(NO_RECURSION) |  | ||||||
| 	while (g->stack) |  | ||||||
| 	{ |  | ||||||
| 		r = g->stack; |  | ||||||
| 		g->stack = r->next; |  | ||||||
| 		qse_dir_close (r->dp); |  | ||||||
| 		QSE_MMGR_FREE (g->mmgr, r); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	while (g->free) |  | ||||||
| 	{ |  | ||||||
| 		r = g->stack; |  | ||||||
| 		g->free = r->next; |  | ||||||
| 		QSE_MMGR_FREE (g->mmgr, r); |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
| 	return -1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int qse_glob (const qse_char_t* pattern, qse_glob_cbimpl_t cbimpl, void* cbctx, int flags, qse_mmgr_t* mmgr, qse_cmgr_t* cmgr) |  | ||||||
| { |  | ||||||
| 	segment_t seg; |  | ||||||
| 	glob_t g; |  | ||||||
| 	int x; |  | ||||||
|  |  | ||||||
| 	QSE_MEMSET (&g, 0, QSE_SIZEOF(g)); |  | ||||||
| 	g.cbimpl = cbimpl; |  | ||||||
| 	g.cbctx = cbctx; |  | ||||||
| 	g.mmgr = mmgr; |  | ||||||
| 	g.cmgr = cmgr; |  | ||||||
| 	g.flags = flags; |  | ||||||
|  |  | ||||||
| #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) |  | ||||||
| 	g.fnmat_flags |= QSE_STRFNMAT_IGNORECASE; |  | ||||||
| 	g.fnmat_flags |= QSE_STRFNMAT_NOESCAPE; |  | ||||||
| #else |  | ||||||
| 	if (flags & QSE_GLOB_IGNORECASE) g.fnmat_flags |= QSE_STRFNMAT_IGNORECASE; |  | ||||||
| 	if (flags & QSE_GLOB_NOESCAPE) g.fnmat_flags |= QSE_STRFNMAT_NOESCAPE; |  | ||||||
| #endif |  | ||||||
| 	if (flags & QSE_GLOB_PERIOD) g.fnmat_flags |= QSE_STRFNMAT_PERIOD; |  | ||||||
|  |  | ||||||
| 	if (qse_str_init (&g.path, mmgr, 512) <= -1) return -1; |  | ||||||
| 	if (qse_str_init (&g.tbuf, mmgr, 256) <= -1)  |  | ||||||
| 	{ |  | ||||||
| 		qse_str_fini (&g.path); |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) || defined(_WIN32) |  | ||||||
| 	/* nothing */ |  | ||||||
| #else |  | ||||||
| 	if (qse_mbs_init (&g.mbuf, mmgr, 512) <= -1)  |  | ||||||
| 	{ |  | ||||||
| 		qse_str_fini (&g.path); |  | ||||||
| 		qse_str_fini (&g.path); |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	QSE_MEMSET (&seg, 0, QSE_SIZEOF(seg)); |  | ||||||
| 	seg.type = NONE; |  | ||||||
| 	seg.ptr = pattern; |  | ||||||
| 	seg.len = 0; |  | ||||||
|  |  | ||||||
| 	x = search (&g, &seg); |  | ||||||
|  |  | ||||||
| #if defined(QSE_CHAR_IS_MCHAR) || defined(_WIN32) |  | ||||||
| 	/* nothing */ |  | ||||||
| #else |  | ||||||
| 	qse_mbs_fini (&g.mbuf); |  | ||||||
| #endif |  | ||||||
| 	qse_str_fini (&g.tbuf); |  | ||||||
| 	qse_str_fini (&g.path); |  | ||||||
|  |  | ||||||
| 	if (x <= -1) return -1; |  | ||||||
| 	return g.expanded; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										590
									
								
								qse/lib/cmn/glob.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										590
									
								
								qse/lib/cmn/glob.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,590 @@ | |||||||
|  | /* | ||||||
|  |  * $Id$ | ||||||
|  |  * | ||||||
|  |     Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. | ||||||
|  |  | ||||||
|  |     Redistribution and use in source and binary forms, with or without | ||||||
|  |     modification, are permitted provided that the following conditions | ||||||
|  |     are met: | ||||||
|  |     1. Redistributions of source code must retain the above copyright | ||||||
|  |        notice, this list of conditions and the following disclaimer. | ||||||
|  |     2. Redistributions in binary form must reproduce the above copyright | ||||||
|  |        notice, this list of conditions and the following disclaimer in the | ||||||
|  |        documentation and/or other materials provided with the distribution. | ||||||
|  |  | ||||||
|  |     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | ||||||
|  |     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||||
|  |     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||||
|  |     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||||
|  |     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||||
|  |     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  |     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  |     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  |     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||||
|  |     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if defined(NO_RECURSION) | ||||||
|  | typedef struct stack_node_t stack_node_t; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | struct glob_t | ||||||
|  | { | ||||||
|  | 	cbimpl_t cbimpl; | ||||||
|  | 	void* cbctx; | ||||||
|  |  | ||||||
|  | 	qse_mmgr_t* mmgr; | ||||||
|  | 	qse_cmgr_t* cmgr; | ||||||
|  | 	int flags; | ||||||
|  |  | ||||||
|  | 	str_t path; | ||||||
|  | 	str_t tbuf; /* temporary buffer */ | ||||||
|  |  | ||||||
|  | #if defined(DECLARE_MBUF) | ||||||
|  | 	qse_mbs_t mbuf; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	int expanded; | ||||||
|  | 	int fnmat_flags; | ||||||
|  |  | ||||||
|  | #if defined(NO_RECURSION) | ||||||
|  | 	stack_node_t* stack; | ||||||
|  | 	stack_node_t* free; | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef struct glob_t glob_t; | ||||||
|  |  | ||||||
|  | struct segment_t | ||||||
|  | { | ||||||
|  | 	segment_type_t type; | ||||||
|  |  | ||||||
|  | 	const char_t* ptr; | ||||||
|  | 	qse_size_t    len; | ||||||
|  |  | ||||||
|  | 	char_t sep; /* preceeding separator */ | ||||||
|  | 	unsigned int wild: 1;  /* indicate that it contains wildcards */ | ||||||
|  | 	unsigned int esc: 1;  /* indicate that it contains escaped letters */ | ||||||
|  | 	unsigned int next: 1;  /* indicate that it has the following segment */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef struct segment_t segment_t; | ||||||
|  |  | ||||||
|  | #if defined(NO_RECURSION) | ||||||
|  | struct stack_node_t | ||||||
|  | { | ||||||
|  | 	qse_size_t tmp; | ||||||
|  | 	qse_size_t tmp2; | ||||||
|  | 	qse_dir_t* dp; | ||||||
|  | 	segment_t seg; | ||||||
|  |  | ||||||
|  | 	stack_node_t* next; | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(DECLARE_MBUF) | ||||||
|  | static qse_mchar_t* wcs_to_mbuf (glob_t* g, const qse_wchar_t* wcs, qse_mbs_t* mbs) | ||||||
|  | { | ||||||
|  | 	qse_size_t ml, wl; | ||||||
|  |  | ||||||
|  | 	if (qse_wcstombswithcmgr (wcs, &wl, QSE_NULL, &ml, g->cmgr) <= -1 || | ||||||
|  | 	    qse_mbs_setlen (mbs, ml) == (qse_size_t)-1) return QSE_NULL; | ||||||
|  |  | ||||||
|  | 	qse_wcstombswithcmgr (wcs, &wl, QSE_MBS_PTR(mbs), &ml, g->cmgr); | ||||||
|  | 	return QSE_MBS_PTR(mbs); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static int path_exists (glob_t* g, const char_t* name) | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) | ||||||
|  |  | ||||||
|  | 	/* ------------------------------------------------------------------- */ | ||||||
|  | 	#if !defined(INVALID_FILE_ATTRIBUTES) | ||||||
|  | 	#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) | ||||||
|  | 	#endif | ||||||
|  | 	#if defined(CHAR_IS_MCHAR) | ||||||
|  | 	return (GetFileAttributesA(name) != INVALID_FILE_ATTRIBUTES)? 1: 0; | ||||||
|  | 	#else | ||||||
|  | 	return (GetFileAttributesW(name) != INVALID_FILE_ATTRIBUTES)? 1: 0; | ||||||
|  | 	#endif | ||||||
|  | 	/* ------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | #elif defined(__OS2__) | ||||||
|  |  | ||||||
|  | 	/* ------------------------------------------------------------------- */ | ||||||
|  | 	FILESTATUS3 fs; | ||||||
|  | 	APIRET rc; | ||||||
|  | 	const qse_mchar_t* mptr; | ||||||
|  |  | ||||||
|  | #if defined(CHAR_IS_MCHAR) | ||||||
|  | 	mptr = name; | ||||||
|  | #else | ||||||
|  | 	mptr = wcs_to_mbuf (g, name, &g->mbuf); | ||||||
|  | 	if (mptr == QSE_NULL) return -1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	rc = DosQueryPathInfo (mptr, FIL_STANDARD, &fs, QSE_SIZEOF(fs)); | ||||||
|  |  | ||||||
|  | 	return (rc == NO_ERROR)? 1: | ||||||
|  | 	       (rc == ERROR_PATH_NOT_FOUND)? 0: -1; | ||||||
|  | 	/* ------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | #elif defined(__DOS__) | ||||||
|  |  | ||||||
|  | 	/* ------------------------------------------------------------------- */ | ||||||
|  | 	unsigned int x, attr; | ||||||
|  | 	const qse_mchar_t* mptr; | ||||||
|  |  | ||||||
|  | #if defined(CHAR_IS_MCHAR) | ||||||
|  | 	mptr = name; | ||||||
|  | #else | ||||||
|  | 	mptr = wcs_to_mbuf (g, name, &g->mbuf); | ||||||
|  | 	if (mptr == QSE_NULL) return -1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	x = _dos_getfileattr (mptr, &attr); | ||||||
|  | 	return (x == 0)? 1:  | ||||||
|  | 	       (errno == ENOENT)? 0: -1; | ||||||
|  | 	/* ------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | #elif defined(macintosh) | ||||||
|  | 	HFileInfo fpb; | ||||||
|  | 	const qse_mchar_t* mptr; | ||||||
|  |  | ||||||
|  | #if defined(CHAR_IS_MCHAR) | ||||||
|  | 	mptr = name; | ||||||
|  | #else | ||||||
|  | 	mptr = wcs_to_mbuf (g, name, &g->mbuf); | ||||||
|  | 	if (mptr == QSE_NULL) return -1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	QSE_MEMSET (&fpb, 0, QSE_SIZEOF(fpb)); | ||||||
|  | 	fpb.ioNamePtr = (unsigned char*)mptr; | ||||||
|  | 	 | ||||||
|  | 	return (PBGetCatInfoSync ((CInfoPBRec*)&fpb) == noErr)? 1: 0; | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | 	/* ------------------------------------------------------------------- */ | ||||||
|  | #if defined(HAVE_LSTAT) | ||||||
|  | 	qse_lstat_t st; | ||||||
|  | #else | ||||||
|  | 	qse_stat_t st; | ||||||
|  | #endif | ||||||
|  | 	const qse_mchar_t* mptr; | ||||||
|  |  | ||||||
|  | #if defined(CHAR_IS_MCHAR) | ||||||
|  | 	mptr = name; | ||||||
|  | #else | ||||||
|  | 	mptr = wcs_to_mbuf (g, name, &g->mbuf); | ||||||
|  | 	if (mptr == QSE_NULL) return -1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(HAVE_LSTAT) | ||||||
|  | 	return (QSE_LSTAT (mptr, &st) <= -1)? 0: 1; | ||||||
|  | #else | ||||||
|  | 	/* use stat() if no lstat() is available. */ | ||||||
|  | 	return (QSE_STAT (mptr, &st) <= -1)? 0: 1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	/* ------------------------------------------------------------------- */ | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static int get_next_segment (glob_t* g, segment_t* seg) | ||||||
|  | { | ||||||
|  | 	if (seg->type == NONE) | ||||||
|  | 	{ | ||||||
|  | 		/* seg->ptr must point to the beginning of the pattern | ||||||
|  | 		 * and seg->len must be zero when seg->type is NONE. */ | ||||||
|  | 		if (IS_NIL(seg->ptr[0])) | ||||||
|  | 		{ | ||||||
|  | 			/* nothing to do */ | ||||||
|  | 		} | ||||||
|  | 		else if (IS_SEP(seg->ptr[0])) | ||||||
|  | 		{ | ||||||
|  | 			seg->type = ROOT; | ||||||
|  | 			seg->len = 1; | ||||||
|  | 			seg->next = IS_NIL(seg->ptr[1])? 0: 1; | ||||||
|  | 			seg->sep = T('\0'); | ||||||
|  | 			seg->wild = 0; | ||||||
|  | 			seg->esc = 0; | ||||||
|  | 		} | ||||||
|  | 	#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) | ||||||
|  | 		else if (IS_DRIVE(seg->ptr)) | ||||||
|  | 		{ | ||||||
|  | 			seg->type = ROOT; | ||||||
|  | 			seg->len = 2; | ||||||
|  | 			if (IS_SEP(seg->ptr[2])) seg->len++; | ||||||
|  | 			seg->next = IS_NIL(seg->ptr[seg->len])? 0: 1; | ||||||
|  | 			seg->sep = T('\0'); | ||||||
|  | 			seg->wild = 0; | ||||||
|  | 			seg->esc = 0; | ||||||
|  | 		} | ||||||
|  | 	#endif | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			int escaped = 0; | ||||||
|  | 			seg->type = NORMAL; | ||||||
|  | 			seg->sep = T('\0'); | ||||||
|  | 			seg->wild = 0; | ||||||
|  | 			seg->esc = 0; | ||||||
|  | 			do | ||||||
|  | 			{ | ||||||
|  | 				if (escaped) escaped = 0; | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					if (IS_ESC(seg->ptr[seg->len]))  | ||||||
|  | 					{ | ||||||
|  | 						escaped = 1; | ||||||
|  | 						seg->esc = 1; | ||||||
|  | 					} | ||||||
|  | 					else if (IS_WILD(seg->ptr[seg->len])) seg->wild = 1; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				seg->len++; | ||||||
|  | 			} | ||||||
|  | 			while (!IS_SEP_OR_NIL(seg->ptr[seg->len])); | ||||||
|  | 			seg->next = IS_NIL(seg->ptr[seg->len])? 0: 1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else if (seg->type == ROOT) | ||||||
|  | 	{ | ||||||
|  | 		int escaped = 0; | ||||||
|  | 		seg->type = NORMAL; | ||||||
|  | 		seg->ptr = &seg->ptr[seg->len]; | ||||||
|  | 		seg->len = 0; | ||||||
|  | 		seg->sep = T('\0'); | ||||||
|  | 		seg->wild = 0; | ||||||
|  | 		seg->esc = 0; | ||||||
|  |  | ||||||
|  | 		while (!IS_SEP_OR_NIL(seg->ptr[seg->len]))  | ||||||
|  | 		{ | ||||||
|  | 			if (escaped) escaped = 0; | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				if (IS_ESC(seg->ptr[seg->len]))  | ||||||
|  | 				{ | ||||||
|  | 					escaped = 1; | ||||||
|  | 					seg->esc = 1; | ||||||
|  | 				} | ||||||
|  | 				else if (IS_WILD(seg->ptr[seg->len])) seg->wild = 1; | ||||||
|  | 			} | ||||||
|  | 			seg->len++; | ||||||
|  | 		} | ||||||
|  | 		seg->next = IS_NIL(seg->ptr[seg->len])? 0: 1; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		QSE_ASSERT (seg->type == NORMAL); | ||||||
|  |  | ||||||
|  | 		seg->ptr = &seg->ptr[seg->len + 1]; | ||||||
|  | 		seg->len = 0; | ||||||
|  | 		seg->wild = 0; | ||||||
|  | 		seg->esc = 0; | ||||||
|  | 		if (IS_NIL(seg->ptr[-1]))  | ||||||
|  | 		{ | ||||||
|  | 			seg->type = NONE; | ||||||
|  | 			seg->next = 0; | ||||||
|  | 			seg->sep = T('\0'); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			int escaped = 0; | ||||||
|  | 			seg->sep = seg->ptr[-1]; | ||||||
|  | 			while (!IS_SEP_OR_NIL(seg->ptr[seg->len]))  | ||||||
|  | 			{ | ||||||
|  | 				if (escaped) escaped = 0; | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					if (IS_ESC(seg->ptr[seg->len]))  | ||||||
|  | 					{ | ||||||
|  | 						escaped = 1; | ||||||
|  | 						seg->esc = 1; | ||||||
|  | 					} | ||||||
|  | 					else if (IS_WILD(seg->ptr[seg->len])) seg->wild = 1; | ||||||
|  | 				} | ||||||
|  | 				seg->len++; | ||||||
|  | 			} | ||||||
|  | 			seg->next = IS_NIL(seg->ptr[seg->len])? 0: 1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return seg->type; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int handle_non_wild_segments (glob_t* g, segment_t* seg) | ||||||
|  | { | ||||||
|  | 	while (get_next_segment(g, seg) != NONE && !seg->wild) | ||||||
|  | 	{ | ||||||
|  | 		QSE_ASSERT (seg->type != NONE && !seg->wild); | ||||||
|  |  | ||||||
|  | 		if (seg->sep && str_ccat (&g->path, seg->sep) == (qse_size_t)-1) return -1; | ||||||
|  | 		if (seg->esc) | ||||||
|  | 		{ | ||||||
|  | 			/* if the segment contains escape sequences, | ||||||
|  | 			 * strip the escape letters off the segment */ | ||||||
|  |  | ||||||
|  | 			cstr_t tmp; | ||||||
|  | 			qse_size_t i; | ||||||
|  | 			int escaped = 0; | ||||||
|  |  | ||||||
|  | 			if (STR_CAPA(&g->tbuf) < seg->len && | ||||||
|  | 			    str_setcapa (&g->tbuf, seg->len) == (qse_size_t)-1) return -1; | ||||||
|  |  | ||||||
|  | 			tmp.ptr = STR_PTR(&g->tbuf); | ||||||
|  | 			tmp.len = 0; | ||||||
|  |  | ||||||
|  | 			/* the following loop drops the last character  | ||||||
|  | 			 * if it is the escape character */ | ||||||
|  | 			for (i = 0; i < seg->len; i++) | ||||||
|  | 			{ | ||||||
|  | 				if (escaped) | ||||||
|  | 				{ | ||||||
|  | 					escaped = 0; | ||||||
|  | 					tmp.ptr[tmp.len++] = seg->ptr[i]; | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					if (IS_ESC(seg->ptr[i]))  | ||||||
|  | 						escaped = 1; | ||||||
|  | 					else | ||||||
|  | 						tmp.ptr[tmp.len++] = seg->ptr[i]; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (str_ncat (&g->path, tmp.ptr, tmp.len) == (qse_size_t)-1) return -1; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			/* if the segmetn doesn't contain escape sequences, | ||||||
|  | 			 * append the segment to the path without special handling */ | ||||||
|  | 			if (str_ncat (&g->path, seg->ptr, seg->len) == (qse_size_t)-1) return -1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (!seg->next && path_exists (g, STR_PTR(&g->path)) > 0) | ||||||
|  | 		{ | ||||||
|  | 			/* reached the last segment. match if the path exists */ | ||||||
|  | 			if (g->cbimpl (STR_XSTR(&g->path), g->cbctx) <= -1) return -1; | ||||||
|  | 			g->expanded = 1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int search (glob_t* g, segment_t* seg) | ||||||
|  | { | ||||||
|  | 	qse_dir_t* dp; | ||||||
|  | 	qse_size_t tmp, tmp2; | ||||||
|  | 	qse_dir_ent_t ent; | ||||||
|  | 	int x; | ||||||
|  |  | ||||||
|  | #if defined(NO_RECURSION) | ||||||
|  | 	stack_node_t* r; | ||||||
|  |  | ||||||
|  | entry: | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	dp = QSE_NULL; | ||||||
|  |  | ||||||
|  | 	if (handle_non_wild_segments (g, seg) <= -1) goto oops; | ||||||
|  |  | ||||||
|  | 	if (seg->wild) | ||||||
|  | 	{ | ||||||
|  | 		int dir_flags = DIR_CHAR_FLAGS; | ||||||
|  | 		if (g->flags & QSE_GLOB_SKIPSPCDIR) dir_flags |= QSE_DIR_SKIPSPCDIR; | ||||||
|  |  | ||||||
|  | 		dp = qse_dir_open ( | ||||||
|  | 			g->mmgr, 0, (const qse_char_t*)STR_PTR(&g->path), | ||||||
|  | 			dir_flags, QSE_NULL); | ||||||
|  | 		if (dp) | ||||||
|  | 		{ | ||||||
|  | 			tmp = STR_LEN(&g->path); | ||||||
|  |  | ||||||
|  | 			if (seg->sep && str_ccat (&g->path, seg->sep) == (qse_size_t)-1) goto oops; | ||||||
|  | 			tmp2 = STR_LEN(&g->path); | ||||||
|  |  | ||||||
|  | 			while (1) | ||||||
|  | 			{ | ||||||
|  | 				str_setlen (&g->path, tmp2); | ||||||
|  |  | ||||||
|  | 				x = qse_dir_read (dp, &ent); | ||||||
|  | 				if (x <= -1)  | ||||||
|  | 				{ | ||||||
|  | 					if (g->flags & QSE_GLOB_TOLERANT) break; | ||||||
|  | 					else goto oops; | ||||||
|  | 				} | ||||||
|  | 				if (x == 0) break; | ||||||
|  |  | ||||||
|  | 				if (str_cat (&g->path, (const char_t*)ent.name) == (qse_size_t)-1) goto oops; | ||||||
|  |  | ||||||
|  | 				if (strnfnmat (STR_CPTR(&g->path,tmp2), seg->ptr, seg->len, g->fnmat_flags) > 0) | ||||||
|  | 				{ | ||||||
|  | 					if (seg->next) | ||||||
|  | 					{ | ||||||
|  | 				#if defined(NO_RECURSION) | ||||||
|  | 						if (g->free)  | ||||||
|  | 						{ | ||||||
|  | 							r = g->free; | ||||||
|  | 							g->free = r->next; | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							r = QSE_MMGR_ALLOC (g->mmgr, QSE_SIZEOF(*r)); | ||||||
|  | 							if (r == QSE_NULL) goto oops; | ||||||
|  | 						} | ||||||
|  | 						 | ||||||
|  | 						/* push key variables that must be restored  | ||||||
|  | 						 * into the stack. */ | ||||||
|  | 						r->tmp = tmp; | ||||||
|  | 						r->tmp2 = tmp2; | ||||||
|  | 						r->dp = dp; | ||||||
|  | 						r->seg = *seg; | ||||||
|  |  | ||||||
|  | 						r->next = g->stack; | ||||||
|  | 						g->stack = r; | ||||||
|  |  | ||||||
|  | 						/* move to the function entry point as if | ||||||
|  | 						 * a recursive call has been made */ | ||||||
|  | 						goto entry; | ||||||
|  |  | ||||||
|  | 					resume: | ||||||
|  | 						; | ||||||
|  |  | ||||||
|  | 				#else | ||||||
|  | 						segment_t save; | ||||||
|  | 						int x; | ||||||
|  |  | ||||||
|  | 						save = *seg; | ||||||
|  | 						x = search (g, seg); | ||||||
|  | 						*seg = save; | ||||||
|  | 						if (x <= -1) goto oops; | ||||||
|  | 				#endif | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						if (g->cbimpl (STR_XSTR(&g->path), g->cbctx) <= -1) goto oops; | ||||||
|  | 						g->expanded = 1; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			str_setlen (&g->path, tmp); | ||||||
|  | 			qse_dir_close (dp); dp = QSE_NULL; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	QSE_ASSERT (dp == QSE_NULL); | ||||||
|  |  | ||||||
|  | #if defined(NO_RECURSION) | ||||||
|  | 	if (g->stack) | ||||||
|  | 	{ | ||||||
|  | 		/* the stack is not empty. the emulated recusive call | ||||||
|  | 		 * must have been made. restore the variables pushed | ||||||
|  | 		 * and jump to the resumption point */ | ||||||
|  | 		r = g->stack; | ||||||
|  | 		g->stack = r->next; | ||||||
|  |  | ||||||
|  | 		tmp = r->tmp; | ||||||
|  | 		tmp2 = r->tmp2; | ||||||
|  | 		dp = r->dp; | ||||||
|  | 		*seg = r->seg; | ||||||
|  |  | ||||||
|  | 		/* link the stack node to the free list  | ||||||
|  | 		 * instead of freeing it here */ | ||||||
|  | 		r->next = g->free; | ||||||
|  | 		g->free = r; | ||||||
|  |  | ||||||
|  | 		goto resume; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	while (g->free) | ||||||
|  | 	{ | ||||||
|  | 		/* destory the free list */ | ||||||
|  | 		r = g->free; | ||||||
|  | 		g->free = r->next; | ||||||
|  | 		QSE_MMGR_FREE (g->mmgr, r); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | oops: | ||||||
|  | 	if (dp) qse_dir_close (dp); | ||||||
|  |  | ||||||
|  | #if defined(NO_RECURSION) | ||||||
|  | 	while (g->stack) | ||||||
|  | 	{ | ||||||
|  | 		r = g->stack; | ||||||
|  | 		g->stack = r->next; | ||||||
|  | 		qse_dir_close (r->dp); | ||||||
|  | 		QSE_MMGR_FREE (g->mmgr, r); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	while (g->free) | ||||||
|  | 	{ | ||||||
|  | 		r = g->stack; | ||||||
|  | 		g->free = r->next; | ||||||
|  | 		QSE_MMGR_FREE (g->mmgr, r); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int glob (const char_t* pattern, cbimpl_t cbimpl, void* cbctx, int flags, qse_mmgr_t* mmgr, qse_cmgr_t* cmgr) | ||||||
|  | { | ||||||
|  | 	segment_t seg; | ||||||
|  | 	glob_t g; | ||||||
|  | 	int x; | ||||||
|  |  | ||||||
|  | 	QSE_MEMSET (&g, 0, QSE_SIZEOF(g)); | ||||||
|  | 	g.cbimpl = cbimpl; | ||||||
|  | 	g.cbctx = cbctx; | ||||||
|  | 	g.mmgr = mmgr; | ||||||
|  | 	g.cmgr = cmgr; | ||||||
|  | 	g.flags = flags; | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) || defined(__OS2__) || defined(__DOS__) | ||||||
|  | 	g.fnmat_flags |= QSE_STRFNMAT_IGNORECASE; | ||||||
|  | 	g.fnmat_flags |= QSE_STRFNMAT_NOESCAPE; | ||||||
|  | #else | ||||||
|  | 	if (flags & QSE_GLOB_IGNORECASE) g.fnmat_flags |= QSE_STRFNMAT_IGNORECASE; | ||||||
|  | 	if (flags & QSE_GLOB_NOESCAPE) g.fnmat_flags |= QSE_STRFNMAT_NOESCAPE; | ||||||
|  | #endif | ||||||
|  | 	if (flags & QSE_GLOB_PERIOD) g.fnmat_flags |= QSE_STRFNMAT_PERIOD; | ||||||
|  |  | ||||||
|  | 	if (str_init (&g.path, mmgr, 512) <= -1) return -1; | ||||||
|  | 	if (str_init (&g.tbuf, mmgr, 256) <= -1)  | ||||||
|  | 	{ | ||||||
|  | 		str_fini (&g.path); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #if defined(DECLARE_MBUF) | ||||||
|  | 	if (qse_mbs_init (&g.mbuf, mmgr, 512) <= -1)  | ||||||
|  | 	{ | ||||||
|  | 		str_fini (&g.path); | ||||||
|  | 		str_fini (&g.path); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	QSE_MEMSET (&seg, 0, QSE_SIZEOF(seg)); | ||||||
|  | 	seg.type = NONE; | ||||||
|  | 	seg.ptr = pattern; | ||||||
|  | 	seg.len = 0; | ||||||
|  |  | ||||||
|  | 	x = search (&g, &seg); | ||||||
|  |  | ||||||
|  | #if defined(DECLARE_MBUF) | ||||||
|  | 	qse_mbs_fini (&g.mbuf); | ||||||
|  | #endif | ||||||
|  | 	str_fini (&g.tbuf); | ||||||
|  | 	str_fini (&g.path); | ||||||
|  |  | ||||||
|  | 	if (x <= -1) return -1; | ||||||
|  | 	return g.expanded; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user