enhanced qse_mbsxsubst() and qse_wcsxsubst() for buffer size prediction
This commit is contained in:
		@ -125,6 +125,10 @@ struct qse_wcs_t
 | 
				
			|||||||
	qse_size_t      capa;  /**< buffer capacity */
 | 
						qse_size_t      capa;  /**< buffer capacity */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QSE_MBSSUBST_NOBUF ((qse_mchar_t*)1)
 | 
				
			||||||
 | 
					#define QSE_WCSSUBST_NOBUF ((qse_wchar_t*)1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The qse_mbssubst_t type defines a callback function for qse_mbsxsubst()
 | 
					 * The qse_mbssubst_t type defines a callback function for qse_mbsxsubst()
 | 
				
			||||||
 * and qse_mbsxnsubst() to substitue a new value for an identifier \a ident.
 | 
					 * and qse_mbsxnsubst() to substitue a new value for an identifier \a ident.
 | 
				
			||||||
@ -148,8 +152,10 @@ typedef qse_wchar_t* (*qse_wcssubst_t) (
 | 
				
			|||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(QSE_CHAR_IS_MCHAR)
 | 
					#if defined(QSE_CHAR_IS_MCHAR)
 | 
				
			||||||
 | 
					#	define QSE_STRSUBST_NOBUF QSE_MBSSUBST_NOBUF
 | 
				
			||||||
#	define qse_strsubst_t qse_mbssubst_t
 | 
					#	define qse_strsubst_t qse_mbssubst_t
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
					#	define QSE_STRSUBST_NOBUF QSE_WCSSUBST_NOBUF
 | 
				
			||||||
#	define qse_strsubst_t qse_wcssubst_t
 | 
					#	define qse_strsubst_t qse_wcssubst_t
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -696,6 +702,45 @@ QSE_EXPORT qse_size_t qse_wcsxfncpy (
 | 
				
			|||||||
 * qse_mchar_t buf[25];
 | 
					 * qse_mchar_t buf[25];
 | 
				
			||||||
 * qse_mbsxsubst (buf, i, QSE_MT("user=${USER},group=${GROUP}"), subst, QSE_NULL);
 | 
					 * qse_mbsxsubst (buf, i, QSE_MT("user=${USER},group=${GROUP}"), subst, QSE_NULL);
 | 
				
			||||||
 * \endcode
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * If \a buf is #QSE_MBSSUBST_NOBUF, the function returns the length of the 
 | 
				
			||||||
 | 
					 * resulting string that a buffer large enough would be able to hold. You can 
 | 
				
			||||||
 | 
					 * pass #QSE_MBSSUBST_NOBUF to find out how large a buffer you need to perform 
 | 
				
			||||||
 | 
					 * substitution without truncation. The substitution callback function should 
 | 
				
			||||||
 | 
					 * handle this special case for buffer size prediction. The sample callback shown
 | 
				
			||||||
 | 
					 * above can be extended to return the buffer pointer without actual copying 
 | 
				
			||||||
 | 
					 * if the buffer points to #QSE_MBSSUBST_NOBUF as shown belown.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * qse_mchar_t* subst (qse_mchar_t* buf, qse_size_t bsz, const qse_mcstr_t* ident, void* ctx)
 | 
				
			||||||
 | 
					 * { 
 | 
				
			||||||
 | 
					 *   if (qse_mcsxcmp (ident->ptr, ident->len, QSE_MT("USER")) == 0)
 | 
				
			||||||
 | 
					 *     return buf + (buf == QSE_MBSSUBST_NOBUF? 3: qse_mcsxput (buf, bsz, QSE_MT("sam")));
 | 
				
			||||||
 | 
					 *   else if (qse_mcsxcmp (ident->ptr, ident->len, QSE_MT("GROUP")) == 0)
 | 
				
			||||||
 | 
					 *     return buf + (buf == QSE_MBSSUBST_NOBUF? 6: qse_mcsxput (buf, bsz, QSE_MT("coders")));	
 | 
				
			||||||
 | 
					 *   return buf; 
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * len = qse_mbsxsubst (QSE_MBSSUBST_NOBUF, 0, QSE_MT("user=${USER},group=${GROUP}"), subst, QSE_NULL);
 | 
				
			||||||
 | 
					 * buf = malloc (QSE_SIZEOF(qse_mbs_t) * (len + 1));
 | 
				
			||||||
 | 
					 * qse_mbsxsubst (buf, len + 1, QSE_MT("user=${USER},group=${GROUP}"), subst, QSE_NULL);
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A ${} segment may contain a default value. For example, the segment 
 | 
				
			||||||
 | 
					 * ${USER:=Unknown} translates to Unknown if the callback function returns 
 | 
				
			||||||
 | 
					 * #QSE_NULL for USER. The default value part may contain ${} segments 
 | 
				
			||||||
 | 
					 * recursively.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * qse_mchar_t* subst (qse_mchar_t* buf, qse_size_t bsz, const qse_mcstr_t* ident, void* ctx)
 | 
				
			||||||
 | 
					 * { 
 | 
				
			||||||
 | 
					 *   if (qse_mbsxcmp (ident->ptr, ident->len, QSE_MT("USER")) == 0)
 | 
				
			||||||
 | 
					 *     return QSE_NULL;
 | 
				
			||||||
 | 
					 *   else if (qse_mbsxcmp (ident->ptr, ident->len, QSE_MT("GROUP")) == 0)
 | 
				
			||||||
 | 
					 *     return buf + (buf == QSE_MBSSUBST_NOBUF? 6: qse_wcsxput (buf, bsz, QSE_MT("coders")));	
 | 
				
			||||||
 | 
					 *   return buf; 
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
QSE_EXPORT qse_size_t qse_mbsxsubst (
 | 
					QSE_EXPORT qse_size_t qse_mbsxsubst (
 | 
				
			||||||
	qse_mchar_t*           buf,
 | 
						qse_mchar_t*           buf,
 | 
				
			||||||
@ -731,6 +776,44 @@ QSE_EXPORT qse_size_t qse_mbsxnsubst (
 | 
				
			|||||||
 * qse_wchar_t buf[25];
 | 
					 * qse_wchar_t buf[25];
 | 
				
			||||||
 * qse_wcsxsubst (buf, i, QSE_WT("user=${USER},group=${GROUP}"), subst, QSE_NULL);
 | 
					 * qse_wcsxsubst (buf, i, QSE_WT("user=${USER},group=${GROUP}"), subst, QSE_NULL);
 | 
				
			||||||
 * \endcode
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If \a buf is #QSE_WCSSUBST_NOBUF, the function returns the length of the 
 | 
				
			||||||
 | 
					 * resulting string that a buffer large enough would be able to hold. You can 
 | 
				
			||||||
 | 
					 * pass #QSE_WCSSUBST_NOBUF to find out how large a buffer you need to perform 
 | 
				
			||||||
 | 
					 * substitution without truncation. The substitution callback function should 
 | 
				
			||||||
 | 
					 * handle this special case for buffer size prediction. The sample callback shown
 | 
				
			||||||
 | 
					 * above can be extended to return the buffer pointer without actual copying 
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * qse_mchar_t* subst (qse_mchar_t* buf, qse_size_t bsz, const qse_wcstr_t* ident, void* ctx)
 | 
				
			||||||
 | 
					 * { 
 | 
				
			||||||
 | 
					 *   if (qse_wcsxcmp (ident->ptr, ident->len, QSE_WT("USER")) == 0)
 | 
				
			||||||
 | 
					 *     return buf + (buf == QSE_WCSSUBST_NOBUF? 3: qse_wcsxput (buf, bsz, QSE_WT("sam")));
 | 
				
			||||||
 | 
					 *   else if (qse_wcsxcmp (ident->ptr, ident->len, QSE_WT("GROUP")) == 0)
 | 
				
			||||||
 | 
					 *     return buf + (buf == QSE_WCSSUBST_NOBUF? 6: qse_wcsxput (buf, bsz, QSE_WT("coders")));	
 | 
				
			||||||
 | 
					 *   return buf; 
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * len = qse_wcsxsubst (QSE_WCSSUBST_NOBUF, 0, QSE_WT("user=${USER},group=${GROUP}"), subst, QSE_NULL);
 | 
				
			||||||
 | 
					 * buf = malloc (QSE_SIZEOF(qse_wcs_t) * (len + 1));
 | 
				
			||||||
 | 
					 * qse_wcsxsubst (buf, len + 1, QSE_WT("user=${USER},group=${GROUP}"), subst, QSE_NULL);
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A ${} segment may contain a default value. For example, the segment 
 | 
				
			||||||
 | 
					 * ${USER:=Unknown} translates to Unknown if the callback function returns 
 | 
				
			||||||
 | 
					 * #QSE_NULL for USER. The default value part may contain ${} segments 
 | 
				
			||||||
 | 
					 * recursively.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * qse_mchar_t* subst (qse_mchar_t* buf, qse_size_t bsz, const qse_wcstr_t* ident, void* ctx)
 | 
				
			||||||
 | 
					 * { 
 | 
				
			||||||
 | 
					 *   if (qse_wcsxcmp (ident->ptr, ident->len, QSE_WT("USER")) == 0)
 | 
				
			||||||
 | 
					 *     return QSE_NULL;
 | 
				
			||||||
 | 
					 *   else if (qse_wcsxcmp (ident->ptr, ident->len, QSE_WT("GROUP")) == 0)
 | 
				
			||||||
 | 
					 *     return buf + (buf == QSE_WCSSUBST_NOBUF? 6: qse_wcsxput (buf, bsz, QSE_WT("coders")));	
 | 
				
			||||||
 | 
					 *   return buf; 
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
QSE_EXPORT qse_size_t qse_wcsxsubst (
 | 
					QSE_EXPORT qse_size_t qse_wcsxsubst (
 | 
				
			||||||
	qse_wchar_t*           buf,
 | 
						qse_wchar_t*           buf,
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,7 @@
 | 
				
			|||||||
#undef char_t
 | 
					#undef char_t
 | 
				
			||||||
#undef cstr_t
 | 
					#undef cstr_t
 | 
				
			||||||
#undef T
 | 
					#undef T
 | 
				
			||||||
 | 
					#undef NOBUF
 | 
				
			||||||
#undef strlen
 | 
					#undef strlen
 | 
				
			||||||
#undef scan_dollar
 | 
					#undef scan_dollar
 | 
				
			||||||
#undef expand_dollar
 | 
					#undef expand_dollar
 | 
				
			||||||
@ -35,6 +36,7 @@
 | 
				
			|||||||
#define char_t qse_mchar_t
 | 
					#define char_t qse_mchar_t
 | 
				
			||||||
#define cstr_t qse_mcstr_t
 | 
					#define cstr_t qse_mcstr_t
 | 
				
			||||||
#define T(x) QSE_MT(x)
 | 
					#define T(x) QSE_MT(x)
 | 
				
			||||||
 | 
					#define NOBUF QSE_MBSSUBST_NOBUF
 | 
				
			||||||
#define strlen qse_mbslen
 | 
					#define strlen qse_mbslen
 | 
				
			||||||
#define scan_dollar mbs_scan_dollar
 | 
					#define scan_dollar mbs_scan_dollar
 | 
				
			||||||
#define expand_dollar mbs_expand_dollar
 | 
					#define expand_dollar mbs_expand_dollar
 | 
				
			||||||
@ -48,6 +50,7 @@
 | 
				
			|||||||
#undef char_t
 | 
					#undef char_t
 | 
				
			||||||
#undef cstr_t
 | 
					#undef cstr_t
 | 
				
			||||||
#undef T
 | 
					#undef T
 | 
				
			||||||
 | 
					#undef NOBUF
 | 
				
			||||||
#undef strlen
 | 
					#undef strlen
 | 
				
			||||||
#undef scan_dollar
 | 
					#undef scan_dollar
 | 
				
			||||||
#undef expand_dollar
 | 
					#undef expand_dollar
 | 
				
			||||||
@ -58,6 +61,7 @@
 | 
				
			|||||||
#define char_t qse_wchar_t
 | 
					#define char_t qse_wchar_t
 | 
				
			||||||
#define cstr_t qse_wcstr_t
 | 
					#define cstr_t qse_wcstr_t
 | 
				
			||||||
#define T(x) QSE_WT(x)
 | 
					#define T(x) QSE_WT(x)
 | 
				
			||||||
 | 
					#define NOBUF QSE_WCSSUBST_NOBUF
 | 
				
			||||||
#define strlen qse_wcslen
 | 
					#define strlen qse_wcslen
 | 
				
			||||||
#define scan_dollar wcs_scan_dollar
 | 
					#define scan_dollar wcs_scan_dollar
 | 
				
			||||||
#define expand_dollar wcs_expand_dollar
 | 
					#define expand_dollar wcs_expand_dollar
 | 
				
			||||||
 | 
				
			|||||||
@ -122,7 +122,7 @@ qse_size_t strxnsubst (
 | 
				
			|||||||
	const char_t* f = fmt;
 | 
						const char_t* f = fmt;
 | 
				
			||||||
	const char_t* fend = fmt + fsz;
 | 
						const char_t* fend = fmt + fsz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bsz <= 0) return 0;
 | 
						if (buf != NOBUF && bsz <= 0) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (f < fend)
 | 
						while (f < fend)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -144,8 +144,18 @@ qse_size_t strxnsubst (
 | 
				
			|||||||
				if (tmp == QSE_NULL || ident.len <= 0) goto normal;
 | 
									if (tmp == QSE_NULL || ident.len <= 0) goto normal;
 | 
				
			||||||
				f = tmp;
 | 
									f = tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (buf != NOBUF)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
					b = expand_dollar (b, end - b + 1, &ident, &dfl, subst, ctx);
 | 
										b = expand_dollar (b, end - b + 1, &ident, &dfl, subst, ctx);
 | 
				
			||||||
					if (b >= end) goto fini;
 | 
										if (b >= end) goto fini;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										/* the buffer points to NOBUF. */
 | 
				
			||||||
 | 
										tmp = expand_dollar (buf, bsz, &ident, &dfl, subst, ctx);
 | 
				
			||||||
 | 
										/* increment b by the length of the expanded string */
 | 
				
			||||||
 | 
										b += (tmp - buf);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -157,12 +167,16 @@ qse_size_t strxnsubst (
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	normal:
 | 
						normal:
 | 
				
			||||||
 | 
							if (buf != NOBUF)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
			if (b >= end) break;
 | 
								if (b >= end) break;
 | 
				
			||||||
		*b++ = *f++;
 | 
								*b = *f;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							b++; f++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fini:
 | 
					fini:
 | 
				
			||||||
	*b = T('\0');
 | 
						if (buf != NOBUF) *b = T('\0');
 | 
				
			||||||
	return b - buf;
 | 
						return b - buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -172,3 +186,4 @@ qse_size_t strxsubst (
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	return strxnsubst (buf, bsz, fmt, strlen(fmt), subst, ctx);
 | 
						return strxnsubst (buf, bsz, fmt, strlen(fmt), subst, ctx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user