From 34643b8a8d954b77d1928f39f380e3c09b05e7dc Mon Sep 17 00:00:00 2001 From: XaviDCR92 Date: Sat, 21 Mar 2020 13:14:48 +0100 Subject: [PATCH] Various changes and improvements - Replaced int by specific, more meaningful error codes. - C99 states realloc can be safely called using NULL pointers. - New function dynstr_dup(). --- dynstr.c | 51 +++++++++++++++++++++++++++++++++++------------- include/dynstr.h | 35 ++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/dynstr.c b/dynstr.c index 8779fbf..025f1fc 100644 --- a/dynstr.c +++ b/dynstr.c @@ -26,7 +26,7 @@ void dynstr_init(struct dynstr *const d) memset(d, 0, sizeof *d); } -int dynstr_append(struct dynstr *const d, const char *const format, ...) +enum dynstr_err dynstr_append(struct dynstr *const d, const char *const format, ...) { va_list ap; @@ -34,19 +34,10 @@ int dynstr_append(struct dynstr *const d, const char *const format, ...) { const size_t src_len = vsnprintf(NULL, 0, format, ap); - size_t new_len; + const size_t new_len = d->len + src_len + 1; va_end(ap); - if (!d->str) - { - new_len = src_len + 1; - d->str = malloc(new_len * sizeof *d->str); - } - else - { - new_len = d->len + src_len + 1; - d->str = realloc(d->str, new_len * sizeof *d->str); - } + d->str = realloc(d->str, new_len * sizeof *d->str); if (d->str) { @@ -57,11 +48,43 @@ int dynstr_append(struct dynstr *const d, const char *const format, ...) } else { - return 1; + return DYNSTR_ERR_ALLOC; } } - return 0; + return DYNSTR_OK; +} + +enum dynstr_err dynstr_dup(struct dynstr *const dst, const struct dynstr *const src) +{ + if (!dst->str && !dst->len) + { + if (src->len && src->str) + { + const size_t sz = (src->len + 1) * sizeof *dst->str; + dst->str = realloc(dst->str, sz); + + if (dst->str) + { + memcpy(dst->str, src->str, sz); + dst->len = src->len; + } + else + { + return DYNSTR_ERR_ALLOC; + } + } + else + { + return DYNSTR_ERR_SRC; + } + } + else + { + return DYNSTR_ERR_INIT; + } + + return DYNSTR_OK; } void dynstr_free(struct dynstr *const d) diff --git a/include/dynstr.h b/include/dynstr.h index a2e8f41..a545b81 100644 --- a/include/dynstr.h +++ b/include/dynstr.h @@ -45,7 +45,7 @@ /** * Convenience macro that calls dynstr_append and returns its error code if failed. */ -#define dynstr_append_or_ret(d, format, ...) {const int err = dynstr_append(d, format, ## __VA_ARGS__); if (err) return err;} +#define dynstr_append_or_ret(d, format, ...) {const enum dynstr_err err = dynstr_append(d, format, ## __VA_ARGS__); if (err) return err;} /** * Convenience macro that calls dynstr_append and returns zero if failed. @@ -65,6 +65,19 @@ struct dynstr size_t len; /**< String length, null character not included. */ }; +/** + * List of errors that this library might return. + * @note If using GNU C extensions, this errors can be translated into other + * types by using the convenience macros above. + */ +enum dynstr_err +{ + DYNSTR_OK, /**< Operation was successful. */ + DYNSTR_ERR_ALLOC, /**< Alloc operation failed. */ + DYNSTR_ERR_INIT, /**< Dynamic string was not initialized. */ + DYNSTR_ERR_SRC /**< Source string has invalid parameters. */ +}; + /** * Reportedly, it initializes an empty string with zero length. * @attention Always call this function when creating a dynstr instance. @@ -78,9 +91,25 @@ void dynstr_init(struct dynstr *d); * dynamic string. * @param d Dynamic string where new string will be appended. * @param format String literal in printf format. - * @return Returns 0 if successful, 1 if alloc operation failed. + * @return Returns one of the following error codes: + * # DYNSTR_OK if successful. + * # DYNSTR_ERR_ALLOC if no more memory is available. */ -int dynstr_append(struct dynstr *d, const char *format, ...); +enum dynstr_err dynstr_append(struct dynstr *d, const char *format, ...); + +/** + * This function duplicates a dynamic string to another instance. + * @attention Destination instance must be initialized before calling + * this function. + * @attention Since this function performs a deep copy, please remember to + * free the source instance if no longer used to avoid memory leaks. + * @return Returns one of the following error codes: + * # DYNSTR_OK if successful. + * # DYNSTR_ERR_ALLOC if no more memory is available. + * # DYNSTR_ERR_INIT if destination dynamic string was not initialized. + * # DYNSTR_ERR_SRC if source dynamic string has no length or data. + */ +enum dynstr_err dynstr_dup(struct dynstr *dst, const struct dynstr *src); /** * This function frees memory used by the dynamic string.