Ver Fonte

Merge pull request #2 from neverxie/nx

 Submit the first version of the dynamic string package and fix some bugs.
Bernard Xiong há 7 anos atrás
pai
commit
6bbd38e136
5 ficheiros alterados com 765 adições e 1 exclusões
  1. 138 1
      README.md
  2. 24 0
      SConscript
  3. 218 0
      dstr/examples/examples_dstr.c
  4. 51 0
      dstr/inc/dstr.h
  5. 334 0
      dstr/src/dstr.c

+ 138 - 1
README.md

@@ -1,2 +1,139 @@
 # dstr
-dynamic string in C
+
+## 1、介绍
+这是一个在 RT-Thread 上,基于ANSI/ISO C(C89)实现的动态字符串软件包。
+
+### 1.1 目录结构
+
+| 名称 | 说明 |
+| ---- | ---- |
+| inc  | 头文件目录 |
+| src  | 源代码目录 |
+| examples | 例程目录 |
+
+### 1.2 许可证
+
+dstr package 遵循 LGPLv2.1 许可,详见 `LICENSE` 文件。
+
+### 1.3 依赖
+
+对 RT-Thread 无依赖,也可用于裸机。
+
+## 2、如何打开 dstr
+
+使用 dstr package 需要在 RT-Thread 的包管理器中选择它,具体路径如下:
+
+```
+RT-Thread online packages
+    miscellaneous packages --->
+        [*] dstr: a dynamic string package
+```
+
+然后让 RT-Thread 的包管理器自动更新,或者使用 `pkgs --update` 命令更新包到 BSP 中。
+
+## 3、使用 dstr
+
+使用dstr可参考例子工程,该工程位于:[/dstr/examples/examples_dstr.c](dstr/examples/examples_dstr.c)
+
+### 3.1 创建动态字符串对象
+`rt_dstr_t *rt_dstr_new(const char *str);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| name  | 源字符串 |
+| return  | 创建成功,将返回dstr对象指针;创建失败则返回NULL |
+
+
+### 3.2 删除动态字符串对象
+`void rt_dstr_del(rt_dstr_t *thiz);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| thiz  | 动态字符串对象 |
+| return  | 无 |
+
+
+### 3.3 动态字符串连接
+`rt_dstr_t *rt_dstr_cat(rt_dstr_t *const thiz, const char *src);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| thiz  | 动态字符串对象 |
+| src  | 源字符串 |
+| 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);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| thiz  | 动态字符串对象 |
+| src  | 源字符串 |
+| n  | 需要连接几个字符 |
+| return  | cat成功,将返回dstr对象指针;cat失败,则返回NULL,但不会更改thiz,交由用户处理 |
+
+### 3.5 动态字符串比较
+`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,返回正数 |
+
+
+
+### 3.6 动态字符串比较(比较几个字符)
+`int rt_dstr_ncmp(rt_dstr_t *const dstr1, rt_dstr_t *const dstr2, size_t n);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| dstr1  | 动态字符串1 |
+| dstr2  | 动态字符串2 |
+| n  | 需要比较几个字符 |
+| return  | dstr1 < dstr2,返回负数 |
+| return  | dstr1 = dstr2,返回0 |
+| return  | dstr1 > dstr2,返回正数 |
+
+### 3.7 动态字符串比较(忽略大小写)
+`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,返回正数 |
+
+### 3.8 测量动态字符串长度
+`int rt_dstr_strlen(rt_dstr_t *const thiz);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| thiz  | 动态字符串对象 |
+| return  | 参数非NULL,将返回动态字符串长度;参数为NULL则返回-1 |
+
+
+### 3.9 字符串格式化输出
+`int rt_dstr_sprintf(rt_dstr_t *const thiz, const char *fmt, ...);`
+
+| 参数 | 描述 |
+| ---- | ---- |
+| thiz  | 动态字符串对象 |
+| fmt  | 格式化字符串 |
+| argument...  | 可选参数,任何类型的数据 |
+| return  | 返回动态字符串长度 |
+
+
+## 4、注意事项
+
+暂无
+
+## 5、联系方式 & 感谢
+
+* 维护:[never](https://github.com/neverxie)
+* 主页:https://github.com/RT-Thread-packages/dstr

+ 24 - 0
SConscript

@@ -0,0 +1,24 @@
+from building import * 
+
+# get current dir path
+cwd = GetCurrentDir()
+
+# init src and inc vars
+src = []
+inc = []
+
+# add dstr common include
+inc = inc + [cwd + '/dstr/inc']
+
+# add dstr basic code
+src = src + [cwd + '/dstr/src/dstr.c']
+
+# add dstr test code
+if GetDepend('DSTR_USING_EXAMPLE'):
+    src = src + [cwd + '/dstr/examples/examples_dstr.c']
+
+
+# add group to IDE project
+group = DefineGroup('dstr', src, depend = ['PKG_USING_DSTR'], CPPPATH = inc)
+
+Return('group')

+ 218 - 0
dstr/examples/examples_dstr.c

@@ -0,0 +1,218 @@
+/*
+ * File      : examples_dstr.c
+ * This file is the example code of dstr(dynamic string) package
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-07     never        the first version
+ */
+
+#include <rtthread.h>
+#include <finsh.h>
+#include "dstr.h"
+
+void rt_dstr_printf(rt_dstr_t *thiz)
+{
+    if (thiz == NULL)
+        return;
+    rt_kprintf("%s\n", thiz->str);
+}
+
+void dstr_test_new(void)
+{
+    rt_dstr_t *p = NULL;
+    
+    p = rt_dstr_new("new dstr");
+    rt_dstr_printf(p);
+    rt_dstr_del(p);
+}
+
+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);
+}
+
+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_del(p1);
+}
+
+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);
+}
+
+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
+    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);
+}
+
+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
+    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);    
+}
+
+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);
+}
+
+void dstr_test_sprintf(void)
+{    
+    const char *src = "test sprintf";
+    rt_dstr_t *p1 = NULL;
+    rt_dstr_t *p2 = NULL;
+    
+    //  string format
+    p1 = rt_dstr_new("");
+    
+    rt_dstr_sprintf(p1, "%s", src);
+    
+    rt_dstr_printf(p1);
+    
+    rt_dstr_del(p1);
+    
+    //  hex format    
+    p2 = rt_dstr_new("");
+    
+    rt_dstr_sprintf(p2, "%08x", 0x20180604);
+    
+    rt_dstr_printf(p2);
+    
+    rt_dstr_del(p2);    
+}
+
+void dstr_test(void)
+{
+    dstr_test_new();
+    dstr_test_cat();
+    dstr_test_ncat();
+    dstr_test_cmp();
+    dstr_test_ncmp();
+    dstr_test_casecmp();
+    dstr_test_strlen();
+    dstr_test_sprintf();
+}
+
+MSH_CMD_EXPORT(dstr_test, dstr example);

+ 51 - 0
dstr/inc/dstr.h

@@ -0,0 +1,51 @@
+/*
+ * File      : dstr.h
+ * This file is part of dstr (dynamic string) package
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-07     never        the first version
+ */
+
+#ifndef __DSTR_H__
+#define __DSTR_H__
+
+#include <rtthread.h>
+
+struct rt_dstr
+{
+    char *str;
+    size_t length;  //  allocated space
+};
+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);
+
+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);
+
+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, ...);
+
+#endif /* __DSTR_H__ */

+ 334 - 0
dstr/src/dstr.c

@@ -0,0 +1,334 @@
+/*
+ * File      : dstr.c
+ * This file is part of dstr (dynamic string) package
+ * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-06-07     never        the first version
+ */
+
+#include <rtthread.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "dstr.h"
+
+#define DBG_ENABLE
+#undef  DBG_ENABLE
+#define DBG_SECTION_NAME  "[RTDSTR]"
+#define DBG_LEVEL         DBG_INFO
+#define DBG_COLOR
+#include <rtdbg.h>
+
+/**
+ * This function will create a dstr(dynamic string) object.
+ *
+ * @param str the string
+ *
+ * @return a new dstr thiz
+ */
+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)
+    {
+        dbg_log(DBG_ERROR, "new malloc error\n");
+        return NULL;
+    }
+
+    thiz->length = strlen(str) + 1; //  allocated space
+    thiz->str = (char *)malloc(sizeof(char) * thiz->length);
+
+    if (thiz->str == NULL)
+    {
+        free(thiz);
+        return NULL;
+    }
+
+    memcpy(thiz->str, str, thiz->length);
+
+    return thiz;
+}
+
+/**
+ * This function will delete a dstr(dynamic string) object.
+ *
+ * @param thiz a dstr(dynamic string) thiz
+ *
+ * @return none
+ */
+void rt_dstr_del(rt_dstr_t *thiz)
+{
+    if (thiz == NULL)
+        return;
+
+    if (thiz->str == NULL)
+    {
+        free(thiz);
+        return;
+    }
+
+    free(thiz->str);
+
+    free(thiz);
+}
+
+static int rt_dstr_resize(rt_dstr_t *const thiz, size_t new_spacesize)
+{
+    char *p = NULL;
+
+    if (thiz == NULL)
+    {
+        dbg_log(DBG_ERROR, "resize.thiz param error\n");
+        return -1;
+    }
+    
+    p = (char *)realloc(thiz->str, new_spacesize);
+
+    if (p == NULL)
+    {
+        dbg_log(DBG_ERROR, "resize.realloc error\n");
+        return -1;
+    }
+    else
+    {   
+        thiz->length = new_spacesize;
+        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, 
+ * 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_cat(rt_dstr_t *const thiz, const char *src)
+{
+    return rt_dstr_ncat(thiz, src, strlen(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 src  the string
+ * @param count the maximum compare length
+ *
+ * @return the dest dstr
+ */
+rt_dstr_t *rt_dstr_ncat(rt_dstr_t *const 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   
+    
+    res = rt_dstr_resize(thiz, new_spacesize);
+
+    if (res == -1)
+    {
+        dbg_log(DBG_ERROR, "nacat.resize error\n");
+        return NULL;
+    }
+
+    memcpy(thiz->str + (old_spacesize - 1), src, n); 
+    *(thiz->str + (old_spacesize - 1) + n) = '\0';
+    
+    return thiz;
+}
+
+/**
+ * This function compares dstr1 and dstr2.
+ *
+ * @param dstr1 the dstr to be compared
+ * @param dstr2 the dstr to be compared
+ *
+ * @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)
+    {
+        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);
+}
+    
+/**
+ * This function compares dstr1 and dstr2.
+ *
+ * @param dstr1 the dstr to be compared
+ * @param dstr2 the dstr to be compared
+ * @param count the maximum compare length
+ *
+ * @return the result
+ */
+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;
+    }
+    
+    return strncmp(str1, str2, n);
+}
+
+/**
+ * This function will compare two dstrs while ignoring differences in case.
+ *
+ * @param dstr1 the dstr to be compared
+ * @param dstr2 the dstr to be compared
+ *
+ * @return the result
+ */
+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)
+    {
+        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);
+}
+
+/**
+ * This function will return the length of a dstr, which terminate will
+ * null character.
+ *
+ * @param thiz the dstr
+ *
+ * @return the length of dstr
+ */
+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
+ * null character.
+ *
+ * @param thiz the dstr
+ *
+ * @return the length of dstr
+ */
+int rt_dstr_sprintf(rt_dstr_t *const thiz, const char *fmt, ...)
+{
+    va_list  arg_ptr;
+    va_list  tmp;
+    int status = 0, res = 0, new_length = 0;
+    
+    va_start(arg_ptr, fmt);
+   
+    va_copy(tmp, arg_ptr);
+    
+    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)
+    {
+        va_end(arg_ptr);
+        return -1;
+    }  
+    
+    res = vsnprintf(thiz->str, new_length + 1, fmt, arg_ptr);
+
+    va_end(arg_ptr);
+    
+    return res;
+}