added qse_globmbs() and qse_globwcs()
This commit is contained in:
		| @ -13,6 +13,7 @@ noinst_HEADERS = \ | ||||
| 	fmt-intmax.h \ | ||||
| 	fmt-out.h \ | ||||
| 	fs.h \ | ||||
| 	glob.h \ | ||||
| 	mem.h \ | ||||
| 	str-dyn.h \ | ||||
| 	str-fcpy.h \ | ||||
|  | ||||
| @ -397,6 +397,7 @@ noinst_HEADERS = \ | ||||
| 	fmt-intmax.h \ | ||||
| 	fmt-out.h \ | ||||
| 	fs.h \ | ||||
| 	glob.h \ | ||||
| 	mem.h \ | ||||
| 	str-dyn.h \ | ||||
| 	str-fcpy.h \ | ||||
|  | ||||
| @ -46,596 +46,158 @@ | ||||
| #	include "syscall.h" | ||||
| #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__) | ||||
| 	/* 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 | ||||
| #	define IS_ESC(c) ((c) == QSE_T('\\')) | ||||
| #	define IS_ESC_MBS(c) ((c) == QSE_MT('\\')) | ||||
| #	define IS_ESC_WCS(c) ((c) == QSE_WT('\\')) | ||||
| #endif | ||||
|  | ||||
| #define IS_SEP(c) QSE_ISPATHSEP(c) | ||||
|  | ||||
| #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(':')) | ||||
| #define IS_NIL_MBS(c) ((c) == QSE_MT('\0')) | ||||
| #define IS_NIL_WCS(c) ((c) == QSE_WT('\0')) | ||||
|  | ||||
| /* this macro only checks for top-level wild-cards among these. | ||||
|  *  *, ?, [], !, -   | ||||
|  * 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 | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| #include "glob.h" | ||||
|  | ||||
							
								
								
									
										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; | ||||
| } | ||||
| @ -163,7 +163,7 @@ static int make_param ( | ||||
| 			goto oops;  | ||||
| 		} | ||||
| 	} | ||||
| #else	 | ||||
| #else | ||||
| 	if (flags & QSE_PIO_MBSCMD)  | ||||
| 	{ | ||||
| 		/* the cmd is flagged to be of qse_mchar_t  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user