~donmcc/astr

baa5210a47e207148a1cb7906dc20f264c133822 — Don McCaughey 1 year, 8 months ago f3b4c1f
Added functions to append formatted characters.

Added functions

    astr_realloc_append_formatted()
    astr_realloc_append_formatted_from_va_list()

along with tests, man page and readme documentation.
5 files changed, 155 insertions(+), 9 deletions(-)

M README.md
M astr.3
M astr.c
M astr.h
M astr_tests.c
M README.md => README.md +18 -7
@@ 9,7 9,12 @@ A C99 library for working with dynamically allocated strings.
All functions in *astr* begin with the `astr_` prefix.  Functions that return
newly allocated strings will contain `_alloc` in their names; the caller is
responsible for calling [`free()`][1] on the returned pointer.
Functions with `_realloc` in their names take a pointer to a string as an 
_in-out_ parameter; these functions may reallocate the string, replacing the
pointed-to string value.
Functions with `_format` take a `printf()` style format string.
Functions with `_append` in their name will add characters to the end of the
given string.
Functions that end with the suffix `_from_va_list` take variable arguments as a 
`va_list` object from `stdarg.h`.



@@ 25,12 30,10 @@ Allocate an empty string.
    char *
    astr_alloc_formatted(char const *format, ...);

Allocate a formatted string.

    char *
    astr_alloc_formatted_from_va_list(char const *format, va_list arguments);

Allocate a formatted string using a `va_list` object.
Allocate a formatted string.

    bool
    astr_eq(char const *s1, char const *s2);


@@ 40,13 43,21 @@ Compare the bytes of two strings for equality; `s1` and `s2` may be `NULL`.
    size_t
    astr_formatted_length(char const *format, ...);

Calculate the length in bytes needed for the formatted string.

    size_t
    astr_formatted_length_from_va_list(char const *format, va_list arguments);

Calculate the length in bytes needed for the formatted string using a `va_list`
object.
Calculate the length in bytes needed for the formatted string.

    int
    astr_realloc_append_formatted(char **s, char const *format, ...);

    int
    astr_realloc_append_foramtted_from_va_list(char **s, char const *format, va_list arguments);

Append formatted characters to the end of the given string, returning 0 on 
success and -1 on error.
The parameter `s` may point to different address on success.


## Dependencies
`astr` requires that `<stdio.h>` defines the [`vasprintf()`][2] and

M astr.3 => astr.3 +35 -2
@@ 7,7 7,9 @@
.Nm astr_alloc_formatted_from_va_list ,
.Nm astr_eq ,
.Nm astr_formatted_length ,
.Nm astr_formatted_length_from_va_list
.Nm astr_formatted_length_from_va_list ,
.Nm astr_realloc_append_formatted ,
.Nm astr_realloc_append_formatted_from_va_list
.Nd functions for working with dynamically allocated strings.
.Sh SYNOPSIS
.In astr.h


@@ 23,6 25,10 @@
.Fn astr_formatted_length "char const *format" "..."
.Ft size_t
.Fn astr_formatted_length_from_va_list "char const *format" "va_list arguments"
.Ft int
.Fn astr_realloc_append_formatted "char **s" "char const *format"
.Ft int
.Fn astr_realloc_append_formatted_from_va_list "char **s" "char const *format" "va_list arguments"
.Sh DESCRIPTION
The
.Nm astr


@@ 42,6 48,11 @@ Functions that return newly allocated strings will contain
in their name; the caller is responsible for calling
.Fn free
on the returned pointer.
Functions that resize a string will contain
.Sy _realloc
in their name; they will take a pointer to a string as an
.Em in-out
parameter.
Functions with
.Sy _formatted
in their name take a


@@ 50,6 61,9 @@ string as specified for
.Xr printf 3
along with zero or more additional arguments as determined by the given format
and produce formatted output.
Functions with
.Sy _append
in their name will add characters to the end of the given string.
Functions that end with the suffix
.Sy _from_va_list
take a variable number of


@@ 81,6 95,12 @@ The
and
.Fn astr_formatted_length_from_va_list
functions calculate the length in bytes required to hold the formatted string.
.Pp
The
.Fn astr_realloc_append_formatted
and
.Fn astr_realloc_append_foramtted_from_va_list
functions append formatted characters to a string.
.Sh RETURN VALUES
.Fn astr_alloc_empty
returns a pointer to a zero-length string on success.


