* added qse_strxput() and qse_strxnput()

* added qse_strxsubst ()
This commit is contained in:
hyung-hwan 2010-04-30 07:14:13 +00:00
parent 2a045b7ff0
commit e0ab4fca90
3 changed files with 211 additions and 8 deletions

View File

@ -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 <qse/macros.h>
/** @file
* <qse/cmn/str.h> 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 <qse/types.h> 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')<base)? (c-QSE_T('0')): base): \
@ -168,14 +183,35 @@ qse_size_t qse_strxncpy (
qse_size_t len
);
/**
* The qse_strxput() function copies the string @a str into the buffer @a buf
* of the size @a bsz. Unlike qse_strxcpy(), it does not null-terminate the
* buffer.
*/
qse_size_t qse_strxput (
qse_char_t* buf,
qse_size_t bsz,
const qse_char_t* str
);
qse_size_t qse_strxnput (
qse_char_t* buf,
qse_size_t bsz,
const qse_char_t* str,
qse_size_t len
);
/**
* The qse_strfcpy() function formats a string by position.
* The position specifier is a number enclosed in ${ and }.
* When ${ is preceeded by a backslash, it is treated literally.
* A sameple format string containing the position specifiers are shown below:
* See the example below:
* @code
* "${1} ${3} ${2} \\${1} string"
* qse_char_t buf[256]
* qse_char_t* colors[] = { QSE_T("blue"), QSE_T("green"), QSE_T("red") };
* qse_strfcpy(buf, QSE_T("RGB: ${2}, ${1}, ${0}"), colors);
* @endcode
* @sa qse_strfncpy, qse_strxfcpy, qse_strxfncpy
*/
qse_size_t qse_strfcpy (
qse_char_t* buf,
@ -185,6 +221,9 @@ qse_size_t qse_strfcpy (
/**
* The qse_strfncpy() function formats a string by position.
* It differs from qse_strfcpy() in that @str is an array of the
* #qse_cstr_t type.
* @sa qse_strfcpy, qse_strxfcpy, qse_strxfncpy
*/
qse_size_t qse_strfncpy (
qse_char_t* buf,
@ -194,6 +233,14 @@ qse_size_t qse_strfncpy (
/**
* The qse_strxfcpy() function formats a string by position.
* It differs from qse_strfcpy() in that @a buf is length-bounded of @a bsz
* characters.
* @code
* qse_char_t buf[256]
* qse_char_t* colors[] = { QSE_T("blue"), QSE_T("green"), QSE_T("red") };
* qse_strxfcpy(buf, QSE_COUNTOF(buf), QSE_T("RGB: ${2}, ${1}, ${0}"), colors);
* @endcode
* @sa qse_strfcpy, qse_strfncpy, qse_strxfncpy
*/
qse_size_t qse_strxfcpy (
qse_char_t* buf,
@ -204,6 +251,9 @@ qse_size_t qse_strxfcpy (
/**
* The qse_strxfncpy() function formats a string by position.
* It differs from qse_strfcpy() in that @a buf is length-bounded of @a bsz
* characters and @a str is an array of the #qse_cstr_t type.
* @sa qse_strfcpy, qse_strfncpy, qse_strxfcpy
*/
qse_size_t qse_strxfncpy (
qse_char_t* buf,
@ -212,6 +262,32 @@ qse_size_t qse_strxfncpy (
const qse_cstr_t str[]
);
/**
* The qse_strxsubst() function expands @a fmt into a buffer @a buf of the size
* @a bsz by substituting new values for ${} segments within it. The actual
* substitution is made by invoking the callback function @a subst.
* @code
* 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"));
* 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,

View File

@ -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;

View File

@ -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;
}