aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--include/BH/String.h205
-rw-r--r--src/String/Core.c21
-rw-r--r--src/String/Float.c244
-rw-r--r--src/String/FromInt.inl34
-rw-r--r--src/String/Int.c130
-rw-r--r--src/String/ToIntS.inl37
-rw-r--r--src/String/ToIntU.inl23
-rw-r--r--test/src/TestFloat.c23
-rw-r--r--test/src/TestInt.c78
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;
}