enhanced qse_strxsubst().
added qse_strxnsubst()
This commit is contained in:
		| @ -20,126 +20,49 @@ | ||||
|  | ||||
| #include <qse/cmn/str.h> | ||||
|  | ||||
| qse_size_t qse_mbsxsubst ( | ||||
| 	qse_mchar_t* buf, qse_size_t bsz, const qse_mchar_t* fmt,  | ||||
| 	qse_mbsxsubst_subst_t subst, void* ctx) | ||||
| { | ||||
| 	qse_mchar_t* b = buf; | ||||
| 	qse_mchar_t* end = buf + bsz - 1; | ||||
| 	const qse_mchar_t* f = fmt; | ||||
| /* ----------------------------------- */ | ||||
|  | ||||
| 	if (bsz <= 0) return 0; | ||||
| #undef char_t | ||||
| #undef cstr_t | ||||
| #undef T | ||||
| #undef strlen | ||||
| #undef scan_dollar | ||||
| #undef expand_dollar | ||||
| #undef subst_t | ||||
| #undef strxsubst | ||||
| #undef strxnsubst | ||||
|  | ||||
| 	while (*f != QSE_MT('\0')) | ||||
| 	{ | ||||
| 		if (*f == QSE_MT('\\')) | ||||
| 		{ | ||||
| 			/* get the escaped character and treat it normally. | ||||
| 			 * if the escaper is the last character, treat it  | ||||
| 			 * normally also. */ | ||||
| 			if (f[1] != QSE_MT('\0')) f++; | ||||
| 		} | ||||
| 		else if (*f == QSE_MT('$')) | ||||
| 		{ | ||||
| 			if (f[1] == QSE_MT('{')) | ||||
| 			{ | ||||
| 				const qse_mchar_t* tmp; | ||||
| 				qse_mcstr_t ident; | ||||
| #define char_t qse_mchar_t | ||||
| #define cstr_t qse_mcstr_t | ||||
| #define T(x) QSE_MT(x) | ||||
| #define strlen qse_mbslen | ||||
| #define scan_dollar mbs_scan_dollar | ||||
| #define expand_dollar mbs_expand_dollar | ||||
| #define subst_t qse_mbssubst_t | ||||
| #define strxsubst qse_mbsxsubst | ||||
| #define strxnsubst qse_mbsxnsubst | ||||
| #include "str-subst.h" | ||||
|  | ||||
| 				f += 2; /* skip ${ */  | ||||
| 				tmp = f; /* mark the beginning */ | ||||
| /* ----------------------------------- */ | ||||
|  | ||||
| 				/* scan an enclosed segment */ | ||||
| 				while (*f != QSE_MT('\0') && *f != QSE_MT('}')) f++; | ||||
| 	 | ||||
| 				if (*f != QSE_MT('}')) | ||||
| 				{ | ||||
| 					/* restore to the position of $ */ | ||||
| 					f = tmp - 2; | ||||
| 					goto normal; | ||||
| 				} | ||||
| #undef char_t | ||||
| #undef cstr_t | ||||
| #undef T | ||||
| #undef strlen | ||||
| #undef scan_dollar | ||||
| #undef expand_dollar | ||||
| #undef subst_t | ||||
| #undef strxsubst | ||||
| #undef strxnsubst | ||||
|  | ||||
| 				f++; /* skip } */ | ||||
| 			 | ||||
| 				ident.ptr = tmp; | ||||
| 				ident.len = f - tmp - 1; | ||||
| #define char_t qse_wchar_t | ||||
| #define cstr_t qse_wcstr_t | ||||
| #define T(x) QSE_WT(x) | ||||
| #define strlen qse_wcslen | ||||
| #define scan_dollar wcs_scan_dollar | ||||
| #define expand_dollar wcs_expand_dollar | ||||
| #define subst_t qse_wcssubst_t | ||||
| #define strxsubst qse_wcsxsubst | ||||
| #define strxnsubst qse_wcsxnsubst | ||||
| #include "str-subst.h" | ||||
|  | ||||
| 				b = subst (b, end - b, &ident, ctx); | ||||
| 				if (b >= end) goto fini; | ||||
|  | ||||
| 				continue; | ||||
| 			} | ||||
| 			else if (f[1] == QSE_MT('$')) f++; | ||||
| 		} | ||||
|  | ||||
| 	normal: | ||||
| 		if (b >= end) break; | ||||
| 		*b++ = *f++; | ||||
| 	} | ||||
|  | ||||
| fini: | ||||
| 	*b = QSE_MT('\0'); | ||||
| 	return b - buf; | ||||
| } | ||||
|  | ||||
| qse_size_t qse_wcsxsubst ( | ||||
| 	qse_wchar_t* buf, qse_size_t bsz, const qse_wchar_t* fmt,  | ||||
| 	qse_wcsxsubst_subst_t subst, void* ctx) | ||||
| { | ||||
| 	qse_wchar_t* b = buf; | ||||
| 	qse_wchar_t* end = buf + bsz - 1; | ||||
| 	const qse_wchar_t* f = fmt; | ||||
|  | ||||
| 	if (bsz <= 0) return 0; | ||||
|  | ||||
| 	while (*f != QSE_WT('\0')) | ||||
| 	{ | ||||
| 		if (*f == QSE_WT('\\')) | ||||
| 		{ | ||||
| 			/* get the escaped character and treat it normally. | ||||
| 			 * if the escaper is the last character, treat it  | ||||
| 			 * normally also. */ | ||||
| 			if (f[1] != QSE_WT('\0')) f++; | ||||
| 		} | ||||
| 		else if (*f == QSE_WT('$')) | ||||
| 		{ | ||||
| 			if (f[1] == QSE_WT('{')) | ||||
| 			{ | ||||
| 				const qse_wchar_t* tmp; | ||||
| 				qse_wcstr_t ident; | ||||
|  | ||||
| 				f += 2; /* skip ${ */  | ||||
| 				tmp = f; /* mark the beginning */ | ||||
|  | ||||
| 				/* scan an enclosed segment */ | ||||
| 				while (*f != QSE_WT('\0') && *f != QSE_WT('}')) f++; | ||||
| 	 | ||||
| 				if (*f != QSE_WT('}')) | ||||
| 				{ | ||||
| 					/* restore to the position of $ */ | ||||
| 					f = tmp - 2; | ||||
| 					goto normal; | ||||
| 				} | ||||
|  | ||||
| 				f++; /* skip } */ | ||||
| 			 | ||||
| 				ident.ptr = tmp; | ||||
| 				ident.len = f - tmp - 1; | ||||
|  | ||||
| 				b = subst (b, end - b, &ident, ctx); | ||||
| 				if (b >= end) goto fini; | ||||
|  | ||||
| 				continue; | ||||
| 			} | ||||
| 			else if (f[1] == QSE_WT('$')) f++; | ||||
| 		} | ||||
|  | ||||
| 	normal: | ||||
| 		if (b >= end) break; | ||||
| 		*b++ = *f++; | ||||
| 	} | ||||
|  | ||||
| fini: | ||||
| 	*b = QSE_WT('\0'); | ||||
| 	return b - buf; | ||||
| } | ||||
|  | ||||
							
								
								
									
										174
									
								
								qse/lib/cmn/str-subst.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								qse/lib/cmn/str-subst.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,174 @@ | ||||
