diff --git a/README.md b/README.md index 299ea8d..b77e848 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # dstr ## 1、介绍 -这是一个在 RT-Thread 上,基于ANSI/ISO C(C89)实现的动态字符串软件包。 +这是一个在 RT-Thread 上,基于 ANSI/ISO C89 实现的动态字符串软件包。 ### 1.1 目录结构 @@ -17,23 +17,29 @@ dstr package 遵循 LGPLv2.1 许可,详见 `LICENSE` 文件。 ### 1.3 依赖 -对 RT-Thread 无依赖,也可用于裸机。 +- 对 RT-Thread 无依赖,也可用于裸机。 + + ## 2、如何打开 dstr -使用 dstr package 需要在 RT-Thread 的包管理器中选择它,具体路径如下: +使用 dstr package 需要在 RT-Thread 的包管理器中选择它,详情如下: ``` -RT-Thread online packages +RT-Thread online packages ---> miscellaneous packages ---> [*] dstr: a dynamic string package + Version (latest) ---> + dstr Options ---> + [*] dstr test example + ``` -然后让 RT-Thread 的包管理器自动更新,或者使用 `pkgs --update` 命令更新包到 BSP 中。 +保存 menuconfig 配置后使用 `pkgs --update` 命令下载软件包 ## 3、使用 dstr -使用dstr可参考例子工程,该工程位于:[/examples/examples_dstr.c](examples/examples_dstr.c) +使用 dstr 可参考例子代码,该代码位于:[/dstr/examples/examples_dstr.c](dstr/examples/examples_dstr.c) ### 3.1 创建动态字符串对象 `rt_dstr_t *rt_dstr_new(const char *str);` @@ -41,7 +47,7 @@ RT-Thread online packages | 参数 | 描述 | | ---- | ---- | | name | 源字符串 | -| return | 创建成功,将返回dstr对象指针;创建失败则返回NULL | +| return | 创建成功,将返回 dstr 对象指针;创建失败则返回 NULL | ### 3.2 删除动态字符串对象 @@ -54,24 +60,24 @@ RT-Thread online packages ### 3.3 动态字符串连接 -`rt_dstr_t *rt_dstr_cat(rt_dstr_t *const thiz, const char *src);` +`rt_dstr_t *rt_dstr_cat(rt_dstr_t *thiz, const char *src);` | 参数 | 描述 | | ---- | ---- | | thiz | 动态字符串对象 | | src | 源字符串 | -| return | cat成功,将返回dstr对象指针;cat失败,则返回NULL,但不会更改thiz,交由用户处理 | +| return | cat 成功,将返回 dstr 对象指针;cat 失败,则返回 NULL,但不会更改 thiz,交由用户处理 | ### 3.4 动态字符串连接(连接几个字符) -`rt_dstr_t *rt_dstr_ncat(rt_dstr_t *const thiz, const char *src, size_t n);` +`rt_dstr_t *rt_dstr_ncat(rt_dstr_t *thiz, const char *src, size_t n);` | 参数 | 描述 | | ---- | ---- | | thiz | 动态字符串对象 | | src | 源字符串 | | n | 需要连接几个字符 | -| return | cat成功,将返回dstr对象指针;cat失败,则返回NULL,但不会更改thiz,交由用户处理 | +| return | cat 成功,将返回 dstr 对象指针;cat 失败,则返回 NULL,但不会更改 thiz,交由用户处理 | ### 3.5 动态字符串比较 `int rt_dstr_cmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2);` @@ -115,25 +121,36 @@ RT-Thread online packages | 参数 | 描述 | | ---- | ---- | | thiz | 动态字符串对象 | -| return | 参数非NULL,将返回动态字符串长度;参数为NULL则返回-1 | +| return | 参数非 NULL,将返回动态字符串长度;参数为 NULL 则返回-1 | ### 3.9 字符串格式化输出 -`int rt_dstr_sprintf(rt_dstr_t *const thiz, const char *fmt, ...);` +`rt_dstr_t *rt_dstr_sprintf(rt_dstr_t *thiz, const char *fmt, ...);` | 参数 | 描述 | | ---- | ---- | | thiz | 动态字符串对象 | | fmt | 格式化字符串 | | argument... | 可选参数,任何类型的数据 | -| return | 返回动态字符串长度 | +| return | 返回 dstr 对象指针 | + +### 3.10 字符串格式化输出(以追加的方式实现) + +`rt_dstr_t *rt_dstr_append_printf(rt_dstr_t *thiz, const char *format, ...);` + +| 参数 | 描述 | +| ---- | -------------- | +| thiz | 动态字符串对象 | +|fmt|格式化字符串| +| argument... | 可选参数,任何类型的数据 | +| return | 返回 dstr 对象指针 | ## 4、注意事项 暂无 -## 5、联系方式 & 感谢 +## 5、联系方式 * 维护:[never](https://github.com/neverxie) * 主页:https://github.com/RT-Thread-packages/dstr diff --git a/examples/examples_dstr.c b/examples/examples_dstr.c index ea15de4..3537879 100644 --- a/examples/examples_dstr.c +++ b/examples/examples_dstr.c @@ -20,13 +20,15 @@ * Change Logs: * Date Author Notes * 2018-06-07 never the first version + * 2018-07-25 never add sample API */ #include #include #include "dstr.h" +#include -void rt_dstr_printf(rt_dstr_t *thiz) +void rt_dstr_print(rt_dstr_t *thiz) { if (thiz == NULL) return; @@ -35,40 +37,58 @@ void rt_dstr_printf(rt_dstr_t *thiz) void dstr_test_new(void) { + rt_kprintf("\n"); + rt_dstr_t *p = NULL; - + p = rt_dstr_new("new dstr"); - rt_dstr_printf(p); + rt_dstr_print(p); rt_dstr_del(p); + rt_kprintf("\n"); } void dstr_test_cat(void) -{ - rt_dstr_t *p = NULL; - - p = rt_dstr_new("cat"); - - rt_dstr_cat(p, " dstr"); - - rt_dstr_printf(p); - - rt_dstr_del(p); +{ + rt_dstr_t *p1 = NULL, *p2 = NULL; + const char *str = "cat "; + + p1 = rt_dstr_cat(p1, "cat sample1"); + + rt_dstr_print(p1); + + rt_dstr_del(p1); + + p2 = rt_dstr_new(str); + + rt_dstr_cat(p2, "sample2"); + + rt_dstr_print(p1); + + rt_dstr_del(p1); + + rt_kprintf("\n"); } void dstr_test_ncat(void) -{ - rt_dstr_t *p1 = NULL; - - p1 = rt_dstr_new("ncat"); - - rt_dstr_ncat(p1, " dstrnnn", 5); - - rt_dstr_ncat(p1, "1234", 3); - - rt_dstr_printf(p1); - rt_kprintf("p2 str:%s\n",p1->str); - +{ + rt_dstr_t *p1 = NULL, *p2 = NULL; + const char *str = "ncat "; + + p1 = rt_dstr_ncat(p1, "ncat sample1", 12); + + rt_dstr_print(p1); + rt_dstr_del(p1); + + p2 = rt_dstr_new(str); + + rt_dstr_ncat(p2, "sample2222", 7); + + rt_dstr_print(p1); + + rt_dstr_del(p1); + + rt_kprintf("\n"); } void dstr_test_cmp(void) @@ -76,29 +96,29 @@ void dstr_test_cmp(void) rt_dstr_t *p1 = NULL; rt_dstr_t *p2 = NULL; int res = 0; - + p1 = rt_dstr_new("helle"); p2 = rt_dstr_new("hellc"); - + res = rt_dstr_cmp(p1, p2); rt_kprintf("cmp result: %d\n", res); - + rt_dstr_del(p1); rt_dstr_del(p2); - + // NULL p1 = rt_dstr_new("abc"); res = rt_dstr_cmp(p1, NULL); rt_kprintf("s2:NULL result: %d\n", res); rt_dstr_del(p1); - + p1 = rt_dstr_new("efg"); res = rt_dstr_cmp(NULL, p1); rt_kprintf("s1:NULL result: %d\n", res); rt_dstr_del(p1); res = rt_dstr_cmp(NULL, NULL); - rt_kprintf("two NULL result: %d\n", res); + rt_kprintf("two NULL result: %d\n\n", res); } void dstr_test_ncmp(void) @@ -106,29 +126,29 @@ void dstr_test_ncmp(void) rt_dstr_t *p1 = NULL; rt_dstr_t *p2 = NULL; int res = 0; - + p1 = rt_dstr_new("hello"); p2 = rt_dstr_new("hella"); - + res = rt_dstr_ncmp(p1, p2, 5); rt_kprintf("ncmp result: %d\n", res); - + rt_dstr_del(p1); rt_dstr_del(p2); - - // NULL + + /* NULL */ p1 = rt_dstr_new("abc"); res = rt_dstr_ncmp(p1, NULL, 2); rt_kprintf("s2:NULL ncmp result: %d\n", res); rt_dstr_del(p1); - + p1 = rt_dstr_new("efg"); res = rt_dstr_ncmp(NULL, p1, 3); rt_kprintf("s1:NULL ncmp result: %d\n", res); rt_dstr_del(p1); res = rt_dstr_ncmp(NULL, NULL, 4); - rt_kprintf("two NULL ncmp result: %d\n", res); + rt_kprintf("two NULL ncmp result: %d\n\n", res); } void dstr_test_casecmp(void) @@ -136,71 +156,112 @@ void dstr_test_casecmp(void) rt_dstr_t *p1 = NULL; rt_dstr_t *p2 = NULL; int res = 0; - + p1 = rt_dstr_new("hello"); p2 = rt_dstr_new("HELLO"); - + res = rt_dstr_casecmp(p1, p2); rt_kprintf("casecmp result: %d\n", res); - + rt_dstr_del(p1); rt_dstr_del(p2); - - // NULL + + /* NULL */ p1 = rt_dstr_new("abc"); res = rt_dstr_casecmp(p1, NULL); rt_kprintf("s2:NULL casecmp result: %d\n", res); rt_dstr_del(p1); - + p1 = rt_dstr_new("efg"); res = rt_dstr_casecmp(NULL, p1); rt_kprintf("s1:NULL casecmp result: %d\n", res); rt_dstr_del(p1); res = rt_dstr_casecmp(NULL, NULL); - rt_kprintf("two NULL casecmp result: %d\n", res); + rt_kprintf("two NULL casecmp result: %d\n\n", res); } void dstr_test_strlen(void) { rt_dstr_t *p1 = NULL; int res = 0; - + p1 = rt_dstr_new("hello strlen"); - + res = rt_dstr_strlen(p1); - + if (res == -1) return; - + rt_kprintf("length: %d\n", res); - + rt_dstr_del(p1); + + rt_kprintf("\n"); } void dstr_test_sprintf(void) -{ - const char *src = "test sprintf"; +{ + const char *src = "sprintf"; rt_dstr_t *p1 = NULL; rt_dstr_t *p2 = NULL; - - // string format - p1 = rt_dstr_new(""); - + + /* string format */ + p1 = rt_dstr_new("test"); + rt_dstr_sprintf(p1, "%s", src); - - rt_dstr_printf(p1); - + + rt_dstr_print(p1); + rt_dstr_del(p1); - - // hex format + + /* hex format */ p2 = rt_dstr_new(""); - + rt_dstr_sprintf(p2, "%08x", 0x20180604); - - rt_dstr_printf(p2); - - rt_dstr_del(p2); + + rt_dstr_print(p2); + + rt_dstr_del(p2); + + rt_kprintf("\n"); +} + +rt_dstr_t *path_cat(const char *path, const char *filename) +{ + rt_dstr_t *p = RT_NULL; + + p = rt_dstr_sprintf(p, "%s/%s", path, filename); + + return p; +} + +rt_dstr_t *header_info_cat(char *send_buffer) +{ + rt_dstr_t *p = RT_NULL; + const char *key = "header-key"; + + /* build header for upload */ + p = rt_dstr_append_printf(p, "api-key: %s\r\n", key); + rt_dstr_append_printf(p, "Content-Length: %d\r\n", strlen(send_buffer)); + rt_dstr_cat(p, "Content-Type: application/octet-stream\r\n"); + + return p; +} + +void dstr_test_append(void) +{ + char *buffer = "test of header"; + + rt_dstr_print(path_cat("/home", "bsp/thread.c")); + rt_dstr_del(path_cat("/home", "bsp/thread.c")); + + rt_kprintf("\n"); + + rt_dstr_print(header_info_cat(buffer)); + rt_dstr_del(header_info_cat(buffer)); + + rt_kprintf("\n"); } void dstr_test(void) @@ -213,6 +274,6 @@ void dstr_test(void) dstr_test_casecmp(); dstr_test_strlen(); dstr_test_sprintf(); + dstr_test_append(); } - MSH_CMD_EXPORT(dstr_test, dstr example); diff --git a/inc/dstr.h b/inc/dstr.h index a15c358..1d2537f 100644 --- a/inc/dstr.h +++ b/inc/dstr.h @@ -20,6 +20,7 @@ * Change Logs: * Date Author Notes * 2018-06-07 never the first version + * 2018-07-25 never add append_printf() and modify some APIs */ #ifndef __DSTR_H__ @@ -30,15 +31,15 @@ struct rt_dstr { char *str; - size_t length; // allocated space + size_t length; /* allocated space. e.g.: "abc" + '\0' */ }; typedef struct rt_dstr rt_dstr_t; rt_dstr_t *rt_dstr_new(const char *str); void rt_dstr_del(rt_dstr_t *thiz); -rt_dstr_t *rt_dstr_cat(rt_dstr_t *const thiz, const char *src); -rt_dstr_t *rt_dstr_ncat(rt_dstr_t *const thiz, const char *src, size_t n); +rt_dstr_t *rt_dstr_cat(rt_dstr_t *thiz, const char *src); +rt_dstr_t *rt_dstr_ncat(rt_dstr_t *thiz, const char *src, size_t n); int rt_dstr_cmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2); int rt_dstr_ncmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2, size_t n); @@ -46,6 +47,6 @@ int rt_dstr_ncmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2, size_t n); int rt_dstr_casecmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2); int rt_dstr_strlen(rt_dstr_t *const thiz); -int rt_dstr_sprintf(rt_dstr_t *const thiz, const char *fmt, ...); - +rt_dstr_t *rt_dstr_sprintf(rt_dstr_t *thiz, const char *fmt, ...); +rt_dstr_t *rt_dstr_append_printf(rt_dstr_t *thiz, const char *format, ...); #endif /* __DSTR_H__ */ diff --git a/src/dstr.c b/src/dstr.c index b031ddb..9b682f0 100644 --- a/src/dstr.c +++ b/src/dstr.c @@ -20,6 +20,7 @@ * Change Logs: * Date Author Notes * 2018-06-07 never the first version + * 2018-07-25 never add append_printf() and modify some APIs */ #include @@ -46,13 +47,13 @@ rt_dstr_t *rt_dstr_new(const char *str) { rt_dstr_t *thiz = NULL; - + if (str == NULL) { dbg_log(DBG_ERROR, "new.string param error\n"); return NULL; } - + thiz = (rt_dstr_t *)malloc(sizeof(struct rt_dstr)); if (thiz == NULL) { @@ -60,7 +61,7 @@ rt_dstr_t *rt_dstr_new(const char *str) return NULL; } - thiz->length = strlen(str) + 1; // allocated space + thiz->length = strlen(str) + 1; /* allocated space */ thiz->str = (char *)malloc(sizeof(char) * thiz->length); if (thiz->str == NULL) @@ -106,7 +107,7 @@ static int rt_dstr_resize(rt_dstr_t *const thiz, size_t new_spacesize) dbg_log(DBG_ERROR, "resize.thiz param error\n"); return -1; } - + p = (char *)realloc(thiz->str, new_spacesize); if (p == NULL) @@ -115,16 +116,16 @@ static int rt_dstr_resize(rt_dstr_t *const thiz, size_t new_spacesize) return -1; } else - { + { thiz->length = new_spacesize; - dbg_log(DBG_INFO, "new_spacesize:%d\n", thiz->length); + dbg_log(DBG_INFO, "new_spacesize:%d\n", thiz->length); thiz->str = p; return 0; } } /** - * This function appends the src string to the dest object, + * This function appends the src string to the dest object, * overwriting the terminating null byte '\0' at the end of the dest, * and then adds a terminating null byte. * @@ -133,7 +134,7 @@ static int rt_dstr_resize(rt_dstr_t *const thiz, size_t new_spacesize) * * @return the dest dstr */ -rt_dstr_t *rt_dstr_cat(rt_dstr_t *const thiz, const char *src) +rt_dstr_t *rt_dstr_cat(rt_dstr_t *thiz, const char *src) { return rt_dstr_ncat(thiz, src, strlen(src)); } @@ -148,15 +149,20 @@ rt_dstr_t *rt_dstr_cat(rt_dstr_t *const thiz, const char *src) * * @return the dest dstr */ -rt_dstr_t *rt_dstr_ncat(rt_dstr_t *const thiz, const char *src, size_t n) +rt_dstr_t *rt_dstr_ncat(rt_dstr_t *thiz, const char *src, size_t n) { int res = 0; size_t new_spacesize = 0, old_spacesize = 0; - - old_spacesize = thiz->length; // allocated space - new_spacesize = n + old_spacesize; // allocated space - + if (thiz == NULL) + { + thiz = rt_dstr_new(""); + } + + old_spacesize = thiz->length; /* allocated space */ + + new_spacesize = n + old_spacesize; /* allocated space */ + res = rt_dstr_resize(thiz, new_spacesize); if (res == -1) @@ -165,9 +171,9 @@ rt_dstr_t *rt_dstr_ncat(rt_dstr_t *const thiz, const char *src, size_t n) return NULL; } - memcpy(thiz->str + (old_spacesize - 1), src, n); + memcpy(thiz->str + (old_spacesize - 1), src, n); *(thiz->str + (old_spacesize - 1) + n) = '\0'; - + return thiz; } @@ -180,20 +186,20 @@ rt_dstr_t *rt_dstr_ncat(rt_dstr_t *const thiz, const char *src, size_t n) * @return the result */ int rt_dstr_cmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2) -{ +{ char *str1, *str2; - + if ((dstr1 == NULL) && (dstr2 == NULL)) { str1 = NULL; str2 = NULL; } - else if(dstr1 == NULL) + else if (dstr1 == NULL) { str1 = NULL; str2 = dstr2->str; } - else if(dstr2 == NULL) + else if (dstr2 == NULL) { str2 = NULL; str1 = dstr1->str; @@ -203,10 +209,10 @@ int rt_dstr_cmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2) str1 = dstr1->str; str2 = dstr2->str; } - + return strcmp(str1, str2); } - + /** * This function compares dstr1 and dstr2. * @@ -219,18 +225,18 @@ int rt_dstr_cmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2) int rt_dstr_ncmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2, size_t n) { char *str1, *str2; - + if ((dstr1 == NULL) && (dstr2 == NULL)) { str1 = NULL; str2 = NULL; } - else if(dstr1 == NULL) + else if (dstr1 == NULL) { str1 = NULL; str2 = dstr2->str; } - else if(dstr2 == NULL) + else if (dstr2 == NULL) { str2 = NULL; str1 = dstr1->str; @@ -240,7 +246,7 @@ int rt_dstr_ncmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2, size_t n) str1 = dstr1->str; str2 = dstr2->str; } - + return strncmp(str1, str2, n); } @@ -255,18 +261,18 @@ int rt_dstr_ncmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2, size_t n) int rt_dstr_casecmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2) { char *str1, *str2; - + if ((dstr1 == NULL) && (dstr2 == NULL)) { str1 = NULL; str2 = NULL; } - else if(dstr1 == NULL) + else if (dstr1 == NULL) { str1 = NULL; str2 = dstr2->str; } - else if(dstr2 == NULL) + else if (dstr2 == NULL) { str2 = NULL; str1 = dstr1->str; @@ -276,8 +282,8 @@ int rt_dstr_casecmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2) str1 = dstr1->str; str2 = dstr2->str; } - - return strcasecmp (str1, str2); + + return strcasecmp(str1, str2); } /** @@ -292,43 +298,89 @@ int rt_dstr_strlen(rt_dstr_t *const thiz) { if (thiz == NULL) return -1; - + return strlen(thiz->str); } /** - * This function will return the length of a dstr, which terminate will + * This function will return the dest dstr, which terminate will * null character. * * @param thiz the dstr * - * @return the length of dstr + * @return the dest dstr */ -int rt_dstr_sprintf(rt_dstr_t *const thiz, const char *fmt, ...) +rt_dstr_t *rt_dstr_sprintf(rt_dstr_t *thiz, const char *fmt, ...) { va_list arg_ptr; va_list tmp; - int status = 0, res = 0, new_length = 0; - + int new_length = 0; + + if (thiz == NULL) + { + thiz = rt_dstr_new(""); + } + va_start(arg_ptr, fmt); - + va_copy(tmp, arg_ptr); - - new_length = vsnprintf(NULL, 0, fmt, tmp); // strlen("test sprintf") = 12 - + + new_length = vsnprintf(NULL, 0, fmt, tmp); /* strlen("test sprintf") = 12 */ + va_end(tmp); - - status = rt_dstr_resize(thiz, new_length + 1); // allocated space - if (status == -1) + if (rt_dstr_resize(thiz, new_length + 1) == -1) /* allocated space */ { va_end(arg_ptr); - return -1; - } - - res = vsnprintf(thiz->str, new_length + 1, fmt, arg_ptr); + return NULL; + } + + vsnprintf(thiz->str, new_length + 1, fmt, arg_ptr); va_end(arg_ptr); - - return res; + + return thiz; } + +/** + * This function will return the dest dstr, which terminate will + * null character. + * + * @param thiz the dstr + * + * @return the dest dstr + */ +rt_dstr_t *rt_dstr_append_printf(rt_dstr_t *thiz, const char *format, ...) +{ + va_list ap; + va_list tmpa; + char *dst = NULL; + int old_length = 0, new_length = 0; + + if (thiz == NULL) + { + thiz = rt_dstr_new(""); + } + + va_start(ap, format); + + old_length = thiz->length; + + va_copy(tmpa, ap); + new_length = vsnprintf(NULL, 0, format, tmpa); + va_end(tmpa); + + if (rt_dstr_resize(thiz, old_length + new_length) == -1) + { + va_end(ap); + return NULL; + } + + dst = thiz->str + old_length - 1; /* remove '\0' */ + + vsnprintf(dst, 1 + new_length, format, ap); + + va_end(ap); + + return thiz; +} \ No newline at end of file