From 5c50eca67c2b137d5b54f3b50e746af32804de4b Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 18 Jul 2020 00:08:58 -0500 Subject: [PATCH] Feature: add f_conversion_number_signed_to_string() and f_conversion_number_unsigned_to_string() These functions handle converting a number to a string representation of that number. The base units 2 through 16 are supported. --- level_0/f_conversion/c/conversion.c | 224 ++++++++++++++++++++++++++++++++++++ level_0/f_conversion/c/conversion.h | 46 ++++++++ 2 files changed, 270 insertions(+) diff --git a/level_0/f_conversion/c/conversion.c b/level_0/f_conversion/c/conversion.c index a36a388..8d1d72e 100644 --- a/level_0/f_conversion/c/conversion.c +++ b/level_0/f_conversion/c/conversion.c @@ -204,6 +204,230 @@ extern "C" { } #endif // _di_f_conversion_character_to_octal_ +#ifndef _di_f_conversion_number_signed_to_string_ + f_return_status f_conversion_number_signed_to_string(const f_number_signed number, const uint8_t base, f_string_dynamic *destination) { + #ifndef _di_level_0_parameter_checking_ + if (destination == 0) return F_status_set_error(F_parameter); + if (base < 2 || base > 16) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + f_status status = F_none; + + if (number == 0) { + f_macro_string_dynamic_resize(status, (*destination), destination->used + 2); + if (F_status_is_error(status)) return status; + + destination->string[destination->used] = '0'; + destination->string[destination->used + 1] = 0; + destination->used += 2; + + return F_none; + } + + bool negative = F_false; + f_number_unsigned current = number; + + if (number < 0) { + current = 0 - number; + negative = F_true; + } + + f_string_length total = 0; + + for (register f_number_signed work = current; work; total++) { + work /= base; + } // for + + if (negative) { + f_macro_string_dynamic_resize(status, (*destination), destination->used + total + 2); + } + else { + f_macro_string_dynamic_resize(status, (*destination), destination->used + total + 1); + } + + if (F_status_is_error(status)) return status; + + f_number_unsigned work = 0; + f_number_unsigned power = 1; + + if (negative) { + destination->string[destination->used] = '-'; + destination->used++; + } + + for (register uint8_t i = 1; i < total; i++) { + power *= base; + } // for + + for (; power; total--) { + work = current / power; + current -= work * power; + power /= base; + + switch (work) { + case 0: + destination->string[destination->used] = '0'; + break; + case 1: + destination->string[destination->used] = '1'; + break; + case 2: + destination->string[destination->used] = '2'; + break; + case 3: + destination->string[destination->used] = '3'; + break; + case 4: + destination->string[destination->used] = '4'; + break; + case 5: + destination->string[destination->used] = '5'; + break; + case 6: + destination->string[destination->used] = '6'; + break; + case 7: + destination->string[destination->used] = '7'; + break; + case 8: + destination->string[destination->used] = '8'; + break; + case 9: + destination->string[destination->used] = '9'; + break; + case 10: + destination->string[destination->used] = 'a'; + break; + case 11: + destination->string[destination->used] = 'b'; + break; + case 12: + destination->string[destination->used] = 'c'; + break; + case 13: + destination->string[destination->used] = 'd'; + break; + case 14: + destination->string[destination->used] = 'e'; + break; + case 15: + destination->string[destination->used] = 'f'; + break; + } + + destination->used++; + } // for + + destination->string[destination->used] = 0; + destination->used++; + + return F_none; + } +#endif // _di_f_conversion_decimal_signed_to_string_ + +#ifndef _di_f_conversion_number_unsigned_to_string_ + f_return_status f_conversion_number_unsigned_to_string(const f_number_unsigned number, const uint8_t base, f_string_dynamic *destination) { + #ifndef _di_level_0_parameter_checking_ + if (destination == 0) return F_status_set_error(F_parameter); + if (base < 2 || base > 16) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + f_status status = F_none; + + if (number == 0) { + f_macro_string_dynamic_resize(status, (*destination), destination->used + 2); + if (F_status_is_error(status)) return status; + + destination->string[destination->used] = '0'; + destination->string[destination->used + 1] = 0; + destination->used += 2; + + return F_none; + } + + f_string_length total = 0; + + for (register f_number_unsigned work = number; work; total++) { + work /= base; + } // for + + f_macro_string_dynamic_resize(status, (*destination), destination->used + total + 1); + if (F_status_is_error(status)) return status; + + f_number_unsigned current = number; + f_number_unsigned work = 0; + f_number_unsigned power = 1; + + for (register uint8_t i = 1; i < total; i++) { + power *= base; + } // for + + for (; power; total--) { + work = current / power; + current -= work * power; + power /= base; + + switch (work) { + case 0: + destination->string[destination->used] = '0'; + break; + case 1: + destination->string[destination->used] = '1'; + break; + case 2: + destination->string[destination->used] = '2'; + break; + case 3: + destination->string[destination->used] = '3'; + break; + case 4: + destination->string[destination->used] = '4'; + break; + case 5: + destination->string[destination->used] = '5'; + break; + case 6: + destination->string[destination->used] = '6'; + break; + case 7: + destination->string[destination->used] = '7'; + break; + case 8: + destination->string[destination->used] = '8'; + break; + case 9: + destination->string[destination->used] = '9'; + break; + case 10: + destination->string[destination->used] = 'a'; + break; + case 11: + destination->string[destination->used] = 'b'; + break; + case 12: + destination->string[destination->used] = 'c'; + break; + case 13: + destination->string[destination->used] = 'd'; + break; + case 14: + destination->string[destination->used] = 'e'; + break; + case 15: + destination->string[destination->used] = 'f'; + break; + } + + destination->used++; + } // for + + destination->string[destination->used] = 0; + destination->used++; + + return F_none; + } +#endif // _di_f_conversion_decimal_unsigned_to_string_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_0/f_conversion/c/conversion.h b/level_0/f_conversion/c/conversion.h index 2688361..ea32d6c 100644 --- a/level_0/f_conversion/c/conversion.h +++ b/level_0/f_conversion/c/conversion.h @@ -243,6 +243,52 @@ extern "C" { extern f_return_status f_conversion_character_to_octal(const int8_t character, f_number_unsigned *number); #endif // _di_f_conversion_character_to_octal_ +/** + * Convert a signed number into the decimal digit string that it represents. + * + * The generated number is appended to the destination string. + * + * This only supports the following base units: 2 through 16. + * + * @param number + * The number to convert. + * @param base + * The base unit, usually 10. + * @param destination + * The destination the converted string is saved into. + * + * @return + * F_none if the number was converted to a string. + * F_parameter (with error bit) if a parameter is invalid. + * F_memory_reallocation (with error bit) on memory reallocation error. + */ +#ifndef _di_f_conversion_number_signed_to_string_ + extern f_return_status f_conversion_number_signed_to_string(const f_number_signed number, const uint8_t base, f_string_dynamic *destination); +#endif // _di_f_conversion_number_signed_to_string_ + +/** + * Convert an unsigned number into the decimal digit string that it represents. + * + * The generated number is appended to the destination string. + * + * This only supports the following base units: 2 through 16. + * + * @param number + * The number to convert. + * @param base + * The base unit, usually 10. + * @param destination + * The destination the converted string is saved into. + * + * @return + * F_none if the number was converted to a string. + * F_parameter (with error bit) if a parameter is invalid. + * F_memory_reallocation (with error bit) on memory reallocation error. + */ +#ifndef _di_f_conversion_number_unsigned_to_string_ + extern f_return_status f_conversion_number_unsigned_to_string(const f_number_unsigned number, const uint8_t base, f_string_dynamic *destination); +#endif // _di_f_conversion_number_unsigned_to_string_ + #ifdef __cplusplus } // extern "C" #endif -- 1.8.3.1