rsys

Basic data structures and low-level features
git clone git://git.meso-star.fr/rsys.git
Log | Files | Refs | README | LICENSE

commit 4f793ab6b7c88fdcf426f3a2af76c633ed555a3e
parent 90bdbf39c299cdfbae83e8007821ba0734f0da1e
Author: vaplv <vaplv@free.fr>
Date:   Wed, 28 Oct 2015 11:53:51 +0100

Add and test some C string conversion functions

Add and test the following functions:
  - cstr_to_double
  - cstr_to_float
  - cstr_to_long
  - cstr_to_int
  - cstr_to_uint
  - cstr_to_list_double
  - cstr_to_list_float

Diffstat:
Mcmake/CMakeLists.txt | 3+++
Asrc/cstr.c | 22++++++++++++++++++++++
Asrc/cstr.h | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cstr_to_list.h | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/str.h | 2+-
Asrc/test_cstr.c | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_math.c | 1-
7 files changed, 407 insertions(+), 2 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -41,6 +41,7 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(RSYS_FILES_SRC clock_time.c + cstr.c float44.c image.c library.c @@ -65,6 +66,7 @@ set(RSYS_FILES_INC_API binary_heap.h clock_time.h condition.h + cstr.h dynamic_array.h dynamic_array_char.h dynamic_array_double.h @@ -148,6 +150,7 @@ if(NOT NO_TEST) new_test(test_atomic) new_test(test_binary_heap rsys) + new_test(test_cstr rsys) new_test(test_dynamic_array rsys) new_test(test_float2 ${MATH_LIB}) new_test(test_float3 ${MATH_LIB}) diff --git a/src/cstr.c b/src/cstr.c @@ -0,0 +1,22 @@ +/* Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#include "cstr_to_list.h" + +#define CSTR_LIST_TYPE double +#include "cstr_to_list.h" + +#define CSTR_LIST_TYPE float +#include "cstr_to_list.h" diff --git a/src/cstr.h b/src/cstr.h @@ -0,0 +1,118 @@ +/* Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef CSTR_H +#define CSTR_H + +#include "rsys.h" + +#include <float.h> +#include <limits.h> +#include <stdlib.h> + +static INLINE res_T +cstr_to_double(const char* str, double* dst) +{ + char* end; + ASSERT(dst); + if(!str) return RES_BAD_ARG; + *dst = strtod(str, &end); + if(end == str) + return RES_BAD_ARG; + for(;*end != '\0'; ++end) { + if(*end != ' ' && *end != '\t') + return RES_BAD_ARG; + } + return RES_OK; +} + +static INLINE res_T +cstr_to_float(const char* str, float* dst) +{ + double dbl; + res_T res; + ASSERT(dst); + res = cstr_to_double(str, &dbl); + if(res != RES_OK) return res; + if((dbl > 0.0 && dbl < FLT_MIN && dbl > FLT_MAX) + || (dbl < 0.0 && dbl >-FLT_MIN && dbl <-FLT_MAX)) + return RES_BAD_ARG; + *dst = (float)dbl; + return RES_OK; +} + +static INLINE res_T +cstr_to_long(const char* str, long* dst) +{ + char* end; + ASSERT(dst); + if(!str) return RES_BAD_ARG; + *dst = strtol(str, &end, 10/* base */); + if(end == str) + return RES_BAD_ARG; + for(;*end != '\0'; ++end) { + if(*end != ' ' && *end != '\t') + return RES_BAD_ARG; + } + return RES_OK; +} + +static INLINE res_T +cstr_to_int(const char* str, int* dst) +{ + long l; + res_T res; + ASSERT(dst); + res = cstr_to_long(str, &l); + if(res != RES_OK) + return res; + if(l > INT_MAX || l < INT_MIN) + return RES_BAD_ARG; + *dst = (int)l; + return RES_OK; +} + +static INLINE res_T +cstr_to_uint(const char* str, unsigned* dst) +{ + long l; + res_T res; + ASSERT(dst); + res = cstr_to_long(str, &l); + if(res != RES_OK) + return res; + if(l < 0 || (sizeof(long) > sizeof(unsigned) && l > (long)UINT_MAX)) + return RES_BAD_ARG; + *dst = (unsigned)l; + return RES_OK; +} + +/* Convert a string "A:B:C:D:E:F" in a list of { A, B, C, D, E, F } */ +RSYS_API res_T +cstr_to_list_double + (const char* str, + double dst[], /* May be NULL */ + size_t* length, /* May be NULL. Length of the filled list */ + const size_t max_length); /* Maximum size of dst */ + +RSYS_API res_T +cstr_to_list_float + (const char* str, + float dst[], /* May be NULL */ + size_t* length, /* May be NULL. Length of the filled list */ + const size_t max_length); /* Maximum size of dst */ + +#endif /* CSTR_H */ + diff --git a/src/cstr_to_list.h b/src/cstr_to_list.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +/* + * Generate the cstr_to_list conversion function with respect to the + * CSTR_LIST_TYPE macro. + */ + +#ifndef CSTR_LIST_TYPE +#ifndef CSTR_TO_LIST_H +#define CSTR_TO_LIST_H + +#include "cstr.h" +#include "dynamic_array_char.h" + +#endif /* CSTR_TO_LIST_H */ +#else /* defined(CSTR_LIST_TYPE) */ + +#ifndef CSTR_LIST_TYPE + #error "Missing the CSTR_LIST_TYPE macro defining the type of the list" +#endif + +res_T +CONCAT(cstr_to_list_, CSTR_LIST_TYPE) + (const char* str, + CSTR_LIST_TYPE dst[], + size_t* length, + const size_t max_length) /* Maximum size of dst */ + +{ + struct darray_char buf; + size_t str_len; + size_t i; + char* tk; + res_T res = RES_OK; + + if(!str) { + /* Avoid exit block since buf is not initialised */ + return RES_BAD_ARG; + } + if(!dst && !length) { /* Useless invocation */ + /* Avoid exit block since buf is not initialised */ + return RES_OK; + } + + /* Copy str in a temporary buffer to parse */ + darray_char_init(NULL, &buf); + str_len = strlen(str); + res = darray_char_resize(&buf, str_len + 1/*null char*/); + if(res != RES_OK) goto error; + strncpy(darray_char_data_get(&buf), str, str_len + 1/*null char*/); + + /* Parse the string */ + tk = strtok(darray_char_data_get(&buf), ":"); + for(i=0; tk; tk = strtok(NULL, ":"), ++i) { + if(dst) { + if(i >= max_length) { + res = RES_BAD_ARG; + goto error; + } + res = CONCAT(cstr_to_, CSTR_LIST_TYPE)(tk, dst + i); + } else { + CSTR_LIST_TYPE d; + res = CONCAT(cstr_to_, CSTR_LIST_TYPE)(tk, &d); + } + if(res != RES_OK) goto error; + } + + if(length) + *length = i; + +exit: + darray_char_release(&buf); + return res; +error: + goto exit; +} + +#undef CSTR_LIST_TYPE + +#endif /* defined(CSTR_LIST_TYPE) */ + diff --git a/src/str.h b/src/str.h @@ -119,7 +119,7 @@ str_copy(struct str* dst, const struct str* src) } static INLINE res_T -str_copy_and_clear( struct str* dst, struct str* src ) +str_copy_and_clear(struct str* dst, struct str* src) { res_T res = RES_OK; ASSERT(dst && src); diff --git a/src/test_cstr.c b/src/test_cstr.c @@ -0,0 +1,169 @@ +/* Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#include "cstr.h" +#include "math.h" + +int +main(int argc, char** argv) +{ + char buf[128]; + double dlist[4]; + float flist[4]; + size_t len; + double d; + float f; + long l; + int i; + unsigned u; + (void)argc, (void)argv; + + CHECK(cstr_to_double(NULL, &d), RES_BAD_ARG); + CHECK(cstr_to_double("a", &d), RES_BAD_ARG); + CHECK(cstr_to_double(STR(PI), &d), RES_OK); + CHECK(d, PI); + CHECK(cstr_to_double(" 1.e-3", &d), RES_OK); + CHECK(d, 1.e-3); + CHECK(cstr_to_double("+1.E+3 ", &d), RES_OK); + CHECK(d, 1.e3); + CHECK(cstr_to_double("INF", &d), RES_OK); + CHECK(d, INF); + CHECK(cstr_to_double("INFINITY", &d), RES_OK); + CHECK(d, INF); + CHECK(cstr_to_double("", &d), RES_BAD_ARG); + + CHECK(cstr_to_float(NULL, &f), RES_BAD_ARG); + CHECK(cstr_to_float("a", &f), RES_BAD_ARG); + CHECK(cstr_to_float(STR(PI), &f), RES_OK); + CHECK(f, (float)PI); + CHECK(cstr_to_float("1.e-1", &f), RES_OK); + CHECK(f, 1.e-1f); + CHECK(cstr_to_float("+1.E+3", &f), RES_OK); + CHECK(f, 1.e3f); + CHECK(cstr_to_float("INF", &f), RES_OK); + CHECK(f, (float)INF); + CHECK(cstr_to_float("INFINITY", &f), RES_OK); + CHECK(f, (float)INF); + CHECK(cstr_to_float(STR(DBL_MAX), &f), RES_BAD_ARG); + CHECK(cstr_to_float(STR(DBL_MIN), &f), RES_BAD_ARG); + + CHECK(cstr_to_long(NULL, &l), RES_BAD_ARG); + CHECK(cstr_to_long("a", &l), RES_BAD_ARG); + CHECK(cstr_to_long("1.e-3", &l), RES_BAD_ARG); + CHECK(cstr_to_long("1", &l), RES_OK); + CHECK(l, 1); + CHECK(cstr_to_long("-1", &l), RES_OK); + CHECK(l, -1); + CHECK(cstr_to_long("+1234567890", &l), RES_OK); + CHECK(l, 1234567890); + CHECK(cstr_to_long(" \t+1234567890 \t ", &l), RES_OK); + CHECK(l, 1234567890); + CHECK(cstr_to_long(" \t+1234567890 \t a", &l), RES_BAD_ARG); + + CHECK(cstr_to_int(NULL, &i), RES_BAD_ARG); + CHECK(cstr_to_int("a", &i), RES_BAD_ARG); + CHECK(cstr_to_int("1.e-1", &i), RES_BAD_ARG); + CHECK(cstr_to_int("1", &i), RES_OK); + CHECK(i, 1); + CHECK(cstr_to_int("-2", &i), RES_OK); + CHECK(i, -2); + CHECK(cstr_to_int("\t-2 ", &i), RES_OK); + CHECK(i, -2); + sprintf(buf, "%d", INT_MAX); + CHECK(cstr_to_int(buf, &i), RES_OK); + CHECK(i, INT_MAX); + sprintf(buf, "%d", INT_MIN); + CHECK(cstr_to_int(buf, &i), RES_OK); + CHECK(i, INT_MIN); + sprintf(buf, "%ld", (long)INT_MAX+1); + CHECK(cstr_to_int(buf, &i), RES_BAD_ARG); + sprintf(buf, "%ld", (long)INT_MIN-1); + CHECK(cstr_to_int(buf, &i), RES_BAD_ARG); + + CHECK(cstr_to_uint(NULL, &u), RES_BAD_ARG); + CHECK(cstr_to_uint("a", &u), RES_BAD_ARG); + CHECK(cstr_to_uint("-1", &u), RES_BAD_ARG); + CHECK(cstr_to_uint("0.", &u), RES_BAD_ARG); + CHECK(cstr_to_uint("0", &u), RES_OK); + CHECK(u, 0); + CHECK(cstr_to_uint("+2", &u), RES_OK); + CHECK(u, 2); + CHECK(cstr_to_uint(" \t+123 \t ", &u), RES_OK); + CHECK(u, 123); + sprintf(buf, "%u", UINT_MAX); + CHECK(cstr_to_uint(buf, &u), RES_OK); + CHECK(u, UINT_MAX); + sprintf(buf, "%lu", (unsigned long)UINT_MAX+1); + CHECK(cstr_to_uint(buf, &u), RES_BAD_ARG); + + CHECK(cstr_to_list_double(NULL, dlist, NULL, 3), RES_BAD_ARG); + CHECK(cstr_to_list_double("a", dlist, NULL, 3), RES_BAD_ARG); + CHECK(cstr_to_list_double("1.e-3:2.0:"STR(PI), dlist, NULL, 3), RES_OK); + CHECK(dlist[0], 1.e-3); + CHECK(dlist[1], 2.0); + CHECK(dlist[2], PI); + CHECK(cstr_to_list_double("1.e-3:2.0:", dlist, &len, 3), RES_OK); + CHECK(len, 2); + CHECK(dlist[0], 1.e-3); + CHECK(dlist[1], 2.0); + CHECK(cstr_to_list_double("-1.0:0.5:1.2:4.3", dlist, &len, 2), RES_BAD_ARG); + CHECK(cstr_to_list_double("-1.0:0.5:1.2:4.3a", NULL, &len, 0), RES_BAD_ARG); + CHECK(cstr_to_list_double("-1.0:0.5:1.2:4.3", NULL, &len, 0), RES_OK); + CHECK(len, 4); + CHECK(cstr_to_list_double("-1.0:0.5:1.2:4.3", dlist, NULL, len), RES_OK); + CHECK(dlist[0], -1.0); + CHECK(dlist[1], 0.5); + CHECK(dlist[2], 1.2); + CHECK(dlist[3], 4.3); + CHECK(cstr_to_list_double(" \t -1.0:0.5:1.2:INF \t", dlist, NULL, 4), RES_OK); + CHECK(dlist[0], -1.0); + CHECK(dlist[1], 0.5); + CHECK(dlist[2], 1.2); + CHECK(dlist[3], INF); + CHECK(cstr_to_list_double(" \t -1.0:0.5:1.2:4.3 \ta", dlist, NULL, 4), RES_BAD_ARG); + dlist[1] = dlist[2] = dlist[3] = -1.0; + CHECK(cstr_to_list_double("1.0", dlist, NULL, 1), RES_OK); + CHECK(dlist[0], 1.0); + CHECK(dlist[1], -1.0); + CHECK(dlist[2], -1.0); + CHECK(dlist[3], -1.0); + + CHECK(cstr_to_list_float(NULL, flist, NULL, 3), RES_BAD_ARG); + CHECK(cstr_to_list_float("a", flist, NULL, 3), RES_BAD_ARG); + CHECK(cstr_to_list_float("1.e-3:2.0:"STR(PI), flist, NULL, 3), RES_OK); + CHECK(flist[0], 1.e-3f); + CHECK(flist[1], 2.0f); + CHECK(flist[2], (float)PI); + CHECK(cstr_to_list_float("1.e-3:2.0:", flist, &len, 3), RES_OK); + CHECK(len, 2); + CHECK(flist[0], 1.e-3f); + CHECK(flist[1], 2.0f); + CHECK(cstr_to_list_float("-1.0:0.5:1.2:4.3", flist, &len, 2), RES_BAD_ARG); + CHECK(cstr_to_list_float("-1.0:0.5:1.2:4.3a", NULL, &len, 0), RES_BAD_ARG); + CHECK(cstr_to_list_float("-1.0:0.5:1.2:4.3", NULL, &len, 0), RES_OK); + CHECK(len, 4); + CHECK(cstr_to_list_float("-1.0:0.5:1.2:4.3", flist, NULL, len), RES_OK); + CHECK(flist[0], -1.0f); + CHECK(flist[1], 0.5f); + CHECK(flist[2], 1.2f); + CHECK(flist[3], 4.3f); + CHECK(cstr_to_list_float(" \t -1.0:0.5:1.2:INF \t", flist, NULL, 4), RES_OK); + CHECK(flist[0], -1.0f); + CHECK(flist[1], 0.5f); + CHECK(flist[2], 1.2f); + CHECK(flist[3], (float)INF); + + return 0; +} diff --git a/src/test_math.c b/src/test_math.c @@ -50,7 +50,6 @@ main(int argc, char** argv) CHECK(eq_eps(PI, 3.14159265358979323846, 1.e-8), 1); CHECK(eq_eps(RCP_PI, 1.0/PI, 1.e-8), 1); - CHECK(1.f/0.f, (float)INF); CHECK(-1.f/0.f, (float)-INF); NCHECK(1.0/0.0, -INF);