From 15eb0c66a435e18c0ba4e07d784eaaab51d0d939 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Tue, 28 Apr 2020 21:57:19 -0500 Subject: [PATCH] Feature: implement append and prepend string functions --- level_1/fl_string/c/private-string.c | 48 +++++++++++ level_1/fl_string/c/private-string.h | 54 ++++++++++++ level_1/fl_string/c/string.c | 72 ++++++++++++++++ level_1/fl_string/c/string.h | 158 +++++++++++++++++++++++++++++++++++ 4 files changed, 332 insertions(+) diff --git a/level_1/fl_string/c/private-string.c b/level_1/fl_string/c/private-string.c index ee01f3f..81cdfbe 100644 --- a/level_1/fl_string/c/private-string.c +++ b/level_1/fl_string/c/private-string.c @@ -5,6 +5,27 @@ extern "C" { #endif +#if !defined(_di_fl_string_append_) || !defined(_di_fl_string_dynamic_append_) || !defined(_di_fl_string_dynamic_partial_append_) + f_return_status private_fl_string_append(const f_string source, const f_string_length source_length, f_string_dynamic *destination) { + f_status status = f_none; + + f_string_length total = destination->used + source_length; + + if (total > f_string_max_size) return f_status_set_error(f_string_too_large); + + if (total > destination->size) { + f_macro_string_dynamic_resize(status, (*destination), total); + if (f_status_is_error(status)) return status; + } + + memcpy(destination->string + destination->used, source, source_length); + + destination->used = total; + + return f_none; + } +#endif // !defined(_di_fl_string_append_) || !defined(_di_fl_string_dynamic_append_) || !defined(_di_fl_string_dynamic_partial_append_) + #if !defined(_di_fl_string_compare_) || !defined(_di_fl_string_dynamic_compare_) || !defined(_di_fl_string_dynamic_partial_compare_) f_return_status private_fl_string_compare(const f_string string1, const f_string string2, const f_string_length offset1, const f_string_length offset2, const f_string_length stop1, const f_string_length stop2) { f_string_length i1 = offset1; @@ -207,6 +228,33 @@ extern "C" { } #endif // !defined(_di_fl_string_mash_) || !defined(_di_fl_string_dynamic_mash_) || !defined(_di_fl_string_dynamic_partial_mash_) +#if !defined(_di_fl_string_prepend_) || !defined(_di_fl_string_dynamic_prepend_) || !defined(_di_fl_string_dynamic_partial_prepend_) + f_return_status private_fl_string_prepend(const f_string source, const f_string_length source_length, f_string_dynamic *destination) { + f_status status = f_none; + + f_string_length total = destination->used + source_length; + + if (total > f_string_max_size) return f_status_set_error(f_string_too_large); + + if (total > destination->size) { + f_macro_string_dynamic_resize(status, (*destination), total); + if (f_status_is_error(status)) return status; + } + + if (destination->used > 0) { + memmove(destination->string + source_length, destination->string, destination->used); + memcpy(destination->string, source, source_length); + } + else { + memcpy(destination->string, source, source_length); + } + + destination->used = total; + + return f_none; + } +#endif // !defined(_di_fl_string_prepend_) || !defined(_di_fl_string_dynamic_prepend_) || !defined(_di_fl_string_dynamic_partial_prepend_) + #if !defined(_di_fl_string_rip_) || !defined(_di_fl_string_dynamic_rip_) f_return_status private_fl_string_rip(const f_string string, const f_string_length start, const f_string_length stop, f_string_dynamic *result) { // The start and stop point are inclusive locations, and therefore start - stop is actually 1 too few locations. diff --git a/level_1/fl_string/c/private-string.h b/level_1/fl_string/c/private-string.h index 6c339fe..e5ce484 100644 --- a/level_1/fl_string/c/private-string.h +++ b/level_1/fl_string/c/private-string.h @@ -18,6 +18,33 @@ extern "C" { #endif /** + * Private implementation of fl_string_append(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param source + * The source string to append. + * @param source_length + * Total number of bytes to copy from source string. + * @param destination + * The destination string the source and glue are appended onto. + * + * @return + * f_none on success. + * f_string_max_size (with error bit) if the combined string is too large. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_allocation (with error bit) on memory allocation error. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see fl_string_append() + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_partial_append() + */ +#if !defined(_di_fl_string_append_) || !defined(_di_fl_string_dynamic_append_) || !defined(_di_fl_string_dynamic_partial_append_) + extern f_return_status private_fl_string_append(const f_string source, const f_string_length source_length, f_string_dynamic *destination) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_string_append_) || !defined(_di_fl_string_dynamic_append_) || !defined(_di_fl_string_dynamic_partial_append_) + +/** * Private implementation of fl_string_compare(). * * Intended to be shared to each of the different implementation variations. @@ -111,6 +138,33 @@ extern "C" { #endif // !defined(_di_fl_string_mash_) || !defined(_di_fl_string_dynamic_mash_) || !defined(_di_fl_string_dynamic_partial_mash_) /** + * Private implementation of fl_string_prepend(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param source + * The source string to prepend. + * @param source_length + * Total number of bytes to copy from source string. + * @param destination + * The destination string the source and glue are prepended onto. + * + * @return + * f_none on success. + * f_string_max_size (with error bit) if the combined string is too large. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_allocation (with error bit) on memory allocation error. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see fl_string_prepend() + * @see fl_string_dynamic_prepend() + * @see fl_string_dynamic_partial_prepend() + */ +#if !defined(_di_fl_string_prepend_) || !defined(_di_fl_string_dynamic_prepend_) || !defined(_di_fl_string_dynamic_partial_prepend_) + extern f_return_status private_fl_string_prepend(const f_string source, const f_string_length source_length, f_string_dynamic *destination) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_string_prepend_) || !defined(_di_fl_string_dynamic_prepend_) || !defined(_di_fl_string_dynamic_partial_prepend_) + +/** * Private implementation of fl_string_rip(). * * Intended to be shared to each of the different implementation variations. diff --git a/level_1/fl_string/c/string.c b/level_1/fl_string/c/string.c index 4b3c1c0..ad606f1 100644 --- a/level_1/fl_string/c/string.c +++ b/level_1/fl_string/c/string.c @@ -5,6 +5,17 @@ extern "C" { #endif +#ifndef _di_fl_string_append_ + f_return_status fl_string_append(const f_string source, const f_string_length source_length, f_string_dynamic *destination) { + #ifndef _di_level_1_parameter_checking_ + if (source_length < 1) return f_status_set_error(f_invalid_parameter); + if (destination == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_1_parameter_checking_ + + return private_fl_string_append(source, source_length, destination); + } +#endif // _di_fl_string_append_ + #ifndef _di_fl_string_compare_ f_return_status fl_string_compare(const f_string string1, const f_string string2, const f_string_length length1, const f_string_length length2) { #ifndef _di_level_1_parameter_checking_ @@ -49,6 +60,17 @@ extern "C" { } #endif // _di_fl_string_dynamic_compare_trim_ +#ifndef _di_fl_string_dynamic_append_ + f_return_status fl_string_dynamic_append(const f_string_dynamic source, f_string_dynamic *destination) { + #ifndef _di_level_1_parameter_checking_ + if (source.used < 1) return f_status_set_error(f_invalid_parameter); + if (destination == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_1_parameter_checking_ + + return private_fl_string_append(source.string, source.used, destination); + } +#endif // _di_fl_string_dynamic_append_ + #ifndef _di_fl_string_dynamic_mash_ f_return_status fl_string_dynamic_mash(const f_string glue, const f_string_length glue_length, const f_string_dynamic source, f_string_dynamic *destination) { #ifndef _di_level_1_parameter_checking_ @@ -95,6 +117,20 @@ extern "C" { } #endif // _di_fl_string_dynamic_partial_compare_trim_ +#ifndef _di_fl_string_dynamic_partial_append_ + f_return_status fl_string_dynamic_partial_append(const f_string_dynamic source, const f_string_location offset, f_string_dynamic *destination) { + #ifndef _di_level_1_parameter_checking_ + if (source.used < 1) return f_status_set_error(f_invalid_parameter); + if (destination == 0) return f_status_set_error(f_invalid_parameter); + + if (offset.start > offset.stop) return f_status_set_error(f_invalid_parameter); + if (source.used <= offset.stop) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_1_parameter_checking_ + + return private_fl_string_append(source.string + offset.start, (offset.stop - offset.start) + 1, destination); + } +#endif // _di_fl_string_dynamic_partial_append_ + #ifndef _di_fl_string_dynamic_partial_mash_ f_return_status fl_string_dynamic_partial_mash(const f_string glue, const f_string_length glue_length, const f_string_dynamic source, const f_string_location offset, f_string_dynamic *destination) { #ifndef _di_level_1_parameter_checking_ @@ -110,6 +146,31 @@ extern "C" { } #endif // _di_fl_string_dynamic_partial_mash_ +#ifndef _di_fl_string_dynamic_partial_prepend_ + f_return_status fl_string_dynamic_partial_prepend(const f_string_dynamic source, const f_string_location offset, f_string_dynamic *destination) { + #ifndef _di_level_1_parameter_checking_ + if (source.used < 1) return f_status_set_error(f_invalid_parameter); + if (destination == 0) return f_status_set_error(f_invalid_parameter); + + if (offset.start > offset.stop) return f_status_set_error(f_invalid_parameter); + if (source.used <= offset.stop) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_1_parameter_checking_ + + return private_fl_string_prepend(source.string + offset.start, (offset.stop - offset.start) + 1, destination); + } +#endif // _di_fl_string_dynamic_partial_prepend_ + +#ifndef _di_fl_string_dynamic_prepend_ + f_return_status fl_string_dynamic_prepend(const f_string_dynamic source, f_string_dynamic *destination) { + #ifndef _di_level_1_parameter_checking_ + if (source.used < 1) return f_status_set_error(f_invalid_parameter); + if (destination == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_1_parameter_checking_ + + return private_fl_string_prepend(source.string, source.used, destination); + } +#endif // _di_fl_string_dynamic_prepend_ + #ifndef _di_fl_string_dynamic_rip_ f_return_status fl_string_dynamic_rip(const f_string_dynamic buffer, const f_string_location location, f_string_dynamic *result) { #ifndef _di_level_1_parameter_checking_ @@ -452,6 +513,17 @@ extern "C" { } #endif // _di_fl_string_mash_ +#ifndef _di_fl_string_prepend_ + f_return_status fl_string_prepend(const f_string source, const f_string_length source_length, f_string_dynamic *destination) { + #ifndef _di_level_1_parameter_checking_ + if (source_length < 1) return f_status_set_error(f_invalid_parameter); + if (destination == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_1_parameter_checking_ + + return private_fl_string_prepend(source, source_length, destination); + } +#endif // _di_fl_string_prepend_ + #ifndef _di_fl_string_rip_ f_return_status fl_string_rip(const f_string string, const f_string_length start, const f_string_length stop, f_string_dynamic *result) { #ifndef _di_level_1_parameter_checking_ diff --git a/level_1/fl_string/c/string.h b/level_1/fl_string/c/string.h index 1a1bf94..58f078a 100644 --- a/level_1/fl_string/c/string.h +++ b/level_1/fl_string/c/string.h @@ -35,6 +35,31 @@ extern "C" { #endif /** + * Append the source string onto the destination. + * + * @param source + * The source string to append. + * @param source_length + * Total number of bytes to copy from source string. + * @param destination + * The destination string the source is appended onto. + * + * @return + * f_none on success. + * f_string_max_size (with error bit) if the combined string is too large. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_allocation (with error bit) on memory allocation error. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see fl_string_append() + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_partial_append() + */ +#ifndef _di_fl_string_append_ + extern f_return_status fl_string_append(const f_string source, const f_string_length source_length, f_string_dynamic *destination); +#endif // _di_fl_string_append_ + +/** * Compare two strings, similar to strncmp(). * * This does not stop on NULL. @@ -94,6 +119,29 @@ extern "C" { #endif // _di_fl_string_compare_trim_ /** + * Append the source string onto the destination. + * + * @param source + * The source string to append. + * @param destination + * The destination string the source is appended onto. + * + * @return + * f_none on success. + * f_string_max_size (with error bit) if the combined string is too large. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_allocation (with error bit) on memory allocation error. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see fl_string_append() + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_partial_append() + */ +#ifndef _di_fl_string_dynamic_append_ + extern f_return_status fl_string_dynamic_append(const f_string_dynamic source, f_string_dynamic *destination); +#endif // _di_fl_string_dynamic_append_ + +/** * Compare two strings, similar to strncmp(). * * This does not stop on NULL. @@ -233,6 +281,31 @@ extern "C" { #endif // _di_fl_string_dynamic_partial_compare_trim_ /** + * Append the source string onto the destination. + * + * @param source + * The source string to append. + * @param offset + * A range within the source to restrict the append from. + * @param destination + * The destination string the source is appended onto. + * + * @return + * f_none on success. + * f_string_max_size (with error bit) if the combined string is too large. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_allocation (with error bit) on memory allocation error. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see fl_string_append() + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_partial_append() + */ +#ifndef _di_fl_string_dynamic_partial_append_ + extern f_return_status fl_string_dynamic_partial_append(const f_string_dynamic source, const f_string_location offset, f_string_dynamic *destination); +#endif // _di_fl_string_dynamic_partial_append_ + +/** * Append the source string onto the destination with the glue in between. * * If the destination string is empty, then no glue is appended. @@ -264,6 +337,62 @@ extern "C" { #endif // _di_fl_string_dynamic_partial_mash_ /** + * Prepend the source string onto the destination. + * + * Prepend operations require memory move operations and are therefore likely more expensive than append operations. + * + * @param source + * The source string to prepend. + * @param offset + * A range within the source to restrict the prepend from. + * @param destination + * The destination string the source is prepended onto. + * + * @return + * f_none on success. + * f_string_max_size (with error bit) if the combined string is too large. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_allocation (with error bit) on memory allocation error. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see fl_string_append() + * @see fl_string_prepend() + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_prepend() + * @see fl_string_dynamic_partial_append() + */ +#ifndef _di_fl_string_dynamic_partial_append_ + extern f_return_status fl_string_dynamic_partial_prepend(const f_string_dynamic source, const f_string_location offset, f_string_dynamic *destination); +#endif // _di_fl_string_dynamic_partial_append_ + +/** + * Prepend the source string onto the destination. + * + * Prepend operations require memory move operations and are therefore likely more expensive than append operations. + * + * @param source + * The source string to prepend. + * @param destination + * The destination string the source is prepended onto. + * + * @return + * f_none on success. + * f_string_max_size (with error bit) if the combined string is too large. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_allocation (with error bit) on memory allocation error. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see fl_string_append() + * @see fl_string_prepend() + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_partial_append() + * @see fl_string_dynamic_partial_prepend() + */ +#ifndef _di_fl_string_dynamic_prepend_ + extern f_return_status fl_string_dynamic_prepend(const f_string_dynamic source, f_string_dynamic *destination); +#endif // _di_fl_string_dynamic_prepend_ + +/** * Allocate a new string from the provided range in the buffer. * * @param buffer @@ -513,6 +642,35 @@ extern "C" { #endif // _di_fl_string_mash_ /** + * Prepend the source string onto the destination. + * + * Prepend operations require memory move operations and are therefore likely more expensive than append operations. + * + * @param source + * The source string to prepend. + * @param source_length + * Total number of bytes to copy from source string. + * @param destination + * The destination string the source is prepended onto. + * + * @return + * f_none on success. + * f_string_max_size (with error bit) if the combined string is too large. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_allocation (with error bit) on memory allocation error. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see fl_string_append() + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_prepend() + * @see fl_string_dynamic_partial_append() + * @see fl_string_dynamic_partial_prepend() + */ +#ifndef _di_fl_string_prepend_ + extern f_return_status fl_string_prepend(const f_string source, const f_string_length source_length, f_string_dynamic *destination); +#endif // _di_fl_string_prepend_ + +/** * Allocate a new string from the provided range in the string. * * @param string -- 1.8.3.1