diff --git a/qse/include/qse/cmn/str.h b/qse/include/qse/cmn/str.h index 0fe0d984..436c4125 100644 --- a/qse/include/qse/cmn/str.h +++ b/qse/include/qse/cmn/str.h @@ -2730,6 +2730,12 @@ QSE_EXPORT qse_size_t qse_mbs_pac ( qse_mbs_t* str ); +QSE_EXPORT qse_size_t qse_mbs_fcat ( + qse_mbs_t* str, + const qse_mchar_t* fmt, + ... +); + /** * The qse_wcs_open() function creates a dynamically resizable wide-character * string. @@ -2915,6 +2921,12 @@ QSE_EXPORT qse_size_t qse_wcs_pac ( qse_wcs_t* str ); +QSE_EXPORT qse_size_t qse_wcs_fcat ( + qse_wcs_t* str, + const qse_wchar_t* fmt, + ... +); + #if defined(QSE_CHAR_IS_MCHAR) # define qse_str_setmmgr(str,mmgr) qse_mbs_wetmmgr(str,mmgr) # define qse_str_getmmgr(str) qse_mbs_getmmgr(str) @@ -2942,6 +2954,7 @@ QSE_EXPORT qse_size_t qse_wcs_pac ( # define qse_str_del(str,index,size) qse_mbs_del(str,index,size) # define qse_str_trm(str) qse_mbs_trm(str) # define qse_str_pac(str) qse_mbs_pac(str) +# define qse_str_fcat qse_mbs_fcat #else # define qse_str_setmmgr(str,mmgr) qse_wcs_wetmmgr(str,mmgr) # define qse_str_getmmgr(str) qse_wcs_getmmgr(str) @@ -2969,6 +2982,7 @@ QSE_EXPORT qse_size_t qse_wcs_pac ( # define qse_str_del(str,index,size) qse_wcs_del(str,index,size) # define qse_str_trm(str) qse_wcs_trm(str) # define qse_str_pac(str) qse_wcs_pac(str) +# define qse_str_fcat qse_wcs_fcat #endif diff --git a/qse/lib/cmn/str-dyn.c b/qse/lib/cmn/str-dyn.c index bec6ae44..13c4b304 100644 --- a/qse/lib/cmn/str-dyn.c +++ b/qse/lib/cmn/str-dyn.c @@ -19,8 +19,49 @@ */ #include +#include #include "mem.h" +static int put_mchar_null (qse_mchar_t c, void* ctx) +{ + return 1; +} + +static int put_wchar_null (qse_wchar_t c, void* ctx) +{ + return 1; +} + +static int put_mchar (qse_mchar_t c, void* ctx) +{ + qse_mbs_t* str = (qse_mbs_t*)ctx; + if (str->val.len < str->capa) str->val.ptr[str->val.len++] = c; + return 1; +} + +static int put_wchar (qse_wchar_t c, void* ctx) +{ + qse_wcs_t* str = (qse_wcs_t*)ctx; + if (str->val.len < str->capa) str->val.ptr[str->val.len++] = c; + return 1; +} + +static int wcs_to_mbs ( + const qse_wchar_t* wcs, qse_size_t* wcslen, + qse_mchar_t* mbs, qse_size_t* mbslen, void* ctx) +{ + return qse_wcsntombsnwithcmgr (wcs, wcslen, mbs, mbslen, qse_getdflcmgr()); +} + +static int mbs_to_wcs ( + const qse_mchar_t* mbs, qse_size_t* mbslen, + qse_wchar_t* wcs, qse_size_t* wcslen, void* ctx) +{ + return qse_mbsntowcsnwithcmgr (mbs, mbslen, wcs, wcslen, qse_getdflcmgr()); +} + +/* -------------------------------------------------------- */ + #undef char_t #undef xstr_t #undef str_sizer_t @@ -29,6 +70,11 @@ #undef strncpy #undef strxpac #undef strxtrm +#undef fmtout_t +#undef fmtout +#undef put_char_null +#undef put_char +#undef conv_char #undef str_t #undef str_open #undef str_close @@ -57,6 +103,8 @@ #undef str_del #undef str_trm #undef str_pac +#undef str_fmt +#undef str_fcat #define char_t qse_mchar_t #define xstr_t qse_mxstr_t @@ -66,6 +114,11 @@ #define strncpy(x,y,z) qse_mbsncpy(x,y,z) #define strxpac(x,y) qse_mbsxpac(x,y) #define strxtrm(x,y) qse_mbsxtrm(x,y) +#define fmtout_t qse_mfmtout_t +#define fmtout qse_mfmtout +#define put_char_null put_mchar_null +#define put_char put_mchar +#define conv_char wcs_to_mbs #define str_t qse_mbs_t #define str_open qse_mbs_open #define str_close qse_mbs_close @@ -94,6 +147,8 @@ #define str_del qse_mbs_del #define str_trm qse_mbs_trm #define str_pac qse_mbs_pac +#define str_fmt qse_mbs_fmt +#define str_fcat qse_mbs_fcat #include "str-dyn.h" /* -------------------------------------------------------- */ @@ -106,6 +161,11 @@ #undef strncpy #undef strxpac #undef strxtrm +#undef fmtout_t +#undef fmtout +#undef put_char_null +#undef put_char +#undef conv_char #undef str_t #undef str_open #undef str_close @@ -134,6 +194,8 @@ #undef str_del #undef str_trm #undef str_pac +#undef str_fmt +#undef str_fcat #define char_t qse_wchar_t #define xstr_t qse_wxstr_t @@ -143,6 +205,11 @@ #define strncpy(x,y,z) qse_wcsncpy(x,y,z) #define strxpac(x,y) qse_wcsxpac(x,y) #define strxtrm(x,y) qse_wcsxtrm(x,y) +#define fmtout_t qse_wfmtout_t +#define fmtout qse_wfmtout +#define put_char_null put_wchar_null +#define put_char put_wchar +#define conv_char mbs_to_wcs #define str_t qse_wcs_t #define str_open qse_wcs_open #define str_close qse_wcs_close @@ -171,4 +238,6 @@ #define str_del qse_wcs_del #define str_trm qse_wcs_trm #define str_pac qse_wcs_pac +#define str_fmt qse_wcs_fmt +#define str_fcat qse_wcs_fcat #include "str-dyn.h" diff --git a/qse/lib/cmn/str-dyn.h b/qse/lib/cmn/str-dyn.h index bf360d20..9320c6d8 100644 --- a/qse/lib/cmn/str-dyn.h +++ b/qse/lib/cmn/str-dyn.h @@ -20,6 +20,8 @@ #include #include "mem.h" +#include "fmt.h" +#include str_t* str_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_size_t capa) { @@ -71,7 +73,7 @@ int str_init (str_t* str, qse_mmgr_t* mmgr, qse_size_t capa) void str_fini (str_t* str) { - if (str->val.ptr != QSE_NULL) QSE_MMGR_FREE (str->mmgr, str->val.ptr); + if (str->val.ptr) QSE_MMGR_FREE (str->mmgr, str->val.ptr); } qse_mmgr_t* str_getmmgr (str_t* mbs) @@ -424,3 +426,53 @@ qse_size_t str_pac (str_t* str) } +qse_size_t str_fmt (str_t* str, const char_t* fmt, ...) +{ + return (qse_size_t)-1; +} + +qse_size_t str_fcat (str_t* str, const char_t* fmt, ...) +{ + va_list ap; + fmtout_t fo; + int x; + qse_size_t old_len, inc; + + old_len = str->val.len; + + fo.limit = QSE_TYPE_MAX(qse_size_t) - 1; + fo.ctx = str; + fo.put = str->val.ptr? put_char: put_char_null; + fo.conv = conv_char; + + va_start (ap, fmt); + x = fmtout (fmt, &fo, ap); + va_end (ap); + + if (x <= -1) + { + str->val.len = old_len; + return (qse_size_t)-1; + } + + if (str->val.ptr == QSE_NULL || str->val.len - old_len < fo.count) + { + str->val.len = old_len; + + /* resizing is required */ + x = resize_for_ncat (str, fo.count); + + if (x <= -1) return (qse_size_t)-1; + if (x >= 1) + { + fo.put = put_char; + + va_start (ap, fmt); + x = fmtout (fmt, &fo, ap); + va_end (ap); + } + } + + str->val.ptr[str->val.len] = T('\0'); + return str->val.len; +} diff --git a/qse/lib/cmn/str-fmt.c b/qse/lib/cmn/str-fmt.c index 7807b078..50eca019 100644 --- a/qse/lib/cmn/str-fmt.c +++ b/qse/lib/cmn/str-fmt.c @@ -39,21 +39,21 @@ struct wbuf_t typedef struct wbuf_t wbuf_t; +static int put_mchar_null (qse_mchar_t c, void* ctx) +{ + return 1; +} + +static int put_wchar_null (qse_wchar_t c, void* ctx) +{ + return 1; +} + static int put_mchar (qse_mchar_t c, void* ctx) { mbuf_t* buf = (mbuf_t*)ctx; - /* do not copy but return success if the buffer pointer - * points to NULL. this is to let the caller specify - * NULL as a buffer to get the length required for the - * full formatting excluding the terminating NULL. - * The actual length required is the return value + 1. */ - if (buf->ptr == QSE_NULL) - { - buf->len++; - return 1; - } - else if (buf->len < buf->capa) + if (buf->len < buf->capa) { buf->ptr[buf->len++] = c; return 1; @@ -67,13 +67,6 @@ static int put_wchar (qse_wchar_t c, void* ctx) { wbuf_t* buf = (wbuf_t*)ctx; - /* do not copy but return success if the buffer pointer - * points to NULL. this is to let the caller specify - * NULL as a buffer to get the length required for the - * full formatting excluding the terminating NULL. - * The actual length required is the return value + 1. */ - if (buf->ptr == QSE_NULL) return 1; - if (buf->len < buf->capa) { buf->ptr[buf->len++] = c; @@ -105,6 +98,7 @@ static int mbs_to_wcs ( #undef buf_t #undef fmtout_t #undef fmtout +#undef put_char_null #undef put_char #undef conv_char #undef strfmt @@ -115,6 +109,7 @@ static int mbs_to_wcs ( #define buf_t mbuf_t #define fmtout_t qse_mfmtout_t #define fmtout qse_mfmtout +#define put_char_null put_mchar_null #define put_char put_mchar #define conv_char wcs_to_mbs #define strfmt qse_mbsfmt @@ -128,6 +123,7 @@ static int mbs_to_wcs ( #undef buf_t #undef fmtout_t #undef fmtout +#undef put_char_null #undef put_char #undef conv_char #undef strfmt @@ -138,6 +134,7 @@ static int mbs_to_wcs ( #define buf_t wbuf_t #define fmtout_t qse_wfmtout_t #define fmtout qse_wfmtout +#define put_char_null put_wchar_null #define put_char put_wchar #define conv_char mbs_to_wcs #define strfmt qse_wcsfmt diff --git a/qse/lib/cmn/str-fmt.h b/qse/lib/cmn/str-fmt.h index 75a19e81..81836edb 100644 --- a/qse/lib/cmn/str-fmt.h +++ b/qse/lib/cmn/str-fmt.h @@ -32,7 +32,7 @@ qse_size_t strfmt (char_t* buf, const char_t* fmt, ...) fo.limit = QSE_TYPE_MAX(qse_size_t) - 1; fo.ctx = &b; - fo.put = put_char; + fo.put = b.ptr? put_char: put_char_null; fo.conv = conv_char; /* no I/O error must occurred by fmtout but there can be @@ -47,12 +47,14 @@ qse_size_t strfmt (char_t* buf, const char_t* fmt, ...) * you don't need to worry about an error. */ /* null-terminate regardless of error */ - b.ptr[b.len] = T('\0'); + if (b.ptr) + { + QSE_ASSERT (fo.count == b.len); + b.ptr[b.len] = T('\0'); + } if (x <= -1) return QSE_TYPE_MAX(qse_size_t); - - QSE_ASSERT (fo.count == b.len); - return b.len; + return fo.count; } qse_size_t strxfmt (char_t* buf, qse_size_t len, const char_t* fmt, ...) @@ -74,7 +76,7 @@ qse_size_t strxfmt (char_t* buf, qse_size_t len, const char_t* fmt, ...) fo.limit = QSE_TYPE_MAX(qse_size_t) - 1; fo.ctx = &b; - fo.put = put_char; + fo.put = b.ptr? put_char: put_char_null; fo.conv = conv_char; va_start (ap, fmt); @@ -87,10 +89,13 @@ qse_size_t strxfmt (char_t* buf, qse_size_t len, const char_t* fmt, ...) * you don't need to worry about an error. */ /* null-terminate regardless of error */ - if (len > 0) b.ptr[b.len] = T('\0'); - if (x <= -1) return QSE_TYPE_MAX(qse_size_t); + if (b.ptr) + { + QSE_ASSERT (fo.count == b.len); + if (len > 0) b.ptr[b.len] = T('\0'); + } - QSE_ASSERT (fo.count == b.len); - return b.len; + if (x <= -1) return QSE_TYPE_MAX(qse_size_t); + return fo.count; }