diff --git a/CHANGELOG.md b/CHANGELOG.md index 381505c7..a79d8468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ The git repositories are hosted at the following sites: ### Security ### Added +* Added BACnet library itoa, ltoa, ultoa, dtoa, and utoa ASCII + functions for ease of printing formatted values. (#1157) * Added library specific string-to functions similar to stdlib. Added library specific string-to functions for BACnet primitives. (#1151) diff --git a/src/bacnet/bacdcode.c b/src/bacnet/bacdcode.c index a4daa335..bb8cdba2 100644 --- a/src/bacnet/bacdcode.c +++ b/src/bacnet/bacdcode.c @@ -1466,12 +1466,10 @@ int bacnet_null_context_decode( /** * @brief Reverse the bits of the given byte. - * * @param in_byte Byte to reverse. - * * @return Byte with reversed bit order. */ -static uint8_t byte_reverse_bits(uint8_t in_byte) +uint8_t bacnet_byte_reverse_bits(uint8_t in_byte) { uint8_t out_byte = 0; @@ -1534,7 +1532,8 @@ int decode_bitstring( /* Copy the bytes in reversed bit order. */ for (i = 0; i < bytes_used; i++) { bitstring_set_octet( - bit_string, (uint8_t)i, byte_reverse_bits(apdu[len++])); + bit_string, (uint8_t)i, + bacnet_byte_reverse_bits(apdu[len++])); } /* Erase the remaining unused bits. */ unused_bits = (uint8_t)(apdu[0] & 0x07); @@ -1581,7 +1580,7 @@ int bacnet_bitstring_decode( /* Copy the bytes in reversed bit order. */ for (i = 0; i < bytes_used; i++) { bitstring_set_octet( - value, (uint8_t)i, byte_reverse_bits(apdu[len])); + value, (uint8_t)i, bacnet_byte_reverse_bits(apdu[len])); len++; } /* Erase the remaining unused bits. */ @@ -1775,7 +1774,8 @@ int encode_bitstring(uint8_t *apdu, const BACNET_BIT_STRING *bit_string) len++; for (i = 0; i < used_bytes; i++) { if (apdu) { - apdu[len] = byte_reverse_bits(bitstring_octet(bit_string, i)); + apdu[len] = + bacnet_byte_reverse_bits(bitstring_octet(bit_string, i)); } len++; } diff --git a/src/bacnet/bacdcode.h b/src/bacnet/bacdcode.h index 5a5da8e4..27d7fd35 100644 --- a/src/bacnet/bacdcode.h +++ b/src/bacnet/bacdcode.h @@ -242,6 +242,8 @@ int bacnet_bitstring_decode( uint32_t apdu_len_max, uint32_t len_value, BACNET_BIT_STRING *value); +BACNET_STACK_EXPORT +uint8_t bacnet_byte_reverse_bits(uint8_t in_byte); BACNET_STACK_EXPORT int bacnet_bitstring_application_encode( diff --git a/src/bacnet/bacstr.c b/src/bacnet/bacstr.c index e5f9aef0..c9c78c65 100644 --- a/src/bacnet/bacstr.c +++ b/src/bacnet/bacstr.c @@ -1775,3 +1775,85 @@ bool bacnet_string_to_unsigned( return true; } + +/** + * @brief General purpose print formatter which returns the formatted string + * @param buffer - destination string + * @param count - length of the destination string + * @param format - format string + * @return character string buffer + */ +char * +bacnet_sprintf_to_ascii(char *buffer, size_t size, const char *format, ...) +{ + va_list args; + + va_start(args, format); + /* The vsnprintf function always writes a null terminator, + even if it truncates the output. */ + (void)vsnprintf(buffer, size, format, args); + va_end(args); + + return buffer; +} + +/** + * @brief Convert a value into a string and return the base-10 string + * @param value Number to be converted. + * @param buffer Buffer that holds the result of the conversion. + * @param size Length of the buffer in units of the character type. + * @param precision Number of decimal places + * @return character string buffer + */ +char *bacnet_dtoa(double value, char *buffer, size_t size, unsigned precision) +{ + return bacnet_sprintf_to_ascii(buffer, size, "%.*f", precision, value); +} + +/** + * @brief Convert a value into a string and return the base-10 string + * @param value Number to be converted. + * @param buffer Buffer that holds the result of the conversion. + * @param size Length of the buffer in units of the character type. + * @return character string buffer + */ +char *bacnet_itoa(int value, char *buffer, size_t size) +{ + return bacnet_sprintf_to_ascii(buffer, size, "%d", value); +} + +/** + * @brief Convert a value into a string and return the base-10 string + * @param value Number to be converted. + * @param buffer Buffer that holds the result of the conversion. + * @param size Length of the buffer in units of the character type. + * @return character string buffer + */ +char *bacnet_ltoa(long value, char *buffer, size_t size) +{ + return bacnet_sprintf_to_ascii(buffer, size, "%ld", value); +} + +/** + * @brief Convert a value into a string and return the base-10 string + * @param value Number to be converted. + * @param buffer Buffer that holds the result of the conversion. + * @param size Length of the buffer in units of the character type. + * @return character string buffer + */ +char *bacnet_utoa(unsigned value, char *buffer, size_t size) +{ + return bacnet_sprintf_to_ascii(buffer, size, "%u", value); +} + +/** + * @brief Convert a value into a string and return the base-10 string + * @param value Number to be converted. + * @param buffer Buffer that holds the result of the conversion. + * @param size Length of the buffer in units of the character type. + * @return character string buffer + */ +char *bacnet_ultoa(unsigned long value, char *buffer, size_t size) +{ + return bacnet_sprintf_to_ascii(buffer, size, "%lu", value); +} diff --git a/src/bacnet/bacstr.h b/src/bacnet/bacstr.h index 9888be8c..2153cc1f 100644 --- a/src/bacnet/bacstr.h +++ b/src/bacnet/bacstr.h @@ -205,6 +205,20 @@ BACNET_STACK_EXPORT bool bacnet_string_to_unsigned( const char *str, BACNET_UNSIGNED_INTEGER *unsigned_int); +BACNET_STACK_EXPORT +char *bacnet_dtoa(double value, char *buffer, size_t size, unsigned precision); +BACNET_STACK_EXPORT +char *bacnet_itoa(int value, char *buffer, size_t size); +BACNET_STACK_EXPORT +char *bacnet_ltoa(long value, char *buffer, size_t size); +BACNET_STACK_EXPORT +char *bacnet_utoa(unsigned value, char *buffer, size_t size); +BACNET_STACK_EXPORT +char *bacnet_ultoa(unsigned long value, char *buffer, size_t size); +BACNET_STACK_EXPORT +char * +bacnet_sprintf_to_ascii(char *buffer, size_t count, const char *format, ...); + #ifdef __cplusplus } #endif /* __cplusplus */