Explorar el Código

【更新】dstr 源码 & README,增加 v0.2.0

neverxie hace 7 años
padre
commit
586cbdb993
Se han modificado 4 ficheros con 446 adiciones y 235 borrados
  1. 127 30
      README.md
  2. 93 54
      examples/examples_dstr.c
  3. 10 2
      inc/dstr.h
  4. 216 149
      src/dstr.c

+ 127 - 30
README.md

@@ -19,7 +19,15 @@ dstr package 遵循 LGPLv2.1 许可,详见 `LICENSE` 文件。
 
 - 对 RT-Thread 无依赖,也可用于裸机。
 
-
+### 1.4 版本日志
+- v0.2.0
+  - 增在从前面拼接字符串相关API
+  - 增加从前面拼接动态字符串相关API
+  - 增加从后面拼接动态字符串相关API
+  - 改善用户体验
+  - 修复已知 bug
+- v0.1.0
+  - 动态字符串软件包第一版
 
 ## 2、如何打开 dstr
 
@@ -29,10 +37,9 @@ dstr package 遵循 LGPLv2.1 许可,详见 `LICENSE` 文件。
 RT-Thread online packages --->
     miscellaneous packages --->
         [*] dstr: a dynamic string package
-        	Version (latest) --->
+        	Version (v0.2.0) --->
         	dstr Options --->
         		[*] dstr test example
