Added string vector(argv like) functions

This commit is contained in:
Nils O. Selåsdal
2013-09-04 18:10:26 +02:00
parent a5b8d53177
commit 216dfe879d
4 changed files with 291 additions and 1 deletions
+90
View File
@@ -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
View File
@@ -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
View File
@@ -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
+91
View File
@@ -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;
}