| /* | ||||
|  * $Id$ | ||||
|  * | ||||
|     Copyright 2006-2012 Chung, Hyung-Hwan. | ||||
|     This file is part of QSE. | ||||
|  | ||||
|     QSE is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU Lesser General Public License as | ||||
|     published by the Free Software Foundation, either version 3 of | ||||
|     the License, or (at your option) any later version. | ||||
|  | ||||
|     QSE is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU Lesser General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU Lesser General Public | ||||
|     License along with QSE. If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| #if !defined(char_t) && !defined(cstr_t) && !defined(strxsubst) | ||||
| #	error Never include this file | ||||
| #endif | ||||
|  | ||||
| static const char_t* scan_dollar ( | ||||
| 	const char_t* f, qse_size_t l, cstr_t* ident, cstr_t* dfl, int depth) | ||||
| { | ||||
| 	const char_t* end = f + l; | ||||
|  | ||||
| 	QSE_ASSERT (l >= 2); | ||||
| 	 | ||||
| 	f += 2; /* skip ${ */  | ||||
| 	if (ident) ident->ptr = f; | ||||
|  | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		if (f >= end) return QSE_NULL; | ||||
| 		if (*f == T('}') || *f == T(':')) break; | ||||
| 		f++; | ||||
| 	} | ||||
|  | ||||
| 	if (*f == T(':')) | ||||
| 	{ | ||||
| 		if (f >= end || *(f + 1) != T('='))  | ||||
| 		{ | ||||
| 			/* not := */ | ||||
| 			return QSE_NULL;  | ||||
| 		} | ||||
|  | ||||
| 		if (ident) ident->len = f - ident->ptr; | ||||
|  | ||||
| 		f += 2; /* skip := */ | ||||
|  | ||||
| 		if (dfl) dfl->ptr = f; | ||||
| 		while (1) | ||||
| 		{ | ||||
| 			if (f >= end) return QSE_NULL; | ||||
|  | ||||
| 			else if (*f == T('$') && *(f + 1) == T('{')) | ||||
| 			{ | ||||
| 				if (depth >= 64) return QSE_NULL; /* depth too deep */ | ||||
|  | ||||
| 				/* TODO: remove recursion */ | ||||
| 				f = scan_dollar (f, end - f, QSE_NULL, QSE_NULL, depth + 1); | ||||
| 				if (f == QSE_NULL) return QSE_NULL; | ||||
| 			} | ||||
| 			else if (*f == T('}'))  | ||||
| 			{ | ||||
| 				/* ending bracket  */ | ||||
| 				if (dfl) dfl->len = f - dfl->ptr; | ||||
| 				return f + 1; | ||||
| 			} | ||||
| 			else	f++; | ||||
| 		} | ||||
| 	} | ||||
| 	else if (*f == T('}'))  | ||||
| 	{ | ||||
| 		if (ident) ident->len = f - ident->ptr; | ||||
| 		if (dfl)  | ||||
| 		{ | ||||
| 			dfl->ptr = QSE_NULL; | ||||
| 			dfl->len = 0; | ||||
| 		} | ||||
| 		return f + 1; | ||||
| 	} | ||||
|  | ||||
| 	/* this part must not be reached */ | ||||
| 	return QSE_NULL; | ||||
| } | ||||
|  | ||||
| static char_t* expand_dollar ( | ||||
| 	char_t* buf, qse_size_t bsz, const cstr_t* ident, const cstr_t* dfl, | ||||
| 	subst_t subst, void* ctx) | ||||
| { | ||||
| 	char_t* tmp; | ||||
|  | ||||
| 	tmp = subst (buf, bsz, ident, ctx); | ||||
| 	if (tmp == QSE_NULL) | ||||
| 	{ | ||||
| 		/* substitution failed */ | ||||
| 		if (dfl->len > 0) | ||||
| 		{ | ||||
| 			/* take the default value */ | ||||
| 			qse_size_t len; | ||||
|  | ||||
| 			/* TODO: remove recursion */ | ||||
| 			len = strxnsubst (buf, bsz, dfl->ptr, dfl->len, subst, ctx); | ||||
| 			tmp = buf + len; | ||||
| 		} | ||||
| 		else tmp = buf; | ||||
| 	} | ||||
|  | ||||
| 	return tmp; | ||||
| } | ||||
|  | ||||
| qse_size_t strxnsubst ( | ||||
| 	char_t* buf, qse_size_t bsz, const char_t* fmt, qse_size_t fsz, | ||||
| 	subst_t subst, void* ctx) | ||||
| { | ||||
| 	char_t* b = buf; | ||||
| 	char_t* end = buf + bsz - 1; | ||||
| 	const char_t* f = fmt; | ||||
| 	const char_t* fend = fmt + fsz; | ||||
|  | ||||
| 	if (bsz <= 0) return 0; | ||||
|  | ||||
| 	while (f < fend) | ||||
| 	{ | ||||
| 		if (*f == T('\\')) | ||||
| 		{ | ||||
| 			/* get the escaped character and treat it normally. | ||||
| 			 * if the escaper is the last character, treat it  | ||||
| 			 * normally also. */ | ||||
| 			if (f < fend - 1) f++; | ||||
| 		} | ||||
| 		else if (*f == T('$') && f < fend - 1) | ||||
| 		{ | ||||
| 			if (*(f + 1) == T('{')) | ||||
| 			{ | ||||
| 				const char_t* tmp; | ||||
| 				cstr_t ident, dfl; | ||||
|  | ||||
| 				tmp = scan_dollar (f, fend - f, &ident, &dfl, 0); | ||||
| 				if (tmp == QSE_NULL || ident.len <= 0) goto normal; | ||||
| 				f = tmp; | ||||
|  | ||||
| 				b = expand_dollar (b, end - b + 1, &ident, &dfl, subst, ctx); | ||||
| 				if (b >= end) goto fini; | ||||
|  | ||||
| 				continue; | ||||
| 			} | ||||
| 			else if (*(f + 1) == T('$'))  | ||||
| 			{ | ||||
| 				/* $$ -> $. \$ is also $. */ | ||||
| 				f++; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	normal: | ||||
| 		if (b >= end) break; | ||||
| 		*b++ = *f++; | ||||
| 	} | ||||
|  | ||||
| fini: | ||||
| 	*b = T('\0'); | ||||
| 	return b - buf; | ||||
| } | ||||
|  | ||||
| qse_size_t strxsubst ( | ||||
| 	char_t* buf, qse_size_t bsz, const char_t* fmt,  | ||||
| 	subst_t subst, void* ctx) | ||||
| { | ||||
| 	return strxnsubst (buf, bsz, fmt, strlen(fmt), subst, ctx); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user