From f1ecb8299b9aeb8ed82c53e59bac98e728f66a80 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Thu, 1 Feb 2018 22:53:11 +0100 Subject: [PATCH] rollback strvec to previous version derivating strvec from vec is not a good idea for debug because the debugger does not know the type --- lib/ecoli_strvec.c | 178 ++++++++++++++++++++++++++++++++------------- lib/ecoli_strvec.h | 59 +++++++++++++++ 2 files changed, 188 insertions(+), 49 deletions(-) diff --git a/lib/ecoli_strvec.c b/lib/ecoli_strvec.c index 53017fb..51597a8 100644 --- a/lib/ecoli_strvec.c +++ b/lib/ecoli_strvec.c @@ -33,7 +33,6 @@ #include #include #include -#include #include EC_LOG_TYPE_REGISTER(strvec); @@ -43,97 +42,179 @@ struct ec_strvec_elt { char *str; }; -struct ec_strvec; +struct ec_strvec { + size_t len; + struct ec_strvec_elt **vec; +}; -static void ec_strvec_elt_free(void *ptr) +struct ec_strvec *ec_strvec(void) { - struct ec_strvec_elt **p_elt = ptr; - struct ec_strvec_elt *elt = *p_elt; + struct ec_strvec *strvec; - elt->refcnt--; - if (elt->refcnt == 0) { - ec_free(elt->str); + strvec = ec_calloc(1, sizeof(*strvec)); + if (strvec == NULL) + return NULL; + + return strvec; +} + +int ec_strvec_add(struct ec_strvec *strvec, const char *s) +{ + struct ec_strvec_elt *elt, **new_vec; + + new_vec = ec_realloc(strvec->vec, + sizeof(*strvec->vec) * (strvec->len + 1)); + if (new_vec == NULL) + return -ENOMEM; + + strvec->vec = new_vec; + + elt = ec_malloc(sizeof(*elt)); + if (elt == NULL) + return -ENOMEM; + + elt->str = ec_strdup(s); + if (elt->str == NULL) { ec_free(elt); + return -ENOMEM; } + elt->refcnt = 1; + + new_vec[strvec->len] = elt; + strvec->len++; + return 0; } -static void ec_strvec_elt_copy(void *dst, void *src) +struct ec_strvec *ec_strvec_from_array(const char * const *strarr, + size_t n) { - struct ec_strvec_elt **p_elt_dst = dst, **p_elt_src = src; - struct ec_strvec_elt *elt = *p_elt_src; + struct ec_strvec *strvec = NULL; + size_t i; + + strvec = ec_strvec(); + for (i = 0; i < n; i++) { + if (ec_strvec_add(strvec, strarr[i]) < 0) + goto fail; + } + + return strvec; - elt->refcnt++; - *p_elt_dst = elt; +fail: + ec_strvec_free(strvec); + return NULL; } -struct ec_strvec *ec_strvec(void) +int ec_strvec_del_last(struct ec_strvec *strvec) { - struct ec_vec *vec; + struct ec_strvec_elt *elt; - vec = ec_vec(sizeof(struct ec_strvec_elt *), 0, - ec_strvec_elt_copy, ec_strvec_elt_free); + if (strvec->len == 0) { + errno = EINVAL; + return -1; + } - return (struct ec_strvec *)vec; + elt = strvec->vec[strvec->len - 1]; + elt->refcnt--; + if (elt->refcnt == 0) { + ec_free(elt->str); + ec_free(elt); + } + strvec->len--; + return 0; } -int ec_strvec_add(struct ec_strvec *strvec, const char *s) +struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off, + size_t len) { - struct ec_strvec_elt *elt = NULL; + struct ec_strvec *copy = NULL; + size_t i, veclen; - elt = ec_malloc(sizeof(*elt)); - if (elt == NULL) - goto fail; + veclen = ec_strvec_len(strvec); + if (off + len > veclen) + return NULL; - elt->str = ec_strdup(s); - if (elt->str == NULL) + copy = ec_strvec(); + if (copy == NULL) goto fail; - elt->refcnt = 1; - if (ec_vec_add_ptr((struct ec_vec *)strvec, elt) < 0) + if (len == 0) + return copy; + + copy->vec = ec_calloc(len, sizeof(*copy->vec)); + if (copy->vec == NULL) goto fail; - return 0; + for (i = 0; i < len; i++) { + copy->vec[i] = strvec->vec[i + off]; + copy->vec[i]->refcnt++; + } + copy->len = len; -fail: - ec_free(elt); - return -1; -} + return copy; -struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off, - size_t len) -{ - return (struct ec_strvec *)ec_vec_ndup((struct ec_vec *)strvec, - off, len); +fail: + ec_strvec_free(copy); + return NULL; } struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec) { - return (struct ec_strvec *)ec_vec_dup((struct ec_vec *)strvec); + return ec_strvec_ndup(strvec, 0, ec_strvec_len(strvec)); } void ec_strvec_free(struct ec_strvec *strvec) { - ec_vec_free((struct ec_vec *)strvec); + struct ec_strvec_elt *elt; + size_t i; + + if (strvec == NULL) + return; + + for (i = 0; i < ec_strvec_len(strvec); i++) { + elt = strvec->vec[i]; + elt->refcnt--; + if (elt->refcnt == 0) { + ec_free(elt->str); + ec_free(elt); + } + } + + ec_free(strvec->vec); + ec_free(strvec); } size_t ec_strvec_len(const struct ec_strvec *strvec) { - return ec_vec_len((struct ec_vec *)strvec); + return strvec->len; } const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx) { - struct ec_strvec_elt *elt; - - if (ec_vec_get(&elt, (struct ec_vec *)strvec, idx) < 0) + if (strvec == NULL || idx >= strvec->len) return NULL; - return elt->str; + return strvec->vec[idx]->str; +} + +int ec_strvec_cmp(const struct ec_strvec *strvec1, + const struct ec_strvec *strvec2) +{ + size_t i; + + if (ec_strvec_len(strvec1) != ec_strvec_len(strvec2)) + return -1; + + for (i = 0; i < ec_strvec_len(strvec1); i++) { + if (strcmp(ec_strvec_val(strvec1, i), + ec_strvec_val(strvec2, i))) + return -1; + } + + return 0; } void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec) { - const char *s; size_t i; if (strvec == NULL) { @@ -141,13 +222,12 @@ void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec) return; } - fprintf(out, "strvec (len=%zu) [", ec_strvec_len(strvec)); + fprintf(out, "strvec (len=%zu) [", strvec->len); for (i = 0; i < ec_strvec_len(strvec); i++) { - s = ec_strvec_val(strvec, i); if (i == 0) - fprintf(out, "%s", s); + fprintf(out, "%s", strvec->vec[i]->str); else - fprintf(out, ", %s", s); + fprintf(out, ", %s", strvec->vec[i]->str); } fprintf(out, "]\n"); diff --git a/lib/ecoli_strvec.h b/lib/ecoli_strvec.h index 6d2a5b4..1c03734 100644 --- a/lib/ecoli_strvec.h +++ b/lib/ecoli_strvec.h @@ -46,6 +46,40 @@ */ struct ec_strvec *ec_strvec(void); +#ifndef EC_COUNT_OF +#define EC_COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / \ + ((size_t)(!(sizeof(x) % sizeof(0[x]))))) +#endif + +/** + * Allocate a new string vector + * + * The string vector is initialized with the list of const strings + * passed as arguments. + * + * @return + * The new strvec object, or NULL on error (errno is set). + */ +#define EC_STRVEC(args...) ({ \ + const char *_arr[] = {args}; \ + ec_strvec_from_array(_arr, EC_COUNT_OF(_arr)); \ + }) +/** + * Allocate a new string vector + * + * The string vector is initialized with the array of const strings + * passed as arguments. + * + * @param strarr + * The array of const strings. + * @param n + * The number of strings in the array. + * @return + * The new strvec object, or NULL on error (errno is set). + */ +struct ec_strvec *ec_strvec_from_array(const char * const *strarr, + size_t n); + /** * Add a string in a vector. * @@ -58,6 +92,18 @@ struct ec_strvec *ec_strvec(void); */ int ec_strvec_add(struct ec_strvec *strvec, const char *s); +/** + * Delete the last entry in the string vector. + * + * @param strvec + * The pointer to the string vector. + * @param s + * The string to be added at the end of the vector. + * @return + * 0 on success or -1 on error (errno is set). + */ +int ec_strvec_del_last(struct ec_strvec *strvec); + /** * Duplicate a string vector. * @@ -114,6 +160,19 @@ size_t ec_strvec_len(const struct ec_strvec *strvec); */ const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx); +/** + * Compare two string vectors + * + * @param strvec + * The pointer to the first string vector. + * @param strvec + * The pointer to the second string vector. + * @return + * 0 if the string vectors are equal. + */ +int ec_strvec_cmp(const struct ec_strvec *strvec1, + const struct ec_strvec *strvec2); + /** * Dump a string vector. * -- 2.39.5