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 *human_bytesz_suite(void);
|
||||||
extern Suite *dbuf_suite(void);
|
extern Suite *dbuf_suite(void);
|
||||||
extern Suite *sprintb_suite(void);
|
extern Suite *sprintb_suite(void);
|
||||||
|
extern Suite *strv_suite(void);
|
||||||
|
|
||||||
static suite_func suites[] = {
|
static suite_func suites[] = {
|
||||||
bitvec_suite,
|
bitvec_suite,
|
||||||
@@ -41,7 +42,8 @@ static suite_func suites[] = {
|
|||||||
mbuf_suite,
|
mbuf_suite,
|
||||||
human_bytesz_suite,
|
human_bytesz_suite,
|
||||||
dbuf_suite,
|
dbuf_suite,
|
||||||
sprintb_suite
|
sprintb_suite,
|
||||||
|
strv_suite
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
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