Added string vector(argv like) functions
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef UC_STRVEC_H_
|
||||
#define UC_STRVEC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/** A Vector of strings.*/
|
||||
struct UCStrv
|
||||
{
|
||||
/** number of strings */
|
||||
size_t cnt;
|
||||
/** allocated room in strings (internal use) */
|
||||
size_t allocated;
|
||||
/** Array of strings */
|
||||
char **strings;
|
||||
};
|
||||
|
||||
/** Initialize a UCStrv
|
||||
*
|
||||
* @param strv
|
||||
*/
|
||||
void uc_strv_init(struct UCStrv *strv);
|
||||
|
||||
/**
|
||||
* Grow the UCStrv so it can hold n more items
|
||||
*
|
||||
* @param strv UCStrv to grow
|
||||
* @param cnt expand strvec to hold this cnt more items
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
int uc_strv_grow(struct UCStrv *strv, size_t cnt);
|
||||
|
||||
/**
|
||||
* Expand the UCStrv to hold 1 more item
|
||||
*
|
||||
* @param strv UCStrv to expand
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
int uc_strv_expand(struct UCStrv *strv);
|
||||
|
||||
/**
|
||||
* Append a string to the UCStrv, the string will be copied in
|
||||
*
|
||||
* @param strv UCStrv to append to
|
||||
* @param str String to append, the string will be copied.
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
int uc_strv_append(struct UCStrv *strv, const char *str);
|
||||
|
||||
/**
|
||||
* Append a string to the strvec, nocopy variang.
|
||||
* The string shold be dynamically allocated, as
|
||||
* destroying the UCStrv will free() all items.
|
||||
*
|
||||
* @param strv UCStrv to add to
|
||||
* @param str the string to append
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
int uc_strv_append_nocopy(struct UCStrv *strv, char *str);
|
||||
|
||||
/**
|
||||
* Append a NULL pointer to the UCStrv, (cnt is not increased,
|
||||
* so another _appended item will overwrite this NULL terminator)
|
||||
*
|
||||
* @param strv UCStrv to append to
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
int uc_strv_null_terminate(struct UCStrv *strv);
|
||||
|
||||
/**
|
||||
* free all strings in this UCStrv, cnt will be 0 after this
|
||||
* @param strv UCStrv to clear
|
||||
*/
|
||||
void uc_strv_clear(struct UCStrv *strv);
|
||||
|
||||
/**
|
||||
* free all elements as well as the underlying array, the UCStrv is
|
||||
* unusable after this call
|
||||
*
|
||||
* @param strv UCStrv to destroy
|
||||
*/
|
||||
void uc_strv_destroy(struct UCStrv *strv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "ucore/strvec.h"
|
||||
|
||||
void uc_strv_init(struct UCStrv *strv)
|
||||
{
|
||||
strv->cnt = 0;
|
||||
strv->allocated = 0;
|
||||
strv->strings = NULL;
|
||||
}
|
||||
|
||||
int uc_strv_grow(struct UCStrv *strv, size_t cnt)
|
||||
{
|
||||
|
||||
size_t allocate = strv->allocated + cnt;
|
||||
void *tmp = realloc(strv->strings, sizeof *strv->strings * allocate);
|
||||
|
||||
if (tmp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
strv->strings = tmp;
|
||||
strv->allocated = allocate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uc_strv_expand(struct UCStrv *strv)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (strv->cnt >= strv->allocated) {
|
||||
rc = uc_strv_grow(strv, 1);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int uc_strv_append(struct UCStrv *strv, const char *str)
|
||||
{
|
||||
int rc;
|
||||
char *dup;
|
||||
|
||||
rc = uc_strv_expand(strv);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
dup = strdup(str);
|
||||
if (dup == NULL) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
strv->strings[strv->cnt] = dup;
|
||||
strv->cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uc_strv_append_nocopy(struct UCStrv *strv, char *str)
|
||||
{
|
||||
int rc;
|
||||
rc = uc_strv_expand(strv);
|
||||
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
strv->strings[strv->cnt] = str;
|
||||
strv->cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uc_strv_null_terminate(struct UCStrv *strv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = uc_strv_expand(strv);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
strv->strings[strv->cnt] = NULL;
|
||||
strv->cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uc_strv_clear(struct UCStrv *strv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < strv->cnt; i++) {
|
||||
free(strv->strings[i]);
|
||||
strv->strings[i] = NULL;
|
||||
}
|
||||
|
||||
strv->cnt = 0;
|
||||
}
|
||||
|
||||
void uc_strv_destroy(struct UCStrv *strv)
|
||||
{
|
||||
uc_strv_clear(strv);
|
||||
free(strv->strings);
|
||||
strv->strings = NULL;
|
||||
}
|
||||
|
||||
+3
-1
@@ -23,6 +23,7 @@ extern Suite *mbuf_suite(void);
|
||||
extern Suite *human_bytesz_suite(void);
|
||||
extern Suite *dbuf_suite(void);
|
||||
extern Suite *sprintb_suite(void);
|
||||
extern Suite *strv_suite(void);
|
||||
|
||||
static suite_func suites[] = {
|
||||
bitvec_suite,
|
||||
@@ -41,7 +42,8 @@ static suite_func suites[] = {
|
||||
mbuf_suite,
|
||||
human_bytesz_suite,
|
||||
dbuf_suite,
|
||||
sprintb_suite
|
||||
sprintb_suite,
|
||||
strv_suite
|
||||
};
|
||||
|
||||
int
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <check.h>
|
||||
#include <string.h>
|
||||
#include <ucore/strvec.h>
|
||||
|
||||
|
||||
START_TEST (test_strv_append)
|
||||
struct UCStrv strv;
|
||||
int rc;
|
||||
|
||||
uc_strv_init(&strv);
|
||||
|
||||
rc = uc_strv_append(&strv, "string");
|
||||
fail_if(rc != 0);
|
||||
fail_if(strv.cnt != 1);
|
||||
ck_assert_str_eq("string", strv.strings[0]);
|
||||
|
||||
rc = uc_strv_append(&strv, "string2");
|
||||
fail_if(rc != 0);
|
||||
fail_if(strv.cnt != 2);
|
||||
ck_assert_str_eq("string2", strv.strings[1]);
|
||||
|
||||
uc_strv_destroy(&strv);
|
||||
|
||||
END_TEST
|
||||
|
||||
START_TEST (test_strv_clear)
|
||||
struct UCStrv strv;
|
||||
int rc;
|
||||
|
||||
uc_strv_init(&strv);
|
||||
|
||||
rc = uc_strv_append(&strv, "string");
|
||||
fail_if(rc != 0);
|
||||
fail_if(strv.cnt != 1);
|
||||
|
||||
uc_strv_clear(&strv);
|
||||
fail_if(strv.cnt != 0);
|
||||
uc_strv_destroy(&strv);
|
||||
|
||||
END_TEST
|
||||
|
||||
START_TEST (test_strv_nocopy)
|
||||
struct UCStrv strv;
|
||||
char *str = strdup("string");
|
||||
int rc;
|
||||
|
||||
uc_strv_init(&strv);
|
||||
|
||||
rc = uc_strv_append_nocopy(&strv, str);
|
||||
fail_if(rc != 0);
|
||||
fail_if(strv.cnt != 1);
|
||||
fail_if(strv.strings[0] != str);
|
||||
|
||||
uc_strv_destroy(&strv);
|
||||
|
||||
END_TEST
|
||||
|
||||
START_TEST (test_strv_null_terminate)
|
||||
struct UCStrv strv;
|
||||
int rc;
|
||||
|
||||
uc_strv_init(&strv);
|
||||
|
||||
rc = uc_strv_append(&strv, "string");
|
||||
fail_if(rc != 0);
|
||||
fail_if(strv.cnt != 1);
|
||||
|
||||
rc = uc_strv_null_terminate(&strv);
|
||||
fail_if(rc != 0);
|
||||
fail_if(strv.strings[strv.cnt] != NULL);
|
||||
|
||||
uc_strv_destroy(&strv);
|
||||
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite *strv_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("strvec");
|
||||
TCase *tc = tcase_create("strvec");
|
||||
|
||||
tcase_add_test(tc, test_strv_append);
|
||||
tcase_add_test(tc, test_strv_clear);
|
||||
tcase_add_test(tc, test_strv_nocopy);
|
||||
tcase_add_test(tc, test_strv_null_terminate);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user