diff --git a/qse/include/qse/cmn/str.h b/qse/include/qse/cmn/str.h index ef286fb6..41b62e61 100644 --- a/qse/include/qse/cmn/str.h +++ b/qse/include/qse/cmn/str.h @@ -1,5 +1,5 @@ /* - * $Id: str.h 323 2010-04-05 12:50:01Z hyunghwan.chung $ + * $Id: str.h 324 2010-04-29 13:14:13Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -25,8 +25,7 @@ #include /** @file - * defines various functions, types, macros to manipulate - * a string. + * Various functions, types, macros for string manipulation. * * The qse_cstr_t type and the qse_xstr_t defined in helps you * dealing with a string pointer and length. @@ -39,7 +38,11 @@ #define QSE_STR_SIZER(s) ((s)->sizer) /**< buffer resizer function */ typedef struct qse_str_t qse_str_t; -typedef qse_size_t (*qse_str_sizer_t) (qse_str_t* data, qse_size_t hint); + +typedef qse_size_t (*qse_str_sizer_t) ( + qse_str_t* data, + qse_size_t hint +); /** * The qse_str_t type defines a dynamically resizable string. @@ -53,6 +56,18 @@ struct qse_str_t qse_size_t capa; /**< buffer capacity */ }; +/** + * The qse_strxsubst_subst_t type defines a callback function + * for qse_strxsubst() to substitue a new value for an identifier @a ident. + */ +typedef qse_char_t* (*qse_strxsubst_subst_t) ( + qse_char_t* buf, + qse_size_t bsz, + const qse_cstr_t* ident, + void* ctx +); + + /* int qse_chartonum (qse_char_t c, int base) */ #define QSE_CHARTONUM(c,base) \ ((c>=QSE_T('0') && c<=QSE_T('9'))? ((c-QSE_T('0')ptr, ident->len, QSE_T("USER")) == 0) + * return buf + qse_strxput (buf, bsz, QSE_T("sam")); + * else if (qse_strxcmp (ident->ptr, ident->len, QSE_T("GROUP")) == 0) + * return buf + qse_strxput (buf, bsz, QSE_T("coders")); + * return buf; + * } + * + * qse_char_t buf[25]; + * qse_strxsubst (buf, i, QSE_T("user=${USER},group=${GROUP}"), subst, QSE_NULL); + * @endcode + */ +qse_size_t qse_strxsubst ( + qse_char_t* buf, + qse_size_t bsz, + const qse_char_t* fmt, + qse_strxsubst_subst_t subst, + void* ctx +); + qse_size_t qse_strxcat ( qse_char_t* buf, qse_size_t bsz, diff --git a/qse/lib/cmn/str_bas.c b/qse/lib/cmn/str_bas.c index e1d48521..79ea6ef1 100644 --- a/qse/lib/cmn/str_bas.c +++ b/qse/lib/cmn/str_bas.c @@ -1,5 +1,5 @@ /* - * $Id: str_bas.c 323 2010-04-05 12:50:01Z hyunghwan.chung $ + * $Id: str_bas.c 324 2010-04-29 13:14:13Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -122,6 +122,39 @@ qse_size_t qse_strxncpy ( return n; } +qse_size_t qse_strxput ( + qse_char_t* buf, qse_size_t bsz, const qse_char_t* str) +{ + qse_char_t* p, * p2; + + p = buf; p2 = buf + bsz; + + while (p < p2) + { + if (*str == QSE_T('\0')) break; + *p++ = *str++; + } + + return p - buf; +} + +qse_size_t qse_strxnput ( + qse_char_t* buf, qse_size_t bsz, const qse_char_t* str, qse_size_t len) +{ + qse_char_t* p, * p2; + const qse_char_t* end; + + p = buf; p2 = buf + bsz; end = str + len; + + while (p < p2) + { + if (str >= end) break; + *p++ = *str++; + } + + return p - buf; +} + qse_size_t qse_strfcpy ( qse_char_t* buf, const qse_char_t* fmt, const qse_char_t* str[]) { @@ -326,6 +359,62 @@ fini: return b - buf; } +qse_size_t qse_strxsubst ( + qse_char_t* buf, qse_size_t bsz, const qse_char_t* fmt, + qse_strxsubst_subst_t subst, void* ctx) +{ + qse_char_t* b = buf; + qse_char_t* end = buf + bsz - 1; + const qse_char_t* f = fmt; + + if (bsz <= 0) return 0; + + while (*f != QSE_T('\0')) + { + if (*f == QSE_T('$')) + { + if (f[1] == QSE_T('{')) + { + const qse_char_t* tmp; + qse_cstr_t ident; + + f += 2; /* skip ${ */ + tmp = f; /* mark the beginning */ + + /* scan an enclosed segment */ + while (*f != QSE_T('\0') && *f != QSE_T('}')) f++; + + if (*f != QSE_T('}')) + { + /* 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_T('$')) f++; + } + + normal: + if (b >= end) break; + *b++ = *f++; + } + +fini: + *b = QSE_T('\0'); + return b - buf; +} + + qse_size_t qse_strxcat (qse_char_t* buf, qse_size_t bsz, const qse_char_t* str) { qse_char_t* p, * p2; diff --git a/qse/samples/cmn/str.c b/qse/samples/cmn/str.c index da185fef..29fbc630 100644 --- a/qse/samples/cmn/str.c +++ b/qse/samples/cmn/str.c @@ -508,7 +508,44 @@ static int test11 (void) return 0; } +qse_char_t* subst (qse_char_t* buf, qse_size_t bsz, const qse_cstr_t* ident, void* ctx) +{ + if (qse_strxcmp (ident->ptr, ident->len, QSE_T("USER")) == 0) + { + return buf + qse_strxput (buf, bsz, QSE_T("sam")); + } + else if (qse_strxcmp (ident->ptr, ident->len, QSE_T("GROUP")) == 0) + { + return buf + qse_strxput (buf, bsz, QSE_T("coders")); + } + + /* don't do anything */ + return buf; +} + static int test12 (void) +{ + qse_char_t buf[24]; + qse_size_t i, j; + + for (i = 0; i <= QSE_COUNTOF(buf); i++) + { + qse_strcpy (buf, QSE_T("AAAAAAAAAAAAAAAAAAAAAAA")); + qse_strxsubst (buf, i, QSE_T("user=${USER},group=${GROUP}"), subst, QSE_NULL); + qse_printf (QSE_T("bufsize=%02d, buf=[%-25s] "), i, buf); + + qse_printf (QSE_T("[")); + for (j = 0; j < QSE_COUNTOF(buf); j++) + { + if (buf[j] == QSE_T('\0')) qse_printf (QSE_T("*")); + else qse_printf (QSE_T("%c"), buf[j]); + } + qse_printf (QSE_T("]\n")); + } + return 0; +} + +static int test13 (void) { qse_char_t a1[] = QSE_T(" this is a test string "); qse_char_t a2[] = QSE_T(" this is a test string "); @@ -527,7 +564,7 @@ static int test12 (void) return 0; } -static int test13 (void) +static int test14 (void) { qse_char_t a1[] = QSE_T("abcdefghijklmnopqrstuvwxyz"); qse_str_t x; @@ -571,6 +608,7 @@ int main () R (test11); R (test12); R (test13); + R (test14); return 0; }