* added qse_strxput() and qse_strxnput()
* added qse_strxsubst ()
This commit is contained in:
parent
2a045b7ff0
commit
e0ab4fca90
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user