* 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.
|
Copyright 2006-2009 Chung, Hyung-Hwan.
|
||||||
This file is part of QSE.
|
This file is part of QSE.
|
||||||
@ -25,8 +25,7 @@
|
|||||||
#include <qse/macros.h>
|
#include <qse/macros.h>
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
* <qse/cmn/str.h> defines various functions, types, macros to manipulate
|
* Various functions, types, macros for string manipulation.
|
||||||
* a string.
|
|
||||||
*
|
*
|
||||||
* The qse_cstr_t type and the qse_xstr_t defined in <qse/types.h> helps you
|
* The qse_cstr_t type and the qse_xstr_t defined in <qse/types.h> helps you
|
||||||
* dealing with a string pointer and length.
|
* dealing with a string pointer and length.
|
||||||
@ -39,7 +38,11 @@
|
|||||||
#define QSE_STR_SIZER(s) ((s)->sizer) /**< buffer resizer function */
|
#define QSE_STR_SIZER(s) ((s)->sizer) /**< buffer resizer function */
|
||||||
|
|
||||||
typedef struct qse_str_t qse_str_t;
|
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.
|
* The qse_str_t type defines a dynamically resizable string.
|
||||||
@ -53,6 +56,18 @@ struct qse_str_t
|
|||||||
qse_size_t capa; /**< buffer capacity */
|
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) */
|
/* int qse_chartonum (qse_char_t c, int base) */
|
||||||
#define QSE_CHARTONUM(c,base) \
|
#define QSE_CHARTONUM(c,base) \
|
||||||
((c>=QSE_T('0') && c<=QSE_T('9'))? ((c-QSE_T('0')<base)? (c-QSE_T('0')): 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
|
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 qse_strfcpy() function formats a string by position.
|
||||||
* The position specifier is a number enclosed in ${ and }.
|
* The position specifier is a number enclosed in ${ and }.
|
||||||
* When ${ is preceeded by a backslash, it is treated literally.
|
* 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
|
* @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
|
* @endcode
|
||||||
|
* @sa qse_strfncpy, qse_strxfcpy, qse_strxfncpy
|
||||||
*/
|
*/
|
||||||
qse_size_t qse_strfcpy (
|
qse_size_t qse_strfcpy (
|
||||||
qse_char_t* buf,
|
qse_char_t* buf,
|
||||||
@ -185,6 +221,9 @@ qse_size_t qse_strfcpy (
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The qse_strfncpy() function formats a string by position.
|
* 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_size_t qse_strfncpy (
|
||||||
qse_char_t* buf,
|
qse_char_t* buf,
|
||||||
@ -194,6 +233,14 @@ qse_size_t qse_strfncpy (
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The qse_strxfcpy() function formats a string by position.
|
* 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_size_t qse_strxfcpy (
|
||||||
qse_char_t* buf,
|
qse_char_t* buf,
|
||||||
@ -204,6 +251,9 @@ qse_size_t qse_strxfcpy (
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The qse_strxfncpy() function formats a string by position.
|
* 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_size_t qse_strxfncpy (
|
||||||
qse_char_t* buf,
|
qse_char_t* buf,
|
||||||
@ -212,6 +262,32 @@ qse_size_t qse_strxfncpy (
|
|||||||
const qse_cstr_t str[]
|
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_size_t qse_strxcat (
|
||||||
qse_char_t* buf,
|
qse_char_t* buf,
|
||||||
qse_size_t bsz,
|
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.
|
Copyright 2006-2009 Chung, Hyung-Hwan.
|
||||||
This file is part of QSE.
|
This file is part of QSE.
|
||||||
@ -122,6 +122,39 @@ qse_size_t qse_strxncpy (
|
|||||||
return n;
|
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_size_t qse_strfcpy (
|
||||||
qse_char_t* buf, const qse_char_t* fmt, const qse_char_t* str[])
|
qse_char_t* buf, const qse_char_t* fmt, const qse_char_t* str[])
|
||||||
{
|
{
|
||||||
@ -326,6 +359,62 @@ fini:
|
|||||||
return b - buf;
|
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_size_t qse_strxcat (qse_char_t* buf, qse_size_t bsz, const qse_char_t* str)
|
||||||
{
|
{
|
||||||
qse_char_t* p, * p2;
|
qse_char_t* p, * p2;
|
||||||
|
@ -508,7 +508,44 @@ static int test11 (void)
|
|||||||
return 0;
|
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)
|
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 a1[] = QSE_T(" this is a test string ");
|
||||||
qse_char_t a2[] = 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test13 (void)
|
static int test14 (void)
|
||||||
{
|
{
|
||||||
qse_char_t a1[] = QSE_T("abcdefghijklmnopqrstuvwxyz");
|
qse_char_t a1[] = QSE_T("abcdefghijklmnopqrstuvwxyz");
|
||||||
qse_str_t x;
|
qse_str_t x;
|
||||||
@ -571,6 +608,7 @@ int main ()
|
|||||||
R (test11);
|
R (test11);
|
||||||
R (test12);
|
R (test12);
|
||||||
R (test13);
|
R (test13);
|
||||||
|
R (test14);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user