-        
 ```
 
 保存 menuconfig 配置后使用 `pkgs --update` 命令下载软件包
@@ -47,8 +54,10 @@ RT-Thread online packages --->
 | 参数 | 描述 |
 | ---- | ---- |
 | name  | 源字符串 |
-| return  | 创建成功,将返回 dstr 对象指针;创建失败则返回 NULL |
-
+| 返回 | 描述 |
+| thiz | 动态字符串创建成功 |
+| NULL | 动态字符串创建失败 |
+> 可以传入 NULL,使用详情可以查看 `examples_dstr.c`
 
 ### 3.2 删除动态字符串对象
 `void rt_dstr_del(rt_dstr_t *thiz);`
@@ -56,43 +65,122 @@ RT-Thread online packages --->
 | 参数 | 描述 |
 | ---- | ---- |
 | thiz  | 动态字符串对象 |
-| return  | 无 |
+| 返回 | 描述 |
+| 无 | 无 |
 
 
-### 3.3 动态字符串连
+### 3.3 字符串后拼
 `rt_dstr_t *rt_dstr_cat(rt_dstr_t *thiz, const char *src);`
 
 | 参数 | 描述 |
 | ---- | ---- |
 | thiz  | 动态字符串对象 |
 | src  | 源字符串 |
-| return  | cat 成功,将返回 dstr 对象指针;cat 失败,则返回 NULL,但不会更改 thiz,交由用户处理 |
+| 返回 | 描述 |
+| thiz | 字符串拼接 dstr 成功 |
+| NULL | 字符串拼接 dstr 失败,但不会更改 thiz,交由用户处理 |
 
 
-### 3.4 动态字符串连接(连接几个字符)
+### 3.4 字符串后拼接(拼接 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,交由用户处理 |
+| n  | 需要拼接几个字符 |
+| 返回 | 描述 |
+| thiz | 字符串拼接 dstr 成功 |
+| null | 字符串拼接 dstr 失败,但不会更改 thiz,交由用户处理 |
+
+### 3.5 字符串前拼接
+`rt_dstr_t *rt_dstr_precat(rt_dstr_t *thiz, const char *src);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| thiz  | 动态字符串对象 |
+| src  | 源字符串 |
+| 返回 | 描述 |
+| thiz | 字符串拼接 dstr 成功 |
+| null | 字符串拼接 dstr 失败,但不会更改 thiz,交由用户处理 |
+
+
+### 3.6 字符串前拼接(拼接 n 个字符)
+`rt_dstr_t *rt_dstr_prencat(rt_dstr_t *thiz, const char *src, size_t n);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| thiz  | 动态字符串对象 |
+| src  | 源字符串 |
+| n  | 需要拼接几个字符 |
+| 返回 | 描述 |
+| thiz | 字符串拼接 dstr 成功 |
+| NULL | 字符串拼接 dstr 失败,但不会更改 thiz,交由用户处理 |
+
+
+### 3.7 动态字符串后拼接
+`rt_dstr_t *rt_dstr_cat_dstr(rt_dstr_t *dst, rt_dstr_t *src);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| dst  | 动态字符串对象 |
+| src  | 源字符串 |
+| 返回 | 描述 |
+| dst | 动态字符串拼接 dst 成功,但不会更改 src,交由用户处理 |
+| NULL | 动态字符串拼接 dst 失败,但不会更改 dst & src,交由用户处理 |
+
+
+### 3.8 动态字符串后拼接(拼接 n 个字符)
+`rt_dstr_t *rt_dstr_ncat_dstr(rt_dstr_t *dst, rt_dstr_t *src, size_t n);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| dst  | 动态字符串对象 |
+| src  | 源字符串 |
+| n  | 需要拼接几个字符 |
+| 返回 | 描述 |
+| dst | 动态字符串拼接 dst 成功,但不会更改 src,交由用户处理 |
+| NULL | 动态字符串拼接 dst 失败,但不会更改 dst & src,交由用户处理 |
+
+### 3.9 动态字符串前拼接
+`rt_dstr_t *rt_dstr_precat_dstr(rt_dstr_t *dst, rt_dstr_t *src);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| dst  | 动态字符串对象 |
+| src  | 源字符串 |
+| 返回 | 描述 |
+| dst | 动态字符串拼接 dst 成功,但不会更改 src,交由用户处理 |
+| NULL | 动态字符串拼接 dst 失败,但不会更改 dst & src,交由用户处理 |
+
+
+### 3.10 动态字符串前拼接(拼接几个字符)
+`rt_dstr_t *rt_dstr_prencat_dstr(rt_dstr_t *dst, rt_dstr_t *src, size_t n);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| dst  | 动态字符串对象 |
+| src  | 源字符串 |
+| n  | 需要拼接几个字符 |
+| 返回 | 描述 |
+| thiz | 字符串拼接 dstr 成功 |
+| NULL | 字符串拼接 dstr 失败,但不会更改 thiz,交由用户处理 |
 
-### 3.5 动态字符串比较
+
+### 3.11 动态字符串比较
 `int rt_dstr_cmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2);`
 
 | 参数 | 描述 |
 | ---- | ---- |
 | dstr1  | 动态字符串1 |
 | dstr2  | 动态字符串2 |
-| return  | dstr1 < dstr2,返回负数 |
-| return  | dstr1 = dstr2,返回0 |
-| return  | dstr1 > dstr2,返回正数 |
-
+| 返回 | 描述 |
+| 负数 | dstr1 < dstr2 |
+| 返回0 | dstr1 = dstr2 |
+| 正数 | dstr1 > dstr2 |
 
 
-### 3.6 动态字符串比较(比较几个字符)
+### 3.12 动态字符串比较(比较 n 个字符)
 `int rt_dstr_ncmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2, size_t n);`
 
 | 参数 | 描述 |
@@ -100,31 +188,36 @@ RT-Thread online packages --->
 | dstr1  | 动态字符串1 |
 | dstr2  | 动态字符串2 |
 | n  | 需要比较几个字符 |
-| return  | dstr1 < dstr2,返回负数 |
-| return  | dstr1 = dstr2,返回0 |
-| return  | dstr1 > dstr2,返回正数 |
+| 返回 | 描述 |
+| 负数 | dstr1 < dstr2 |
+| 返回0 | dstr1 = dstr2 |
+| 正数 | dstr1 > dstr2 |
 
-### 3.7 动态字符串比较(忽略大小写)
+### 3.13 动态字符串比较(忽略大小写)
 `int rt_dstr_casecmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2);`
 
 | 参数 | 描述 |
 | ---- | ---- |
 | dstr1  | 动态字符串1 |
 | dstr2  | 动态字符串2 |
-| return  | dstr1 < dstr2,返回负数 |
-| return  | dstr1 = dstr2,返回0 |
-| return  | dstr1 > dstr2,返回正数 |
+| 返回 | 描述 |
+| 负数 | dstr1 < dstr2 |
+| 返回0 | dstr1 = dstr2 |
+| 正数 | dstr1 > dstr2 |
 
-### 3.8 测量动态字符串长度
+### 3.14 测量动态字符串长度
 `int rt_dstr_strlen(rt_dstr_t *const thiz);`
 
 | 参数 | 描述 |
 | ---- | ---- |
 | thiz  | 动态字符串对象 |
-| return  | 参数非 NULL,将返回动态字符串长度;参数为 NULL 则返回-1 |
+| 返回 | 描述 |
+| 正数 | 返回动态字符串长度 |
+| 返回0 | 返回动态字符串长度 |
+| -1 | 输入参数为 NULL 是非法的 |
 
 
-### 3.9 字符串格式化输出
+### 3.15 字符串格式化输出
 `rt_dstr_t *rt_dstr_sprintf(rt_dstr_t *thiz, const char *fmt, ...);`
 
 | 参数 | 描述 |
@@ -132,9 +225,11 @@ RT-Thread online packages --->
 | thiz  | 动态字符串对象 |
 | fmt  | 格式化字符串 |
 | argument...  | 可选参数,任何类型的数据 |
-| return  | 返回 dstr 对象指针 |
+| 返回 | 描述 |
+| thiz | 字符串格式化成功 |
+| NULL | 字符串格式化失败,但不会更改 thiz,交由用户处理 |
 
-### 3.10 字符串格式化输出(以追加的方式实现)
+### 3.16 字符串格式化输出(以追加的方式
 
 `rt_dstr_t *rt_dstr_append_printf(rt_dstr_t *thiz, const char *format, ...);`
 
@@ -143,7 +238,9 @@ RT-Thread online packages --->
 | thiz | 动态字符串对象 |
 |fmt|格式化字符串|
 | argument...  | 可选参数,任何类型的数据 |
-| return  | 返回 dstr 对象指针 |
+| 返回 | 描述 |
+| thiz | 字符串格式化成功 |
+| NULL | 字符串格式化失败,但不会更改 thiz,交由用户处理 |
 
 
 ## 4、注意事项

+ 93 - 54
examples/examples_dstr.c

@@ -21,6 +21,7 @@
  * Date           Author       Notes
  * 2018-06-07     never        the first version
  * 2018-07-25     never        add sample API
+ * 2018-08-30     never        add sample API
  */
 
 #include <rtthread.h>
@@ -32,63 +33,92 @@ void rt_dstr_print(rt_dstr_t *thiz)
 {
     if (thiz == NULL)
         return;
-    rt_kprintf("%s\n", thiz->str);
+    printf("%s\n", thiz->str);
 }
 
 void dstr_test_new(void)
 {
-    rt_kprintf("\n");
-
+    const char *str = "new dstr";
     rt_dstr_t *p = NULL;
 
-    p = rt_dstr_new("new dstr");
+    printf("\n");
+
+    printf("sample of new:\n");
+    p = rt_dstr_new(str);
     rt_dstr_print(p);
     rt_dstr_del(p);
-    rt_kprintf("\n");
+    printf("\n");
 }
 
 void dstr_test_cat(void)
 {
-    rt_dstr_t *p1 = NULL, *p2 = NULL;
+    rt_dstr_t *p = NULL;
     const char *str = "cat ";
 
-    p1 = rt_dstr_cat(p1, "cat sample1");
+    printf("sample of cat:\n");
+    p = rt_dstr_new(str);
+    rt_dstr_cat(p, "sample");
+    rt_dstr_print(p);
+    rt_dstr_del(p);
 
-    rt_dstr_print(p1);
+    printf("\n");
+}
 
-    rt_dstr_del(p1);
+void dstr_test_ncat(void)
+{
+    rt_dstr_t *p = NULL;
+    const char *str = "ncat ";
 
-    p2 = rt_dstr_new(str);
+    printf("sample of ncat:\n");
+    p = rt_dstr_new(str);
+    rt_dstr_ncat(p, "samplexxxxxx", 6);
+    rt_dstr_print(p);
+    rt_dstr_del(p);
 
-    rt_dstr_cat(p2, "sample2");
+    printf("\n");
+}
 
-    rt_dstr_print(p1);
+void dstr_test_precat(void)
+{
+    rt_dstr_t *p = NULL;
 
-    rt_dstr_del(p1);
+    printf("sample of precat:\n");
+    p = rt_dstr_precat(NULL, "456");
+    rt_dstr_precat(p, "123");
+    rt_dstr_precat(p, "pre sample: ");
 
-    rt_kprintf("\n");
+    rt_dstr_print(p);
+    rt_dstr_del(p);
 }
 
-void dstr_test_ncat(void)
+void dstr_test_cat_dstr(void)
 {
     rt_dstr_t *p1 = NULL, *p2 = NULL;
-    const char *str = "ncat ";
-
-    p1 = rt_dstr_ncat(p1, "ncat sample1", 12);
 
+    printf("\n");
+    printf("sample of cat_dstr:\n");
+    p1 = rt_dstr_new("dstr1");
+    p2 = rt_dstr_new("dstr2");
+    p1 = rt_dstr_cat_dstr(p1, p2);
     rt_dstr_print(p1);
-
+    rt_dstr_print(p2);
     rt_dstr_del(p1);
+    rt_dstr_del(p2);
+}
 
-    p2 = rt_dstr_new(str);
-
-    rt_dstr_ncat(p2, "sample2222", 7);
+void dstr_test_precat_dstr(void)
+{
+    rt_dstr_t *p1 = NULL, *p2 = NULL;
 
+    printf("\n");
+    printf("sample of precat_dstr:\n");
+    p1 = rt_dstr_new("dstr1");
+    p2 = rt_dstr_new("dstr2");
+    p1 = rt_dstr_precat_dstr(p1, p2);
     rt_dstr_print(p1);
-
+    rt_dstr_print(p2);
     rt_dstr_del(p1);
-
-    rt_kprintf("\n");
+    rt_dstr_del(p2);
 }
 
 void dstr_test_cmp(void)
@@ -97,28 +127,30 @@ void dstr_test_cmp(void)
     rt_dstr_t *p2 = NULL;
     int res = 0;
 
+    printf("\n");
+    printf("sample of cmp:\n");
     p1 = rt_dstr_new("helle");
     p2 = rt_dstr_new("hellc");
 
     res = rt_dstr_cmp(p1, p2);
-    rt_kprintf("cmp result: %d\n", res);
+    printf("cmp result: %d\n", res);
 
     rt_dstr_del(p1);
     rt_dstr_del(p2);
 
-    //  NULL
+    /* one of them is NULL */
     p1 = rt_dstr_new("abc");
     res = rt_dstr_cmp(p1, NULL);
-    rt_kprintf("s2:NULL result: %d\n", res);
+    printf("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);
+    printf("s1:NULL result: %d\n", res);
     rt_dstr_del(p1);
 
     res = rt_dstr_cmp(NULL, NULL);
-    rt_kprintf("two NULL result: %d\n\n", res);
+    printf("two NULL result: %d\n\n", res);
 }
 
 void dstr_test_ncmp(void)
@@ -127,28 +159,29 @@ void dstr_test_ncmp(void)
     rt_dstr_t *p2 = NULL;
     int res = 0;
 
+    printf("sample of ncmp:\n");
     p1 = rt_dstr_new("hello");
     p2 = rt_dstr_new("hella");
 
     res = rt_dstr_ncmp(p1, p2, 5);
-    rt_kprintf("ncmp result: %d\n", res);
+    printf("ncmp result: %d\n", res);
 
     rt_dstr_del(p1);
     rt_dstr_del(p2);
 
-    /* NULL */
+    /* one of them is NULL */
     p1 = rt_dstr_new("abc");
     res = rt_dstr_ncmp(p1, NULL, 2);
-    rt_kprintf("s2:NULL ncmp result: %d\n", res);
+    printf("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);
+    printf("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\n", res);
+    printf("two NULL ncmp result: %d\n\n", res);
 }
 
 void dstr_test_casecmp(void)
@@ -157,28 +190,29 @@ void dstr_test_casecmp(void)
     rt_dstr_t *p2 = NULL;
     int res = 0;
 
+    printf("sample of casecmp:\n");
     p1 = rt_dstr_new("hello");
     p2 = rt_dstr_new("HELLO");
 
     res = rt_dstr_casecmp(p1, p2);
-    rt_kprintf("casecmp result: %d\n", res);
+    printf("casecmp result: %d\n", res);
 
     rt_dstr_del(p1);
     rt_dstr_del(p2);
 
-    /* NULL */
+    /* one of them is NULL */
     p1 = rt_dstr_new("abc");
     res = rt_dstr_casecmp(p1, NULL);
-    rt_kprintf("s2:NULL casecmp result: %d\n", res);
+    printf("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);
+    printf("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\n", res);
+    printf("two NULL casecmp result: %d\n\n", res);
 }
 
 void dstr_test_strlen(void)
@@ -186,6 +220,7 @@ void dstr_test_strlen(void)
     rt_dstr_t *p1 = NULL;
     int res = 0;
 
+    printf("sample of strlen:\n");
     p1 = rt_dstr_new("hello strlen");
 
     res = rt_dstr_strlen(p1);
@@ -193,11 +228,11 @@ void dstr_test_strlen(void)
     if (res == -1)
         return;
 
-    rt_kprintf("length: %d\n", res);
+    printf("length: %d\n", res);
 
     rt_dstr_del(p1);
 
-    rt_kprintf("\n");
+    printf("\n");
 }
 
 void dstr_test_sprintf(void)
@@ -206,7 +241,7 @@ void dstr_test_sprintf(void)
     rt_dstr_t *p1 = NULL;
     rt_dstr_t *p2 = NULL;
 
-    /* string format */
+    printf("sample of sprintf:\n");
     p1 = rt_dstr_new("test");
 
     rt_dstr_sprintf(p1, "%s", src);
@@ -215,7 +250,6 @@ void dstr_test_sprintf(void)
 
     rt_dstr_del(p1);
 
-    /* hex format */
     p2 = rt_dstr_new("");
 
     rt_dstr_sprintf(p2, "%08x", 0x20180604);
@@ -224,10 +258,10 @@ void dstr_test_sprintf(void)
 
     rt_dstr_del(p2);
 
-    rt_kprintf("\n");
+    printf("\n");
 }
 
-rt_dstr_t *path_cat(const char *path, const char *filename)
+static rt_dstr_t *path_cat(const char *path, const char *filename)
 {
     rt_dstr_t *p = RT_NULL;
 
@@ -236,7 +270,7 @@ rt_dstr_t *path_cat(const char *path, const char *filename)
     return p;
 }
 
-rt_dstr_t *header_info_cat(char *send_buffer)
+static rt_dstr_t *header_info_cat(char *send_buffer)
 {
     rt_dstr_t *p = RT_NULL;
     const char *key = "header-key";
@@ -252,16 +286,18 @@ rt_dstr_t *header_info_cat(char *send_buffer)
 void dstr_test_append(void)
 {
     char *buffer = "test of header";
+    rt_dstr_t *p = NULL;
 
-    rt_dstr_print(path_cat("/home", "bsp/thread.c"));
-    rt_dstr_del(path_cat("/home", "bsp/thread.c"));
-
-    rt_kprintf("\n");
+    printf("sample of append:\n");
+    p = path_cat("/home", "bsp/thread.c");
+    rt_dstr_print(p);
+    rt_dstr_del(p);
 
-    rt_dstr_print(header_info_cat(buffer));
-    rt_dstr_del(header_info_cat(buffer));
+    printf("\n");
 
-    rt_kprintf("\n");
+    p = header_info_cat(buffer);
+    rt_dstr_print(p);
+    rt_dstr_del(p);
 }
 
 void dstr_test(void)
@@ -269,6 +305,9 @@ void dstr_test(void)
     dstr_test_new();
     dstr_test_cat();
     dstr_test_ncat();
+    dstr_test_precat();
+    dstr_test_cat_dstr();
+    dstr_test_precat_dstr();
     dstr_test_cmp();
     dstr_test_ncmp();
     dstr_test_casecmp();

+ 10 - 2
inc/dstr.h

@@ -21,13 +21,12 @@
  * Date           Author       Notes
  * 2018-06-07     never        the first version
  * 2018-07-25     never        add append_printf() and modify some APIs
+ * 2018-08-30     never        add some APIs and modify some APIs
  */
 
 #ifndef __DSTR_H__
 #define __DSTR_H__
 
-#include <rtthread.h>
-
 struct rt_dstr
 {
     char *str;
@@ -41,6 +40,15 @@ void rt_dstr_del(rt_dstr_t *thiz);
 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);
 
+rt_dstr_t *rt_dstr_precat(rt_dstr_t *thiz, const char *src);
+rt_dstr_t *rt_dstr_prencat(rt_dstr_t *thiz, const char *src, size_t n);
+
+rt_dstr_t *rt_dstr_cat_dstr(rt_dstr_t *dst, rt_dstr_t *src);
+rt_dstr_t *rt_dstr_ncat_dstr(rt_dstr_t *dst, rt_dstr_t *src, size_t n);
+
+rt_dstr_t *rt_dstr_precat_dstr(rt_dstr_t *dst, rt_dstr_t *src);
+rt_dstr_t *rt_dstr_prencat_dstr(rt_dstr_t *dst, rt_dstr_t *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);
 

+ 216 - 149
src/dstr.c

@@ -21,9 +21,9 @@
  * Date           Author       Notes
  * 2018-06-07     never        the first version
  * 2018-07-25     never        add append_printf() and modify some APIs
+ * 2018-08-30     never        add some APIs and modify some APIs
  */
 
-#include <rtthread.h>
 #include <stdarg.h>
 #include <string.h>
 #ifdef __GNUC__
@@ -35,11 +35,13 @@
 
 #define DBG_ENABLE
 #undef  DBG_ENABLE
-#define DBG_SECTION_NAME  "[RTDSTR]"
+#define DBG_SECTION_NAME  "RTDSTR"
 #define DBG_LEVEL         DBG_INFO
 #define DBG_COLOR
 #include <rtdbg.h>
 
+typedef rt_dstr_t *(*save_t)(rt_dstr_t *thiz, const char *src, size_t n, size_t old_size);
+
 /**
  * This function will create a dstr(dynamic string) object.
  *
@@ -51,31 +53,35 @@ 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));
+    thiz = (rt_dstr_t *)malloc(sizeof(*thiz));
     if (thiz == NULL)
     {
-        dbg_log(DBG_ERROR, "new malloc error\n");
-        return NULL;
+        dbg_log(DBG_ERROR, "new.malloc error\n");
+        goto err;
     }
 
-    thiz->length = strlen(str) + 1; /* allocated space */
-    thiz->str = (char *)malloc(sizeof(char) * thiz->length);
+    if (str == NULL)
+        thiz->length = 1;
+    else
+        thiz->length = strlen(str) + 1;
 
+    thiz->str = (char *)malloc(sizeof(thiz->length));
     if (thiz->str == NULL)
     {
-        free(thiz);
-        return NULL;
+        dbg_log(DBG_ERROR, "new.malloc error\n");
+        goto err;
     }
 
-    memcpy(thiz->str, str, thiz->length);
+    if (str == NULL)
+        memcpy(thiz->str, "", thiz->length);
+    else
+        memcpy(thiz->str, str, thiz->length);
 
     return thiz;
+
+err:
+    rt_dstr_del(thiz);
+    return NULL;
 }
 
 /**
@@ -90,41 +96,90 @@ void rt_dstr_del(rt_dstr_t *thiz)
     if (thiz == NULL)
         return;
 
-    if (thiz->str == NULL)
+    if (thiz->str != NULL)
     {
-        free(thiz);
-        return;
+        free(thiz->str);
+        thiz->str = NULL;
     }
 
-    free(thiz->str);
-
     free(thiz);
 }
 
-static int rt_dstr_resize(rt_dstr_t *const thiz, size_t new_spacesize)
+static int _resize(rt_dstr_t *const thiz, size_t new_size)
 {
     char *p = NULL;
 
     if (thiz == NULL)
     {
-        dbg_log(DBG_ERROR, "resize.thiz param error\n");
-        return -1;
+        dbg_log(DBG_ERROR, "_resize.thiz param error\n");
+        goto err;
     }
 
-    p = (char *)realloc(thiz->str, new_spacesize);
+    p = (char *)realloc(thiz->str, new_size);
 
     if (p == NULL)
     {
-        dbg_log(DBG_ERROR, "resize.realloc error\n");
-        return -1;
+        dbg_log(DBG_ERROR, "_resize.realloc error\n");
+        goto err;
     }
     else
     {
-        thiz->length = new_spacesize;
-        dbg_log(DBG_INFO, "new_spacesize:%d\n", thiz->length);
+        thiz->length = new_size;
+        dbg_log(DBG_INFO, "new_size:%d\n", thiz->length);
         thiz->str = p;
         return 0;
     }
+err:
+    return -1;
+}
+
+static rt_dstr_t *_ahead(rt_dstr_t *thiz, const char *src, size_t n, size_t old_size)
+{
+    memmove(thiz->str + n, thiz->str, n);
+    memcpy(thiz->str, src, n);
+    *(thiz->str + (old_size - 1) + n) = '\0';
+    return thiz;
+}
+
+static rt_dstr_t *_behind(rt_dstr_t *thiz, const char *src, size_t n, size_t old_size)
+{
+    memcpy(thiz->str + (old_size - 1), src, n);
+    *(thiz->str + (old_size - 1) + n) = '\0';
+    return thiz;
+}
+
+static rt_dstr_t *_xcat(rt_dstr_t *thiz, const char *src, size_t n, save_t fun)
+{
+    int res = 0;
+    size_t new_size = 0, old_size = 0;
+
+    if (thiz == NULL)
+        thiz = rt_dstr_new(NULL);
+
+    if (src == NULL)
+    {
+        dbg_log(DBG_ERROR, "param error\n");
+        goto err;
+    }
+
+    if (n > (strlen(src) + 1))
+    {
+        dbg_log(DBG_ERROR, "size error\n");
+        goto err;
+    }
+
+    old_size = thiz->length;
+    new_size = n + old_size;
+
+    res = _resize(thiz, new_size);
+    if (res == -1)
+    {
+        dbg_log(DBG_ERROR, "_resize error\n");
+        goto err;
+    }
+    return fun(thiz, src, n, old_size);
+err:
+    return NULL;
 }
 
 /**
@@ -132,7 +187,7 @@ static int rt_dstr_resize(rt_dstr_t *const thiz, size_t new_spacesize)
  * overwriting the terminating null byte '\0' at the end of the dest,
  * and then adds a terminating null byte.
  *
- * @param thiz the dstr(dynamic string) thiz
+ * @param thiz the dstr(dynamic string)
  * @param src  the string
  *
  * @return the dest dstr
@@ -146,38 +201,118 @@ rt_dstr_t *rt_dstr_cat(rt_dstr_t *thiz, const char *src)
  * This function is similar, except that it will use at most n bytes from src,
  * and src does not need to be null-terminated if it contains n or more bytes.
  *
- * @param thiz the dstr(dynamic string) thiz
+ * @param thiz the dstr(dynamic string)
  * @param src  the string
- * @param count the maximum compare length
+ * @param n it will use at most n bytes from src
  *
  * @return the dest dstr
  */
 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;
+    return _xcat(thiz, src, n, _behind);
+}
 
-    if (thiz == NULL)
-    {
-        thiz = rt_dstr_new("");
-    }
+/**
+ * This function prepends 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.
+ *
+ * @param thiz the dstr(dynamic string)
+ * @param src  the string
+ *
+ * @return the dest dstr
+ */
+rt_dstr_t *rt_dstr_precat(rt_dstr_t *thiz, const char *src)
+{
+    return _xcat(thiz, src, strlen(src), _ahead);
+}
 
-    old_spacesize = thiz->length;       /* allocated space */
+/**
+ * This function is similar, except that it will use at most n bytes from src,
+ * and src does not need to be null-terminated if it contains n or more bytes.
+ *
+ * @param thiz the dstr(dynamic string)
+ * @param src  the string
+ * @param n it will use at most n bytes from src
+ *
+ * @return the dest dstr
+ */
+rt_dstr_t *rt_dstr_prencat(rt_dstr_t *thiz, const char *src, size_t n)
+{
+    return _xcat(thiz, src, n, _ahead);
+}
+
+/**
+ * This function appends the dstr to the dest object,
+ * overwriting the terminating null byte '\0' at the end of the dest,
+ * and then adds a terminating null byte.
+ *
+ * @param dst the dest dstr thiz
+ * @param src the src dstr
+ *
+ * @return the dest dstr
+ */
+rt_dstr_t *rt_dstr_cat_dstr(rt_dstr_t *dst, rt_dstr_t *src)
+{
+    /* e.g.: src->str = "abc", src->length = 4 */
+    return rt_dstr_ncat_dstr(dst, src, src->length - 1);
+}
 
-    new_spacesize = n + old_spacesize;  /* allocated space */
+/**
+ * This function is similar, except that it will use at most n bytes from src,
+ * and src does not need to be null-terminated if it contains n or more bytes.
+ *
+ * @param n it will use at most n bytes from src
+ *
+ * @return the dest dstr
+ */
+rt_dstr_t *rt_dstr_ncat_dstr(rt_dstr_t *dst, rt_dstr_t *src, size_t n)
+{
+    return _xcat(dst, src->str, n, _behind);
+}
 
-    res = rt_dstr_resize(thiz, new_spacesize);
+/**
+ * This function prepends the dstr to the dest object,
+ * overwriting the terminating null byte '\0' at the end of the dest,
+ * and then adds a terminating null byte.
+ *
+ * @param thiz the dstr(dynamic string) thiz
+ * @param src  the string
+ *
+ * @return the dest dstr
+ */
+rt_dstr_t *rt_dstr_precat_dstr(rt_dstr_t *dst, rt_dstr_t *src)
+{
+    /* e.g.: src->str = "abc", src->length = 4 */
+    return rt_dstr_prencat_dstr(dst, src, src->length - 1);
+}
 
-    if (res == -1)
-    {
-        dbg_log(DBG_ERROR, "nacat.resize error\n");
-        return NULL;
-    }
+/**
+ * This function is similar, except that it will use at most n bytes from src,
+ * and src does not need to be null-terminated if it contains n or more bytes.
+ *
+ * @param thiz the dstr(dynamic string)
+ * @param src  the string
+ * @param n it will use at most n bytes from src
+ *
+ * @return the dest dstr
+ */
+rt_dstr_t *rt_dstr_prencat_dstr(rt_dstr_t *dst, rt_dstr_t *src, size_t n)
+{
+    return _xcat(dst, src->str, n, _ahead);
+}
 
-    memcpy(thiz->str + (old_spacesize - 1), src, n);
-    *(thiz->str + (old_spacesize - 1) + n) = '\0';
+static void _param_process(rt_dstr_t *const d1, rt_dstr_t *const d2, char **s1, char **s2)
+{
+    if (d1 != NULL)
+        *s1 = d1->str;
+    else
+        *s1 = NULL;
 
-    return thiz;
+    if (d2 != NULL)
+        *s2 = d2->str;
+    else
+        *s2 = NULL;
 }
 
 /**
@@ -190,30 +325,10 @@ 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)
 {
-    char *str1, *str2;
+    char *s1 = NULL, *s2 = NULL;
 
-    if ((dstr1 == NULL) && (dstr2 == NULL))
-    {
-        str1 = NULL;
-        str2 = NULL;
-    }
-    else if (dstr1 == NULL)
-    {
-        str1 = NULL;
-        str2 = dstr2->str;
-    }
-    else if (dstr2 == NULL)
-    {
-        str2 = NULL;
-        str1 = dstr1->str;
-    }
-    else
-    {
-        str1 = dstr1->str;
-        str2 = dstr2->str;
-    }
-
-    return strcmp(str1, str2);
+    _param_process(dstr1, dstr2, &s1, &s2);
+    return strcmp(s1, s2);
 }
 
 /**
@@ -227,30 +342,10 @@ 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)
-    {
-        str1 = NULL;
-        str2 = dstr2->str;
-    }
-    else if (dstr2 == NULL)
-    {
-        str2 = NULL;
-        str1 = dstr1->str;
-    }
-    else
-    {
-        str1 = dstr1->str;
-        str2 = dstr2->str;
-    }
+    char *s1 = NULL, *s2 = NULL;
 
-    return strncmp(str1, str2, n);
+    _param_process(dstr1, dstr2, &s1, &s2);
+    return strncmp(s1, s2, n);
 }
 
 /**
@@ -263,30 +358,10 @@ 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;
+    char *s1 = NULL, *s2 = NULL;
 
-    if ((dstr1 == NULL) && (dstr2 == NULL))
-    {
-        str1 = NULL;
-        str2 = NULL;
-    }
-    else if (dstr1 == NULL)
-    {
-        str1 = NULL;
-        str2 = dstr2->str;
-    }
-    else if (dstr2 == NULL)
-    {
-        str2 = NULL;
-        str1 = dstr1->str;
-    }
-    else
-    {
-        str1 = dstr1->str;
-        str2 = dstr2->str;
-    }
-
-    return strcasecmp(str1, str2);
+    _param_process(dstr1, dstr2, &s1, &s2);
+    return strcasecmp(s1, s2);
 }
 
 /**
@@ -315,34 +390,29 @@ int rt_dstr_strlen(rt_dstr_t *const thiz)
  */
 rt_dstr_t *rt_dstr_sprintf(rt_dstr_t *thiz, const char *fmt, ...)
 {
-    va_list  arg_ptr;
-    va_list  tmp;
-    int new_length = 0;
+    va_list  ap;
+    int new_len = 0;
 
     if (thiz == NULL)
-    {
-        thiz = rt_dstr_new("");
-    }
-
-    va_start(arg_ptr, fmt);
+        thiz = rt_dstr_new(NULL);
 
-    va_copy(tmp, arg_ptr);
+    va_start(ap, fmt);
 
-    new_length = vsnprintf(NULL, 0, fmt, tmp);      /* strlen("test sprintf") = 12 */
+    new_len = vsnprintf(NULL, 0, fmt, ap);      /* strlen("test sprintf") = 12 */
 
-    va_end(tmp);
-
-    if (rt_dstr_resize(thiz, new_length + 1) == -1) /* allocated space */
+    if (_resize(thiz, new_len + 1) == -1) /* allocated space */
     {
-        va_end(arg_ptr);
-        return NULL;
+        va_end(ap);
+        goto err;
     }
 
-    vsnprintf(thiz->str, new_length + 1, fmt, arg_ptr);
+    vsnprintf(thiz->str, new_len + 1, fmt, ap);
 
-    va_end(arg_ptr);
+    va_end(ap);
 
     return thiz;
+err:
+    return NULL;
 }
 
 /**
@@ -356,34 +426,31 @@ 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, ...)
 {
     va_list ap;
-    va_list tmpa;
     char *dst = NULL;
-    int old_length = 0, new_length = 0;
+    int old_len = 0, new_len = 0;
 
     if (thiz == NULL)
-    {
-        thiz = rt_dstr_new("");
-    }
+        thiz = rt_dstr_new(NULL);
 
     va_start(ap, format);
 
-    old_length = thiz->length;
+    old_len = thiz->length;
 
-    va_copy(tmpa, ap);
-    new_length = vsnprintf(NULL, 0, format, tmpa);
-    va_end(tmpa);
+    new_len = vsnprintf(NULL, 0, format, ap);
 
-    if (rt_dstr_resize(thiz, old_length + new_length) == -1)
+    if (_resize(thiz, old_len + new_len) == -1)
     {
         va_end(ap);
-        return NULL;
+        goto err;
     }
 
-    dst = thiz->str + old_length - 1; /* remove '\0' */
+    dst = thiz->str + old_len - 1; /* remove '\0' */
 
-    vsnprintf(dst, 1 + new_length, format, ap);
+    vsnprintf(dst, 1 + new_len, format, ap);
 
     va_end(ap);
 
     return thiz;
-}
+err:
+    return NULL;
+}