@@ 94,7 114,7 @@ If there is an error, these functions return a
pointer and set
.Va errno
to
.Er ENOMEM .
.Er EINVAL .
.Pp
.Fn astr_eq
returns


@@ 110,6 130,19 @@ the terminating null character on success.
If there is an error, these functions return zero and set
.Va errno
to
.Er EINVAL.
.Pp
On success,
.Fn astr_realloc_append_formatted
and
.Fn astr_realloc_append_foramtted_from_va_list
return 0 and
.Fa s
may contain a different string address.
.Pp
On failure, these functions return -1 and set
.Va errno
to
.Er EINVAL .
.Sh SEE ALSO
.Xr free 3 ,

M astr.c => astr.c +38 -0
@@ 59,6 59,44 @@ astr_formatted_length_from_va_list(char const *format, va_list arguments)
}


int
astr_realloc_append_formatted(char **s, char const *format, ...)
{
    va_list arguments;
    va_start(arguments, format);
    int result = astr_realloc_append_formatted_from_va_list(s, format, arguments);
    va_end(arguments);
    return result;
}


int
astr_realloc_append_formatted_from_va_list(char **s, 
                                           char const *format, 
                                           va_list arguments)
{
    if (!s || !format) {
        errno = EINVAL;
        return -1;
    }

    size_t length_to_append = astr_formatted_length_from_va_list(format, arguments);
    if (!length_to_append) return 0;

    size_t original_length = strlen(*s);
    size_t new_size = original_length + length_to_append + sizeof('\0');
    char *resized_s = realloc(*s, new_size);
    if (!resized_s) return -1;

    *s = resized_s;
    char *end_of_s = *s + original_length;
    va_list arguments_copy;
    va_copy(arguments_copy, arguments);
    vsprintf(end_of_s, format, arguments_copy);
    return 0;
}


extern char *
astr_alloc_empty(void);


M astr.h => astr.h +8 -0
@@ 20,6 20,14 @@ astr_formatted_length(char const *format, ...);
size_t
astr_formatted_length_from_va_list(char const *format, va_list arguments);

int
astr_realloc_append_formatted(char **s, char const *format, ...);

int
astr_realloc_append_formatted_from_va_list(char **s, 
                                           char const *format, 
                                           va_list arguments);


inline char *
astr_alloc_empty(void)

M astr_tests.c => astr_tests.c +56 -0
@@ 95,6 95,59 @@ test_astr_formatted_length_for_NULL_format(void)
}


static void
test_astr_realloc_append_formatted(void)
{
    char *s = astr_alloc_formatted("foo");

    int result = astr_realloc_append_formatted(&s, "bar %i", 42);

    assert(0 == result);
    assert(astr_eq("foobar 42", s));
    free(s);
}


static void
test_astr_realloc_append_formatted_for_empty_format(void)
{
    char *s = astr_alloc_formatted("foo");
    char *original_s = s;

    int result = astr_realloc_append_formatted(&s, "");

    assert(0 == result);
    assert(original_s == s);
    assert(astr_eq("foo", s));
    free(s);
}


static void
test_astr_realloc_append_formatted_for_NULL_string(void)
{
    errno = 0;
    int result = astr_realloc_append_formatted(NULL, "foobar");

    assert(-1 == result);
    assert(EINVAL == errno);
}


static void
test_astr_realloc_append_formatted_for_NULL_format(void)
{
    char *s = astr_alloc_formatted("foo");

    errno = 0;
    int result = astr_realloc_append_formatted(&s, NULL);

    assert(-1 == result);
    assert(EINVAL == errno);
    free(s);
}


int
main(int argc, char *argv[])
{


@@ 106,6 159,9 @@ main(int argc, char *argv[])
    test_astr_eq_for_empty_strings();
    test_astr_formatted_length();
    test_astr_formatted_length_for_NULL_format();
    test_astr_realloc_append_formatted_for_empty_format();
    test_astr_realloc_append_formatted_for_NULL_string();
    test_astr_realloc_append_formatted_for_NULL_format();
    return EXIT_SUCCESS;
}