diff options
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | include/BH/String.h | 205 | ||||
| -rw-r--r-- | src/String/Core.c | 21 | ||||
| -rw-r--r-- | src/String/Float.c | 244 | ||||
| -rw-r--r-- | src/String/FromInt.inl | 34 | ||||
| -rw-r--r-- | src/String/Int.c | 130 | ||||
| -rw-r--r-- | src/String/ToIntS.inl | 37 | ||||
| -rw-r--r-- | src/String/ToIntU.inl | 23 | ||||
| -rw-r--r-- | test/src/TestFloat.c | 23 | ||||
| -rw-r--r-- | test/src/TestInt.c | 78 |
10 files changed, 466 insertions, 331 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 94399fb..abecdf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,7 +94,6 @@ set(BH_SOURCE src/Util.c src/String/Int.c src/String/Float.c - src/String/Core.c ) set(BH_HEADER @@ -107,7 +106,6 @@ set(BH_HEADER include/BH/Queue.h include/BH/Util.h include/BH/Thread.h - include ) set(BH_SOURCE_DUMMY diff --git a/include/BH/String.h b/include/BH/String.h index 0ce62c4..1484889 100644 --- a/include/BH/String.h +++ b/include/BH/String.h @@ -6,27 +6,9 @@ /** - * Frees dynamically allocated \a string. - * - * \param string String pointer - */ -void BH_StringFree(char *string); - - -/** - * Creates a copy of the input \a string. - * - * \param string String pointer - * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. - */ -char *BH_StringCopy(const char *string); - - -/** - * Formats a double \a value into a string using the provided \a format and - * \a precision. + * Formats a double \a value into a zero terminated \a string (limited by + * \a size) using the provided \a format and \a precision and stores \a actual + * length (if it's provided). * * Formats supported: * - Scientific or fixed format ('g' or 'G') @@ -38,134 +20,197 @@ char *BH_StringCopy(const char *string); * * This function follows IEEE 754 round to even to break ties during rounding. * + * \param string String + * \param size String size * \param value Value * \param format Format * \param precision Precision + * \param actual Written size (optional) * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns zero. + * \return On failure, returns error code. */ -char *BH_StringFromDouble(double value, - char format, - int precision); +int BH_StringFromDouble(char *string, + size_t size, + double value, + char format, + int precision, + size_t *actual); /** - * Reads \a string containing double value in fixed or scientific format, - * optionally reports \a size amount of characters consumed and returns - * the result value. + * Formats signed 8-bit \a value into a \a string (limited by \a size) with + * provided \a base and stores \a actual length (if it's provided). * * \param string String - * \param size Optional size + * \param size String size + * \param value Value + * \param base Base + * \param actual Written size (optional) * - * \return On success, returns parsed double value. - * \return On failure, returns zero. + * \return On success, returns zero. + * \return On failure, returns error code. */ -double BH_StringToDouble(const char *string, - size_t *size); +int BH_StringFromInt8s(char *string, + size_t size, + int8_t value, + int base, + size_t *actual); /** - * Formats signed 8bit \a value into string with the specified \a base. + * Formats signed 16-bit \a value into a \a string (limited by \a size) with + * provided \a base and stores \a actual length (if it's provided). * + * \param string String + * \param size String size * \param value Value * \param base Base + * \param actual Written size (optional) * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns zero. + * \return On failure, returns error code. */ -char *BH_StringFromInt8s(int8_t value, - int base); +int BH_StringFromInt16s(char *string, + size_t size, + int16_t value, + int base, + size_t *actual); /** - * Formats signed 16bit \a value into string with the specified \a base. + * Formats signed 32-bit \a value into a \a string (limited by \a size) with + * provided \a base and stores \a actual length (if it's provided). * + * \param string String + * \param size String size * \param value Value * \param base Base + * \param actual Written size (optional) * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns zero. + * \return On failure, returns error code. */ -char *BH_StringFromInt16s(int16_t value, - int base); +int BH_StringFromInt32s(char *string, + size_t size, + int32_t value, + int base, + size_t *actual); /** - * Formats signed 32bit \a value into string with the specified \a base. + * Formats signed 64-bit \a value into a \a string (limited by \a size) with + * provided \a base and stores \a actual length (if it's provided). * + * \param string String + * \param size String size * \param value Value * \param base Base + * \param actual Written size (optional) * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns zero. + * \return On failure, returns error code. */ -char *BH_StringFromInt32s(int32_t value, - int base); +int BH_StringFromInt64s(char *string, + size_t size, + int64_t value, + int base, + size_t *actual); + /** - * Formats signed 64bit \a value into string with the specified \a base. + * Formats unsigned 8-bit \a value into a \a string (limited by \a size) with + * provides \a base and stores \a actual length (if it's provided). * + * \param string String + * \param size String size * \param value Value * \param base Base + * \param actual Written size (optional) * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns zero. + * \return On failure, returns error code. */ -char *BH_StringFromInt64s(int64_t value, - int base); +int BH_StringFromInt8u(char *string, + size_t size, + uint8_t value, + int base, + size_t *actual); /** - * Formats unsigned 8bit \a value into string with the specified \a base. + * Formats unsigned 16-bit \a value into a \a string (limited by \a size) with + * provides \a base and stores \a actual length (if it's provided). * + * \param string String + * \param size String size * \param value Value * \param base Base + * \param actual Written size (optional) * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns zero. + * \return On failure, returns error code. */ -char *BH_StringFromInt8u(uint8_t value, - int base); +int BH_StringFromInt16u(char *string, + size_t size, + uint16_t value, + int base, + size_t *actual); /** - * Formats unsigned 16bit \a value into string with the specified \a base. + * Formats unsigned 32-bit \a value into a \a string (limited by \a size) with + * provided \a base and stores \a actual length (if it's provided). * + * \param string String + * \param size String size * \param value Value * \param base Base + * \param actual Written size (optional) * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns zero. + * \return On failure, returns error code. */ -char *BH_StringFromInt16u(uint16_t value, - int base); +int BH_StringFromInt32u(char *string, + size_t size, + uint32_t value, + int base, + size_t *actual); /** - * Formats unsigned 32bit \a value into string with the specified \a base. + * Formats unsigned 64-bit \a value into a \a string (limited by \a size) with + * provided \a base and stores \a actual length (if it's provided). * + * \param string String + * \param size String size * \param value Value * \param base Base + * \param actual Written size (optional) * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns zero. + * \return On failure, returns error code. */ -char *BH_StringFromInt32u(uint32_t value, - int base); +int BH_StringFromInt64u(char *string, + size_t size, + uint64_t value, + int base, + size_t *actual); /** - * Formats unsigned 64bit \a value into string with the specified \a base. + * Reads \a string containing double value in fixed or scientific format, + * optionally reports \a size amount of characters consumed and returns + * the result value. * - * \param value Value - * \param base Base + * \param string String + * \param size Optional size * - * \return On success, returns new string pointer. - * \return On failure, returns NULL pointer. + * \return On success, returns parsed double value. + * \return On failure, returns zero. */ -char *BH_StringFromInt64u(uint64_t value, - int base); +double BH_StringToDouble(const char *string, + size_t *size); /** @@ -173,6 +218,7 @@ char *BH_StringFromInt64u(uint64_t value, * \a size amount of characters consumed and returns the result value. * * If base is 0, function will automaticly detect input base by the prefix: + * - Base 2 if prefix is 0b * - Base 8 if prefix is 0 * - Base 16 if prefix is 0x * - Base 10 in other cases @@ -194,6 +240,7 @@ int8_t BH_StringToInt8s(const char *string, * \a size amount of characters consumed and returns the result value. * * If base is 0, function will automaticly detect input base by the prefix: + * - Base 2 if prefix is 0b * - Base 8 if prefix is 0 * - Base 16 if prefix is 0x * - Base 10 in other cases @@ -215,6 +262,7 @@ int16_t BH_StringToInt16s(const char *string, * \a size amount of characters consumed and returns the result value. * * If base is 0, function will automaticly detect input base by the prefix: + * - Base 2 if prefix is 0b * - Base 8 if prefix is 0 * - Base 16 if prefix is 0x * - Base 10 in other cases @@ -236,6 +284,7 @@ int32_t BH_StringToInt32s(const char *string, * \a size amount of characters consumed and returns the result value. * * If base is 0, function will automaticly detect input base by the prefix: + * - Base 2 if prefix is 0b * - Base 8 if prefix is 0 * - Base 16 if prefix is 0x * - Base 10 in other cases @@ -257,6 +306,7 @@ int64_t BH_StringToInt64s(const char *string, * \a size amount of characters consumed and returns the result value. * * If base is 0, function will automaticly detect input base by the prefix: + * - Base 2 if prefix is 0b * - Base 8 if prefix is 0 * - Base 16 if prefix is 0x * - Base 10 in other cases @@ -278,6 +328,7 @@ uint8_t BH_StringToInt8u(const char *string, * \a size amount of characters consumed and returns the result value. * * If base is 0, function will automaticly detect input base by the prefix: + * - Base 2 if prefix is 0b * - Base 8 if prefix is 0 * - Base 16 if prefix is 0x * - Base 10 in other cases @@ -299,6 +350,7 @@ uint16_t BH_StringToInt16u(const char *string, * \a size amount of characters consumed and returns the result value. * * If base is 0, function will automaticly detect input base by the prefix: + * - Base 2 if prefix is 0b * - Base 8 if prefix is 0 * - Base 16 if prefix is 0x * - Base 10 in other cases @@ -320,6 +372,7 @@ uint32_t BH_StringToInt32u(const char *string, * \a size amount of characters consumed and returns the result value. * * If base is 0, function will automaticly detect input base by the prefix: + * - Base 2 if prefix is 0b * - Base 8 if prefix is 0 * - Base 16 if prefix is 0x * - Base 10 in other cases diff --git a/src/String/Core.c b/src/String/Core.c deleted file mode 100644 index 85bc7d1..0000000 --- a/src/String/Core.c +++ /dev/null @@ -1,21 +0,0 @@ -#include <BH/String.h> -#include <stdlib.h> -#include <string.h> - - -void BH_StringFree(char *string) -{ - free(string); -} - - -char *BH_StringCopy(const char *string) -{ - char *result; - - result = malloc(strlen(string) + 1); - if (result) - strcpy(result, string); - - return result; -} diff --git a/src/String/Float.c b/src/String/Float.c index 829e105..9c4e98c 100644 --- a/src/String/Float.c +++ b/src/String/Float.c @@ -22,6 +22,13 @@ #define RELATIVE 2 +struct Buffer +{ + char *data; + size_t size; +}; + + struct DragonState { BInt r; @@ -100,9 +107,8 @@ static void dragonFixup(struct DragonState *state, static void dragonRound(struct DragonState *state, - char *buffer, + struct Buffer *buffer, int *k, - int *size, int high, int low, char s) @@ -110,7 +116,7 @@ static void dragonRound(struct DragonState *state, int i; /* Preconditions */ - assert(state != NULL && buffer != NULL && k != NULL && size != NULL); + assert(state != NULL && buffer != NULL && k != NULL); assert(s >= '0' && s <= '9'); /* Check if rounding up required */ @@ -126,14 +132,14 @@ static void dragonRound(struct DragonState *state, /* Perform rounding up */ if (!low) { - for (i = *size; i && buffer[i - 1] == '9'; i--) - buffer[i - 1] = '0'; + for (i = buffer->size; i && buffer->data[i - 1] == '9'; i--) + buffer->data[i - 1] = '0'; if (i > 0) - buffer[i - 1]++; + buffer->data[i - 1]++; else { - buffer[0] = '1'; + buffer->data[0] = '1'; (*k)++; } } @@ -143,8 +149,7 @@ static void dragonRound(struct DragonState *state, static void dragon(double value, int precision, int mode, - char *buffer, - int *size, + struct Buffer *buffer, int *k) { struct DragonState state; @@ -153,17 +158,17 @@ static void dragon(double value, char s; /* Preconditions */ - assert(buffer != NULL && size != NULL && k != NULL); + assert(buffer != NULL && k != NULL); assert(mode == NORMAL || mode == ABSOLUTE || mode == RELATIVE); assert(precision >= 0); *k = 0; - *size = low = high = 0; + buffer->size = low = high = 0; /* If value is zero - do nothing */ if (!value) { - buffer[(*size)++] = '0'; + buffer->data[buffer->size++] = '0'; return; } @@ -199,7 +204,7 @@ static void dragon(double value, s = '0'; if (state.tmp[0].size) s += state.tmp[0].data[0]; - buffer[(*size)++] = s; + buffer->data[buffer->size++] = s; if (mode == NORMAL) { @@ -210,38 +215,40 @@ static void dragon(double value, BIntAdd(&state.tmp[1], &state.mp, &state.tmp[3]); low = BIntCompare(&state.tmp[1], &state.mm) < 0; high = BIntCompare(&state.tmp[3], &state.tmp[2]) > 0; - if (low || high || state.k == state.cutoff || *size >= BUFSIZE) + if (low || high || state.k == state.cutoff || buffer->size >= BUFSIZE) break; } else { - if (!state.r.size || state.k == state.cutoff || *size >= BUFSIZE) + if (!state.r.size || state.k == state.cutoff || buffer->size >= BUFSIZE) break; } } /* Round digits if required */ - dragonRound(&state, buffer, k, size, high, low, s); + dragonRound(&state, buffer, k, high, low, s); } -static char *formatF(char *buffer, - int precision, - int sign, - int k, - int size) +static int formatF(struct Buffer *output, + struct Buffer *input, + int precision, + int sign, + int k, + size_t *actual) { - char *result, *current; + char *current; int i; /* Preconditions */ - assert(buffer != NULL); - assert(size < BUFSIZE); + assert(output != NULL && input != NULL); + assert(input->size < BUFSIZE); + assert(sign == 0 || sign == 1); - result = malloc(MAX(0, k) + 5 + sign + precision); - current = result; - if (!result) - return NULL; + /* Check that output buffer has enough space */ + current = output->data; + if (output->size < (size_t)(MAX(0, k) + 4 + precision)) + return BH_ERROR; /* Add sign */ if (sign) @@ -262,8 +269,8 @@ static char *formatF(char *buffer, /* Add digits */ for (i = 0; k >= -precision; i++, k--) { - if (i < size) - *(current++) = buffer[i]; + if (i < (int)input->size) + *(current++) = input->data[i]; else *(current++) = '0'; @@ -272,38 +279,41 @@ static char *formatF(char *buffer, } *(current++) = 0; - return result; + if (actual) + *actual = current - output->data; + + return BH_OK; } -static char *formatE(char *buffer, - int precision, - int sign, - int k, - int size, - int upper) +static int formatE(struct Buffer *output, + struct Buffer *input, + int precision, + int sign, + int k, + int upper, + size_t *actual) { - char *result, *current; + char *current; int i; /* Preconditions */ - assert(buffer != NULL); - assert(size < BUFSIZE); + assert(input != NULL && output != NULL); + assert(input->size < BUFSIZE); assert(sign == 0 || sign == 1); assert(upper == 0 || upper == 1); - result = malloc(9 + sign + precision); - current = result; - if (!result) - return NULL; + current = output->data; + if (output->size < (size_t)(9 + precision)) + return BH_ERROR; /* Add sign and digits */ if (sign) *(current++) = '-'; - for (i = 0; i < size; i++) + for (i = 0; i < (int)input->size; i++) { - *(current++) = buffer[i]; + *(current++) = input->data[i]; if (i == 0 && precision > 0) *(current++) = '.'; } @@ -323,106 +333,137 @@ static char *formatE(char *buffer, *(current++) = '+'; /* Convert exponent to digits and add them */ - for (size = 0; k || size < 2; size++) + for (i = 0; k || i < 2; i++) { - buffer[size] = '0' + k % 10; + input->data[i] = '0' + k % 10; k = k / 10; } - for (; size; size--) - *(current++) = buffer[size - 1]; + for (; i; i--) + *(current++) = input->data[i - 1]; - *(current++) = 0; - return result; + *(current++) = 0; + if (actual) + *actual = current - output->data; + + return BH_OK; } -static char *generateF(double value, - int precision, - int sign) +static int generateF(struct Buffer *output, + double value, + int precision, + int sign, + size_t *actual) { char buffer[BUFSIZE]; - int size, k; + struct Buffer input; + int k; + + input.data = buffer; + input.size = 0; /* Call Dragon4 and format the digits */ if (precision < 0) - dragon(value, 0, NORMAL, buffer, &size, &k); + dragon(value, 0, NORMAL, &input, &k); else - dragon(value, precision, ABSOLUTE, buffer, &size, &k); + dragon(value, precision, ABSOLUTE, &input, &k); if (precision < 0) - precision = MAX(0, size - k - 1); + precision = MAX(0, (int)input.size - k - 1); - return formatF(buffer, precision, sign, k, size); + return formatF(output, &input, precision, sign, k, actual); } -static char *generateE(double value, - int precision, - int upper, - int sign) +static int generateE(struct Buffer *output, + double value, + int precision, + int upper, + int sign, + size_t *actual) { char buffer[BUFSIZE]; - int size, k; + struct Buffer input; + int k; + + input.data = buffer; + input.size = 0; /* Adjust precision and call Dragon4 to generate digits */ if (precision < 0) - dragon(value, 0, NORMAL, buffer, &size, &k); + dragon(value, 0, NORMAL, &input, &k); else - dragon(value, (precision + 1), RELATIVE, buffer, &size, &k); + dragon(value, (precision + 1), RELATIVE, &input, &k); if (precision < 0) - precision = size - 1; + precision = input.size - 1; - return formatE(buffer, precision, sign, k, size, upper); + return formatE(output, &input, precision, sign, k, upper, actual); } -static char *generateG(double value, - int precision, - int upper, - int sign) +static int generateG(struct Buffer *output, + double value, + int precision, + int upper, + int sign, + size_t *actual) { char buffer[BUFSIZE]; - int size, k, fixed; + struct Buffer input; + int k, fixed; + input.data = buffer; + input.size = 0; if (precision == 0) precision = 1; /* Call Dragon4 to generate digits */ if (precision < 0) { - dragon(value, 0, NORMAL, buffer, &size, &k); - fixed = k >= -4 && k <= (size - 1); + dragon(value, 0, NORMAL, &input, &k); + fixed = k >= -4 && k <= (int)(input.size - 1); } else { - dragon(value, precision, RELATIVE, buffer, &size, &k); + dragon(value, precision, RELATIVE, &input, &k); fixed = k >= -4 && k < precision; /* Remove trailing zeros and adjust precision */ - for (; size && precision > 0 && buffer[size - 1] == '0'; size--, precision--); + for (; input.size && precision > 0 && buffer[input.size - 1] == '0'; input.size--, precision--); } if (fixed) { - precision = MAX(0, size - k - 1); - return formatF(buffer, precision, sign, k, size); + precision = MAX(0, (int)input.size - k - 1); + return formatF(output, &input, precision, sign, k, actual); } else { - precision = MAX(0, size - 1); - return formatE(buffer, precision, sign, k, size, upper); + precision = MAX(0, (int)input.size - 1); + return formatE(output, &input, precision, sign, k, upper, actual); } } -char *BH_StringFromDouble(double value, - char format, - int precision) +int BH_StringFromDouble(char *string, + size_t size, + double value, + char format, + int precision, + size_t *actual) { static const char *infStrings[] = { "inf", "-inf", "INF", "-INF" }; static const char *nanStrings[] = { "nan", "NAN" }; int sign, type, upper; + struct Buffer output; + + output.data = string; + output.size = size; + + /* Buffer is less then 5 characters */ + if (size < 5) + return BH_ERROR; type = BH_ClassifyDouble(value); upper = isupper(format) > 0; @@ -433,16 +474,27 @@ char *BH_StringFromDouble(double value, /* Handle NaN and Inf */ if (type == BH_FP_INFINITE) - return BH_StringCopy(infStrings[upper * 2 + sign]); + { + memcpy(string, infStrings[upper * 2 + sign], 4 + sign); + if (actual) + *actual = 4 + sign; + return BH_OK; + } else if (type == BH_FP_NAN) - return BH_StringCopy(nanStrings[upper]); + { + memcpy(string, nanStrings[upper], 4); + if (actual) + *actual = 4; + return BH_OK; + } + /* Do the formating */ if (format == 'g' || format == 'G') - return generateG(value, precision, upper, sign); + return generateG(&output, value, precision, upper, sign, actual); else if (format == 'e' || format == 'E') - return generateE(value, precision, upper, sign); + return generateE(&output, value, precision, upper, sign, actual); else - return generateF(value, precision, sign); + return generateF(&output, value, precision, sign, actual); } @@ -593,16 +645,8 @@ double BH_StringToDouble(const char *string, return 0.0; } - /* Handle zero input */ - if (count == 0) - { - if (sign) - return -0.0; - return 0.0; - } - - /* Exponent too low */ - if (e < -329) + /* Zero or exponent too low */ + if (!count || e < -329) { if (sign) return -0.0; diff --git a/src/String/FromInt.inl b/src/String/FromInt.inl new file mode 100644 index 0000000..57eaee0 --- /dev/null +++ b/src/String/FromInt.inl @@ -0,0 +1,34 @@ +int sign, flag = 0; +signed char sym; + +/* Check for valid base and zero out read size */ +result = 0; +if (size) + *size = 0; +if (base != 0 && (base < 2 || base > 36)) + return 0; + +/* Handle space, sign and base */ +skipSpace(&string, size); +handleSign(&string, size, &sign); +guessBase(&string, size, &base); + +/* Read digits */ +while(*string) +{ + sym = *(string++); + sym = lookup[(unsigned int)sym]; + if (sym >= base || sym == -1) + break; + + if (size) + (*size)++; + result = result * base + sym; + flag = 1; +} + +/* Zero out size on error */ +if (!result && !flag && size) + *size = 0; + +return result * sign; diff --git a/src/String/Int.c b/src/String/Int.c index f15e9a3..18e62ae 100644 --- a/src/String/Int.c +++ b/src/String/Int.c @@ -80,98 +80,92 @@ static void guessBase(const char **string, } -#define TEMPLATE_IMPL \ - char tmp[sizeof(value) * CHAR_BIT + 1]; char *current, *end, *result; \ - int sign; end = tmp + sizeof(tmp); current = end; sign = 0; \ - if (value < 0) { sign = 1; value = -value; } while (value) { \ - *(--current) = digits[value % base]; value /= base; } \ - if (sign) { *(--current) = '-'; } result = malloc(end - current + 1); \ - if (!result) { return NULL; } memcpy(result, current, end - current); \ - result[end - current] = 0; return result; - - -char *BH_StringFromInt8s(int8_t value, - int base) +int BH_StringFromInt8s(char *string, + size_t size, + int8_t value, + int base, + size_t *actual) { - TEMPLATE_IMPL + #include "ToIntS.inl" } -char *BH_StringFromInt16s(int16_t value, - int base) +int BH_StringFromInt16s(char *string, + size_t size, + int16_t value, + int base, + size_t *actual) { - TEMPLATE_IMPL + #include "ToIntS.inl" } -char *BH_StringFromInt32s(int32_t value, - int base) +int BH_StringFromInt32s(char *string, + size_t size, + int32_t value, + int base, + size_t *actual) { - TEMPLATE_IMPL + #include "ToIntS.inl" } -char *BH_StringFromInt64s(int64_t value, - int base) +int BH_StringFromInt64s(char *string, + size_t size, + int64_t value, + int base, + size_t *actual) { - TEMPLATE_IMPL + #include "ToIntS.inl" } -#undef TEMPLATE_IMPL -#define TEMPLATE_IMPL \ - char tmp[sizeof(value) * CHAR_BIT]; char *current, *end, *result; \ - end = tmp + sizeof(tmp); current = end; while (value) { \ - *(--current) = digits[value % base]; value /= base; } \ - result = malloc(end - current + 1); if (!result) { return NULL; } \ - memcpy(result, current, end - current); result[end - current] = 0; \ - return result; - - -char *BH_StringFromInt8u(uint8_t value, - int base) +int BH_StringFromInt8u(char *string, + size_t size, + uint8_t value, + int base, + size_t *actual) { - TEMPLATE_IMPL + #include "ToIntU.inl" } -char *BH_StringFromInt16u(uint16_t value, - int base) +int BH_StringFromInt16u(char *string, + size_t size, + uint16_t value, + int base, + size_t *actual) { - TEMPLATE_IMPL + #include "ToIntU.inl" } -char *BH_StringFromInt32u(uint32_t value, - int base) +int BH_StringFromInt32u(char *string, + size_t size, + uint32_t value, + int base, + size_t *actual) { - TEMPLATE_IMPL + #include "ToIntU.inl" } -char *BH_StringFromInt64u(uint64_t value, - int base) +int BH_StringFromInt64u(char *string, + size_t size, + uint64_t value, + int base, + size_t *actual) { - TEMPLATE_IMPL + #include "ToIntU.inl" } -#undef TEMPLATE_IMPL -#define TEMPLATE_IMPL(type) \ - type result = 0; int sign, flag = 0; signed char sym; if (size) *size = 0; \ - if (base != 0 && (base < 2 || base > 36)) { return 0; } \ - skipSpace(&string, size); handleSign(&string, size, &sign); \ - guessBase(&string, size, &base); while(*string) { sym = *(string++); \ - sym = lookup[(unsigned int)sym]; if (sym >= base || sym == -1) { break; } \ - if (size) { (*size)++; } result = result * base + sym; flag = 1; } \ - if (!result && !flag && size) { *size = 0; } return result * sign; - - int8_t BH_StringToInt8s(const char *string, size_t *size, int base) { - TEMPLATE_IMPL(int8_t) + int8_t result; + #include "FromInt.inl" } @@ -179,7 +173,8 @@ int16_t BH_StringToInt16s(const char *string, size_t *size, int base) { - TEMPLATE_IMPL(int16_t) + int16_t result; + #include "FromInt.inl" } @@ -187,7 +182,8 @@ int32_t BH_StringToInt32s(const char *string, size_t *size, int base) { - TEMPLATE_IMPL(int32_t) + int32_t result; + #include "FromInt.inl" } @@ -195,7 +191,8 @@ int64_t BH_StringToInt64s(const char *string, size_t *size, int base) { - TEMPLATE_IMPL(int64_t) + int64_t result; + #include "FromInt.inl" } @@ -203,7 +200,8 @@ uint8_t BH_StringToInt8u(const char *string, size_t *size, int base) { - TEMPLATE_IMPL(uint8_t) + uint8_t result; + #include "FromInt.inl" } @@ -211,7 +209,8 @@ uint16_t BH_StringToInt16u(const char *string, size_t *size, int base) { - TEMPLATE_IMPL(uint16_t) + uint16_t result; + #include "FromInt.inl" } @@ -219,7 +218,8 @@ uint32_t BH_StringToInt32u(const char *string, size_t *size, int base) { - TEMPLATE_IMPL(uint32_t) + uint32_t result; + #include "FromInt.inl" } @@ -227,8 +227,6 @@ uint64_t BH_StringToInt64u(const char *string, size_t *size, int base) { - TEMPLATE_IMPL(uint64_t) + uint64_t result; + #include "FromInt.inl" } - - -#undef TEMPLATE_IMPL diff --git a/src/String/ToIntS.inl b/src/String/ToIntS.inl new file mode 100644 index 0000000..f6ba991 --- /dev/null +++ b/src/String/ToIntS.inl @@ -0,0 +1,37 @@ +char tmp[sizeof(value) * CHAR_BIT + 2]; +char *current, *end; +int sign; + +end = tmp + sizeof(tmp); +current = end; +sign = 0; + +/* Check for sign */ +if (value < 0) +{ + sign = 1; + value = -value; +} + +/* Fill buffer from the end */ +*(--current) = 0; +while (value) +{ + *(--current) = digits[value % base]; + value /= base; +} + +/* Append sign */ +if (sign) + *(--current) = '-'; + +/* Check that string have space for the result */ +if (size < (size_t)(end - current)) + return BH_ERROR; + +/* Copy data */ +memcpy(string, current, end - current); +if (actual) + *actual = end - current; + +return BH_OK; diff --git a/src/String/ToIntU.inl b/src/String/ToIntU.inl new file mode 100644 index 0000000..ff57e84 --- /dev/null +++ b/src/String/ToIntU.inl @@ -0,0 +1,23 @@ +char tmp[sizeof(value) * CHAR_BIT + 1]; +char *current, *end; +end = tmp + sizeof(tmp); +current = end; + +/* Fill buffer from the end */ +*(--current) = 0; +while (value) +{ + *(--current) = digits[value % base]; + value /= base; +} + +/* Check that string have space for the result */ +if (size < (size_t)(end - current)) + return BH_ERROR; + +/* Copy data */ +memcpy(string, current, end - current); +if (actual) + *actual = end - current; + +return BH_OK; diff --git a/test/src/TestFloat.c b/test/src/TestFloat.c index dac6171..309a1c4 100644 --- a/test/src/TestFloat.c +++ b/test/src/TestFloat.c @@ -13,16 +13,14 @@ static int compareString(double value, int precision, const char *ref) { + char str[2000]; int result; - char *str; - str = BH_StringFromDouble(value, format, precision); + BH_VERIFY(BH_StringFromDouble(str, 2000, value, format, precision, NULL) == BH_OK); result = strcmp(str, ref); if (result) printf("Value: %.17g\tReference: %s\tGot: %s\n", value, ref, str); - BH_StringFree(str); - return result; } @@ -31,15 +29,13 @@ static int roundtripString(double value, int format) { double result; - char *str; + char str[2000]; - str = BH_StringFromDouble(value, format, -1); + BH_VERIFY(BH_StringFromDouble(str, 2000, value, format, -1, NULL) == BH_OK); result = BH_StringToDouble(str, NULL); if (result != value) printf("Value: %.17g\tGot: %.17g\tStr: %s\n", value, result, str); - BH_StringFree(str); - return result != value; } @@ -267,7 +263,7 @@ BH_UNIT_TEST(ShortestRoundTrip) BH_UNIT_TEST(Parity) { - char buffer[16], output[2000]; + char buffer[2000], output[2000]; uint64_t frac; double value; int i, j, k; @@ -285,18 +281,15 @@ BH_UNIT_TEST(Parity) for (k = 0; k < 18; k++) { - char *str; - sprintf(buffer, "%%.%dg", k); - str = BH_StringFromDouble(value, 'g', k); sprintf(output, buffer, value); + BH_VERIFY(BH_StringFromDouble(buffer, 2000, value, 'g', k, NULL) == BH_OK); - if (strcmp(str, output)) + if (strcmp(buffer, output)) { - printf("(%.17g) (%d) %s vs %s\n", value, k, str, output); + printf("(%.17g) (%d) %s vs %s\n", value, k, buffer, output); BH_FAIL("Strings aren't equal"); } - BH_StringFree(str); } } } diff --git a/test/src/TestInt.c b/test/src/TestInt.c index 8040b2f..f372d4e 100644 --- a/test/src/TestInt.c +++ b/test/src/TestInt.c @@ -4,48 +4,40 @@ BH_UNIT_TEST(Int8) { - char *str; + char str[9]; size_t size; - BH_VERIFY(str = BH_StringFromInt8s(-13, 16)); + BH_VERIFY(BH_StringFromInt8s(str, 9, -13, 16, NULL) == BH_OK); BH_VERIFY(BH_StringToInt8s(str, &size, 16) == -13); BH_VERIFY(size == 2); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt8s(-13, 10)); + BH_VERIFY(BH_StringFromInt8s(str, 9, -13, 10, NULL) == BH_OK); BH_VERIFY(BH_StringToInt8s(str, &size, 10) == -13); BH_VERIFY(size == 3); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt8s(-13, 8)); + BH_VERIFY(BH_StringFromInt8s(str, 9, -13, 8, NULL) == BH_OK); BH_VERIFY(BH_StringToInt8s(str, &size, 8) == -13); BH_VERIFY(size == 3); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt8s(-13, 2)); + BH_VERIFY(BH_StringFromInt8s(str, 9, -13, 2, NULL) == BH_OK); BH_VERIFY(BH_StringToInt8s(str, &size, 2) == -13); BH_VERIFY(size == 5); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt8u(200, 16)); + BH_VERIFY(BH_StringFromInt8u(str, 9, 200, 16, NULL) == BH_OK); BH_VERIFY(BH_StringToInt8u(str, &size, 16) == 200); BH_VERIFY(size == 2); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt8u(200, 10)); + BH_VERIFY(BH_StringFromInt8u(str, 9, 200, 10, NULL) == BH_OK); BH_VERIFY(BH_StringToInt8u(str, &size, 10) == 200); BH_VERIFY(size == 3); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt8u(200, 8)); + BH_VERIFY(BH_StringFromInt8u(str, 9, 200, 8, NULL) == BH_OK); BH_VERIFY(BH_StringToInt8u(str, &size, 8) == 200); BH_VERIFY(size == 3); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt8u(200, 2)); + BH_VERIFY(BH_StringFromInt8u(str, 9, 200, 2, NULL) == BH_OK); BH_VERIFY(BH_StringToInt8u(str, &size, 2) == 200); BH_VERIFY(size == 8); - BH_StringFree(str); return 0; } @@ -53,48 +45,40 @@ BH_UNIT_TEST(Int8) BH_UNIT_TEST(Int16) { - char *str; + char str[17]; size_t size; - BH_VERIFY(str = BH_StringFromInt16s(-1234, 16)); + BH_VERIFY(BH_StringFromInt16s(str, 17, -1234, 16, NULL) == BH_OK); BH_VERIFY(BH_StringToInt16s(str, &size, 16) == -1234); BH_VERIFY(size == 4); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt16s(-1234, 10)); + BH_VERIFY(BH_StringFromInt16s(str, 17, -1234, 10, NULL) == BH_OK); BH_VERIFY(BH_StringToInt16s(str, &size, 10) == -1234); BH_VERIFY(size == 5); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt16s(-1234, 8)); + BH_VERIFY(BH_StringFromInt16s(str, 17, -1234, 8, NULL) == BH_OK); BH_VERIFY(BH_StringToInt16s(str, &size, 8) == -1234); BH_VERIFY(size == 5); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt16s(-1234, 2)); + BH_VERIFY(BH_StringFromInt16s(str, 17, -1234, 2, NULL) == BH_OK); BH_VERIFY(BH_StringToInt16s(str, &size, 2) == -1234); BH_VERIFY(size == 12); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt16u(43210, 16)); + BH_VERIFY(BH_StringFromInt16u(str, 17, 43210, 16, NULL) == BH_OK); BH_VERIFY(BH_StringToInt16u(str, &size, 16) == 43210); BH_VERIFY(size == 4); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt16u(43210, 10)); + BH_VERIFY(BH_StringFromInt16u(str, 17, 43210, 10, NULL) == BH_OK); BH_VERIFY(BH_StringToInt16u(str, &size, 10) == 43210); BH_VERIFY(size == 5); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt16u(43210, 8)); + BH_VERIFY(BH_StringFromInt16u(str, 17, 43210, 8, NULL) == BH_OK); BH_VERIFY(BH_StringToInt16u(str, &size, 8) == 43210); BH_VERIFY(size == 6); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt16u(43210, 2)); + BH_VERIFY(BH_StringFromInt16u(str, 17, 43210, 2, NULL) == BH_OK); BH_VERIFY(BH_StringToInt16u(str, &size, 2) == 43210); BH_VERIFY(size == 16); - BH_StringFree(str); return 0; } @@ -102,48 +86,40 @@ BH_UNIT_TEST(Int16) BH_UNIT_TEST(Int32) { - char *str; + char str[33]; size_t size; - BH_VERIFY(str = BH_StringFromInt32s(-1234567890l, 16)); + BH_VERIFY(BH_StringFromInt32s(str, 33, -1234567890l, 16, NULL) == BH_OK); BH_VERIFY(BH_StringToInt32s(str, &size, 16) == -1234567890l); BH_VERIFY(size == 9); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt32s(-1234567890l, 10)); + BH_VERIFY(BH_StringFromInt32s(str, 33, -1234567890l, 10, NULL) == BH_OK); BH_VERIFY(BH_StringToInt32s(str, &size, 10) == -1234567890l); BH_VERIFY(size == 11); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt32s(-1234567890l, 8)); + BH_VERIFY(BH_StringFromInt32s(str, 33, -1234567890l, 8, NULL) == BH_OK); BH_VERIFY(BH_StringToInt32s(str, &size, 8) == -1234567890l); BH_VERIFY(size == 12); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt32s(-1234567890l, 2)); + BH_VERIFY(BH_StringFromInt32s(str, 33, -1234567890l, 2, NULL) == BH_OK); BH_VERIFY(BH_StringToInt32s(str, &size, 2) == -1234567890l); BH_VERIFY(size == 32); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt32u(3456789012ul, 16)); + BH_VERIFY(BH_StringFromInt32u(str, 33, 3456789012ul, 16, NULL) == BH_OK); BH_VERIFY(BH_StringToInt32u(str, &size, 16) == 3456789012ul); BH_VERIFY(size == 8); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt32u(3456789012ul, 10)); + BH_VERIFY(BH_StringFromInt32u(str, 33, 3456789012ul, 10, NULL) == BH_OK); BH_VERIFY(BH_StringToInt32u(str, &size, 10) == 3456789012ul); BH_VERIFY(size == 10); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt32u(3456789012ul, 8)); + BH_VERIFY(BH_StringFromInt32u(str, 33, 3456789012ul, 8, NULL) == BH_OK); BH_VERIFY(BH_StringToInt32u(str, &size, 8) == 3456789012ul); BH_VERIFY(size == 11); - BH_StringFree(str); - BH_VERIFY(str = BH_StringFromInt32u(3456789012ul, 2)); + BH_VERIFY(BH_StringFromInt32u(str, 33, 3456789012ul, 2, NULL) == BH_OK); BH_VERIFY(BH_StringToInt32u(str, &size, 2) == 3456789012ul); BH_VERIFY(size == 32); - BH_StringFree(str); return 0; } |
