No raise on `new_points`, use strtod() for string to double
authorJeroen van der Heijden <jeroen@transceptor.technology>
Wed, 2 Jan 2019 13:57:58 +0000 (14:57 +0100)
committerJeroen van der Heijden <jeroen@transceptor.technology>
Wed, 2 Jan 2019 13:57:58 +0000 (14:57 +0100)
13 files changed:
include/xstr/xstr.h
main.c
src/argparse/argparse.c
src/siri/db/aggregate.c
src/siri/db/buffer.c
src/siri/db/group.c
src/siri/db/listener.c
src/siri/db/lookup.c
src/siri/db/points.c
src/siri/db/series.c
src/siri/siri.c
src/xstr/xstr.c
test/test_xstr/test_xstr.c

index 30d1212673b37e2172400c2db560a62c1834399f..10211a41e58bd602c784429217201c2675e334db 100644 (file)
@@ -20,7 +20,7 @@ bool xstr_is_empty(const char * str);
 bool xstr_is_int(const char * str);
 bool xstr_is_float(const char * str);
 bool xstr_is_graph(const char * str);
-double xstr_to_double(const char * src, size_t len);
+double xstr_to_double(const char * src);
 uint64_t xstr_to_uint64(const char * src, size_t len);
 char * xstr_dup(const char * src, size_t * n);
 
diff --git a/main.c b/main.c
index 2d55d7590893cfc8eae17f15f85bedc7a863f999..819a4f14cae8732ba17a72893afd70b27c926786 100644 (file)
--- a/main.c
+++ b/main.c
@@ -22,8 +22,8 @@
 
 int main(int argc, char * argv[])
 {
-    /* set local to LC_ALL */
-    (void) setlocale(LC_ALL, "");
+    /* set local to LC_ALL and C to force a period over comma for float */
+    (void) setlocale(LC_ALL, "C");
 
     /* initialize random */
     srand(time(NULL));
index d5a722681569c31ee8d15148ea48684d08a2a7f9..5823bb64fdd7a6d7404c929e24413b3ddc6abc9d 100644 (file)
@@ -77,7 +77,9 @@ void argparse_add_argument(
     assert(current != NULL);
 
     while (current->next != NULL)
+    {
         current = current->next;
+    }
     current->next = malloc(sizeof(argparse_args_t));
     current->next->argument = argument;
     current->next->next = NULL;
@@ -97,16 +99,20 @@ void argparse_parse(argparse_parser_t *parser, int argc, char *argv[])
         {
         case ARGPARSE_ERR_MISSING_VALUE:
             if  (current->argument->shortcut)
+            {
                 snprintf(buffer,
                         ARGPARSE_ERR_SIZE,
                         "argument -%c/--%s: expected one argument",
                         current->argument->shortcut,
                         current->argument->name);
+            }
             else
+            {
                 snprintf(buffer,
                         ARGPARSE_ERR_SIZE,
                         "argument --%s: expected one argument",
                         current->argument->name);
+            }
             break;
         case ARGPARSE_ERR_UNRECOGNIZED_ARGUMENT:
             snprintf(buffer,
@@ -122,18 +128,22 @@ void argparse_parse(argparse_parser_t *parser, int argc, char *argv[])
             break;
         case ARGPARSE_ERR_INVALID_CHOICE:
             if  (current->argument->shortcut)
+            {
                 snprintf(buffer,
                         ARGPARSE_ERR_SIZE,
                         "argument -%c/--%s: invalid choice: '%s'",
                         current->argument->shortcut,
                         current->argument->name,
                         argv[argn]);
+            }
             else
+            {
                 snprintf(buffer,
                         ARGPARSE_ERR_SIZE,
                         "argument --%s: invalid choice: '%s'",
                         current->argument->name,
                         argv[argn]);
+            }
             break;
         case ARGPARSE_ERR_ARGUMENT_TOO_LONG:
             snprintf(buffer,
@@ -182,15 +192,19 @@ static void fill_defaults(argparse_parser_t * parser)
         case ARGPARSE_STORE_FALSE:
         case ARGPARSE_STORE_INT:
             if (current->argument->pt_value_int32_t == 0)
+            {
                 *current->argument->pt_value_int32_t =
                         current->argument->default_int32_t;
+            }
             continue;
         case ARGPARSE_STORE_STRING:
         case ARGPARSE_STORE_STR_CHOICE:
             if (!strlen(current->argument->str_value))
+            {
                 strcpy(
                     current->argument->str_value,
                     current->argument->str_default);
+            }
             continue;
         }
     }
@@ -224,13 +238,17 @@ static void print_usage(argparse_parser_t * parser, const char * bname)
         case ARGPARSE_STORE_TRUE:
         case ARGPARSE_STORE_FALSE:
             if (current->argument->shortcut)
+            {
                 snprintf(buffer, ARGPARSE_HELP_SIZE,
                         "[-%c] ",
                         current->argument->shortcut);
+            }
             else
+            {
                 snprintf(buffer, ARGPARSE_HELP_SIZE,
                         "[--%s] ",
                         current->argument->name);
+            }
             break;
         case ARGPARSE_STORE_STRING:
         case ARGPARSE_STORE_INT:
@@ -238,27 +256,35 @@ static void print_usage(argparse_parser_t * parser, const char * bname)
             xstr_replace_char(uname, '-', '_');
             xstr_upper_case(uname);
             if (current->argument->shortcut)
+            {
                 snprintf(buffer, ARGPARSE_HELP_SIZE,
                         "[-%c %s] ",
                         current->argument->shortcut,
                         uname);
+            }
             else
+            {
                 snprintf(buffer, ARGPARSE_HELP_SIZE,
                         "[--%s %s] ",
                         current->argument->name,
                         uname);
+            }
             break;
         case ARGPARSE_STORE_STR_CHOICE:
             if (current->argument->shortcut)
+            {
                 snprintf(buffer, ARGPARSE_HELP_SIZE,
                         "[-%c {%s}] ",
                         current->argument->shortcut,
                         current->argument->choices);
+            }
             else
+            {
                 snprintf(buffer, ARGPARSE_HELP_SIZE,
                         "[--%s {%s}] ",
                         current->argument->name,
                         current->argument->choices);
+            }
             break;
         }
 
@@ -269,7 +295,9 @@ static void print_usage(argparse_parser_t * parser, const char * bname)
             line_size = ident + strlen(buffer);
         }
         else
+        {
             printf("%s", buffer);
+        }
     }
     printf("\n");
 }
@@ -293,9 +321,11 @@ static void print_help(argparse_parser_t * parser, const char * bname)
         case ARGPARSE_STORE_TRUE:
         case ARGPARSE_STORE_FALSE:
             if (current->argument->shortcut)
+            {
                 snprintf(buffer, ARGPARSE_HELP_SIZE,
                         " -%c,",
                         current->argument->shortcut);
+            }
             snprintf(buffer, ARGPARSE_HELP_SIZE,
                     "%s --%s",
                     buffer,
@@ -307,10 +337,12 @@ static void print_help(argparse_parser_t * parser, const char * bname)
             xstr_replace_char(uname, '-', '_');
             xstr_upper_case(uname);
             if (current->argument->shortcut)
+            {
                 snprintf(buffer, ARGPARSE_HELP_SIZE,
                         " -%c %s,",
                         current->argument->shortcut,
                         uname);
+            }
             snprintf(buffer, ARGPARSE_HELP_SIZE,
                     "%s --%s %s",
                     buffer,
@@ -332,9 +364,13 @@ static void print_help(argparse_parser_t * parser, const char * bname)
         }
         line_size = strlen(buffer);
         if (line_size > 24)
+        {
             printf("%s\n%*c", buffer, 24, ' ');
+        }
         else
+        {
             printf("%-*s", 24, buffer);
+        }
 
         printf("%s\n", current->argument->help);
     }
@@ -385,9 +421,13 @@ static int process_arg(
 
     /* check if we have exactly one match */
     if (num_matches == 0)
+    {
         return ARGPARSE_ERR_UNRECOGNIZED_ARGUMENT;
+    }
     if (num_matches > 1)
+    {
         return ARGPARSE_ERR_AMBIGUOUS_OPTION;
+    }
 
     /* store true/false are not expecting more, they can be handled here */
     if (    (*arg)->argument->action == ARGPARSE_STORE_TRUE ||
@@ -400,7 +440,9 @@ static int process_arg(
 
     /* we expect a value an this value should not start with - */
     if (++(*argn) == argc || *argv[*argn] == '-')
+    {
         return ARGPARSE_ERR_MISSING_VALUE;
+    }
 
     if (strlen(argv[*argn]) >= ARGPARSE_MAX_LEN_ARG)
     {
@@ -443,13 +485,17 @@ static bool match_choice(char * choices, char * choice)
     {
         /* quit if not enough left to match choice */
         if (len_rest < len_choice)
+        {
             return false;
+        }
 
         /* when we should check, perform the check */
         if (    check &&
                 strncmp(walk, choice, len_choice) == 0 &&
                 (len_rest == len_choice || walk[len_choice] == ','))
+        {
             return true;
+        }
 
         /* set check true again when a comma is found */
         check = *walk == ',';
index 0cfc7ec542ae281c722b0ebb4329780440b66589..e19ba52912bd1accd34536a4ee8a3bd664412744 100644 (file)
@@ -207,6 +207,7 @@ vec_t * siridb_aggregate_list(cleri_children_t * children, char * err_msg)
         return NULL;
     }
 
+    /* Loop over all aggregations */
     while (1)
     {
         gid = children->node->children->node->cl_obj->gid;
@@ -477,8 +478,7 @@ int siridb_aggregate_can_skip(cleri_children_t * children)
 
 /*
  * Return a new allocated points object or the same object as source.
- * In case of an error NULL is returned and an error message is set or a
- * signal is raised.
+ * In case of an error NULL is returned and an error message is set.
  */
 siridb_points_t * siridb_aggregate_run(
         siridb_points_t * source,
@@ -583,7 +583,7 @@ static int AGGREGATE_init_filter(
 
     case CLERI_GID_R_FLOAT:
         aggr->filter_tp = TP_DOUBLE;
-        aggr->filter_via.real = xstr_to_double(node->str, node->len);
+        aggr->filter_via.real = xstr_to_double(node->str);
         break;
 
     case CLERI_GID_STRING:
@@ -983,7 +983,7 @@ static siridb_points_t * AGGREGATE_to_one(
     if (points == NULL)
     {
         sprintf(err_msg, "Memory allocation error.");
-        return NULL;  /* signal is raised */
+        return NULL;
     }
 
     /* set time-stamp */
@@ -1059,7 +1059,7 @@ static siridb_points_t * AGGREGATE_group_by(
     if (points == NULL)
     {
         sprintf(err_msg, "Memory allocation error.");
-        return NULL;  /* signal is raised */
+        return NULL;
     }
 
     goup_ts = GROUP_TS(source->data);
@@ -1099,8 +1099,7 @@ static siridb_points_t * AGGREGATE_group_by(
     if (points->len < max_sz)
     {
         /* shrink points allocation */
-        point = (siridb_point_t *)
-                realloc(points->data, points->len * sizeof(siridb_point_t));
+        point = realloc(points->data, points->len * sizeof(siridb_point_t));
         if (point == NULL && points->len)
         {
             /* not critical */
index 40e169de7d52cf80240cbe5130c67e6509799719..2f1e95e0f811d544b4e8279f3c06238fcd03ed90 100644 (file)
@@ -179,7 +179,9 @@ int siridb_buffer_new_series(
     series->buffer = siridb_points_new(buffer->len, series->tp);
     if (series->buffer == NULL)
     {
-        return -1;  /* signal is raised */
+        /* TODO: maybe we can remove the ERR_ALLOC */
+        ERR_ALLOC
+        return -1;
     }
 
     return (buffer->empty->len) ?
index 92256cce61f7c2abcdbf99a69893d2fc25ebf62f..ae277bb424f8015a8f999e6f1b38c5d528ab9724 100644 (file)
@@ -25,7 +25,7 @@ siridb_group_t * siridb_group_new(
         size_t source_len,
         char * err_msg)
 {
-    siridb_group_t * group = (siridb_group_t *) malloc(sizeof(siridb_group_t));
+    siridb_group_t * group = malloc(sizeof(siridb_group_t));
     if (group == NULL)
     {
         ERR_ALLOC
index b335ab34d3110a92ba2be93b8b57b97ba01459b4..ea5600b4d28efbe1081abe55c89bcc34c5454015 100644 (file)
@@ -3649,7 +3649,7 @@ static void exit_set_drop_threshold(uv_async_t * handle)
 
     cleri_node_t * node = query->nodes->node->children->next->next->node;
 
-    double drop_threshold = xstr_to_double(node->str, node->len);
+    double drop_threshold = xstr_to_double(node->str);
 
     if (drop_threshold < 0.0 || drop_threshold > 1.0)
     {
@@ -4705,6 +4705,9 @@ static void async_no_points_aggregate(uv_async_t * handle)
     for (;  q_select->vec_index < q_select->vec->len;
             ++q_select->vec_index)
     {
+        const char * name;
+        size_t i;
+
         if (required_shard > MAX_BATCH_REQUIRE_SHARD)
         {
             async_more = 1;
@@ -4744,71 +4747,70 @@ static void async_no_points_aggregate(uv_async_t * handle)
 
         uv_mutex_unlock(&siridb->series_mutex);
 
-        if (points != NULL)
+        if (points == NULL)
         {
-            const char * name;
-            size_t i;
+            MEM_ERR_RET
+        }
 
-            for (i = 1; points->len && i < q_select->alist->len; i++)
+        for (i = 1; points->len && i < q_select->alist->len; i++)
+        {
+            aggr_points = siridb_aggregate_run(
+                    points,
+                    (siridb_aggr_t *) q_select->alist->data[i],
+                    query->err_msg);
+
+            if (aggr_points != points)
             {
-                aggr_points = siridb_aggregate_run(
-                        points,
-                        (siridb_aggr_t *) q_select->alist->data[i],
-                        query->err_msg);
+                siridb_points_free(points);
+            }
 
-                if (aggr_points != points)
-                {
-                    siridb_points_free(points);
-                }
+            if (aggr_points == NULL)
+            {
+                siridb_query_send_error(handle, CPROTO_ERR_QUERY);
+                return;
+            }
 
-                if (aggr_points == NULL)
-                {
-                    siridb_query_send_error(handle, CPROTO_ERR_QUERY);
-                    return;
-                }
+            points = aggr_points;
+        }
 
-                points = aggr_points;
-            }
+        q_select->n += points->len;
 
-            q_select->n += points->len;
+        if (q_select->merge_as == NULL)
+        {
+            name = siridb_presuf_name(
+                    q_select->presuf,
+                    series->name,
+                    series->name_len);
 
-            if (q_select->merge_as == NULL)
+            if (name == NULL || ct_add(q_select->result, name, points))
             {
-                name = siridb_presuf_name(
-                        q_select->presuf,
-                        series->name,
-                        series->name_len);
-
-                if (name == NULL || ct_add(q_select->result, name, points))
-                {
-                    sprintf(query->err_msg, "Error adding points to map.");
-                    siridb_points_free(points);
-                    log_critical("Critical error adding points");
-                    siridb_query_send_error(handle, CPROTO_ERR_QUERY);
-                    return;
-                }
+                sprintf(query->err_msg, "Error adding points to map.");
+                siridb_points_free(points);
+                log_critical("Critical error adding points");
+                siridb_query_send_error(handle, CPROTO_ERR_QUERY);
+                return;
             }
-            else
-            {
-                vec_t ** plist;
+        }
+        else
+        {
+            vec_t ** plist;
 
-                name = siridb_presuf_name(
-                        q_select->presuf,
-                        q_select->merge_as,
-                        strlen(q_select->merge_as));
+            name = siridb_presuf_name(
+                    q_select->presuf,
+                    q_select->merge_as,
+                    strlen(q_select->merge_as));
 
-                plist = (vec_t **) ct_getaddr(q_select->result, name);
+            plist = (vec_t **) ct_getaddr(q_select->result, name);
 
-                if (    name == NULL ||
-                        plist == NULL ||
-                        vec_append_safe(plist, points))
-                {
-                    sprintf(query->err_msg, "Error adding points to map.");
-                    siridb_points_free(points);
-                    log_critical("Critical error adding points");
-                    siridb_query_send_error(handle, CPROTO_ERR_QUERY);
-                    return;
-                }
+            if (    name == NULL ||
+                    plist == NULL ||
+                    vec_append_safe(plist, points))
+            {
+                sprintf(query->err_msg, "Error adding points to map.");
+                siridb_points_free(points);
+                log_critical("Critical error adding points");
+                siridb_query_send_error(handle, CPROTO_ERR_QUERY);
+                return;
             }
         }
     }
index 54a59c9c638ce140c9a5fbbde2cdafa6c1be1549..fa5525860fb3d5cb1252716956430f8b124496d2 100644 (file)
@@ -42,8 +42,7 @@ uint16_t siridb_lookup_sn_raw(
  */
 siridb_lookup_t * siridb_lookup_new(uint_fast16_t num_pools)
 {
-    siridb_lookup_t * lookup =
-            (siridb_lookup_t *) calloc(1, sizeof(siridb_lookup_t));
+    siridb_lookup_t * lookup = calloc(1, sizeof(siridb_lookup_t));
 
     if (lookup == NULL)
     {
index 1995ac69a01da309a417ea3d0a4618b5d3636c27..caf842d4e7c8e302a72d181b8a9e53fac33674fc 100644 (file)
@@ -64,29 +64,25 @@ void siridb_points_init(void)
 }
 
 /*
- * Returns NULL and raises a SIGNAL in case an error has occurred.
+ * Returns NULL in case an error has occurred.
  */
 siridb_points_t * siridb_points_new(size_t size, points_tp tp)
 {
-    siridb_points_t * points =
-            (siridb_points_t *) malloc(sizeof(siridb_points_t));
+    siridb_points_t * points = malloc(sizeof(siridb_points_t));
     if (points == NULL)
     {
-        ERR_ALLOC
+        return NULL;
     }
-    else
+
+    points->len = 0;
+    points->tp = tp;
+    points->data = malloc(sizeof(siridb_point_t) * size);
+    if (points->data == NULL)
     {
-        points->len = 0;
-        points->tp = tp;
-        points->data =
-                (siridb_point_t *) malloc(sizeof(siridb_point_t) * size);
-        if (points->data == NULL)
-        {
-            ERR_ALLOC
-            free(points);
-            points = NULL;
-        }
+        free(points);
+        return NULL;
     }
+
     return points;
 }
 
@@ -115,8 +111,7 @@ siridb_points_t * siridb_points_copy(siridb_points_t * points)
     {
         return NULL;
     }
-    siridb_points_t * cpoints =
-            (siridb_points_t *) malloc(sizeof(siridb_points_t));
+    siridb_points_t * cpoints = malloc(sizeof(siridb_points_t));
     if (cpoints != NULL)
     {
         size_t sz = sizeof(siridb_point_t) * points->len;
index 613645ebfbbde1298f3507c9a503f9e51c995ad4..d7e9e54ba4a49e34cfbb15e3e63137f3be4dc133 100644 (file)
@@ -704,7 +704,8 @@ siridb_points_t * siridb_series_get_points(
 
     if (points == NULL)
     {
-        return NULL;  /* signal is raised */
+        ERR_ALLOC  /* TODO: maybe remove ERR_ALLOC */
+        return NULL;
     }
 
     for (i = 0; i < len; i++)
@@ -1080,7 +1081,9 @@ int siridb_series_optimize_shard(
     points = siridb_points_new(size, series->tp);
     if (points == NULL)
     {
-        return -1;  /* signal is raised */
+        /* TODO: check if we can remove this ERR_ALLOC */
+        ERR_ALLOC
+        return -1;
     }
 
     for (i = start; i < end; i++)
index 4cdd17749f637a44242217cad200ad71cde93e04..5d53a3f4fe556defabdca28d7a757dc2583cd724 100644 (file)
@@ -115,6 +115,8 @@ void siri_setup_logger(void)
             return;
         }
     }
+
+    assert (0);
     /* We should not get here since args should always
      * contain a valid log level
      */
index ee3dcd32b5eaff7b04c11ea7a39cd66d9a5ec02d..95dc46c1c7d5cb9e049047aed41662c524cd56c0 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 void xstr_lower_case(char * sptr)
 {
    for (; *sptr != '\0'; sptr++)
-        *sptr = tolower( (unsigned char) * sptr);
+   {
+       *sptr = tolower( (unsigned char) * sptr);
+   }
 }
 
 void xstr_upper_case(char * sptr)
 {
    for (; *sptr != '\0'; sptr++)
-        *sptr = toupper( (unsigned char) * sptr);
+   {
+       *sptr = toupper( (unsigned char) * sptr);
+   }
 }
 
 void xstr_replace_char(char * sptr, char orig, char repl)
@@ -273,54 +278,42 @@ size_t xstr_extract_string(char * dest, const char * source, size_t len)
  *      - string is allowed to have one dot (.) at most but not required
  *      - string can start with a plus (+) or minus (-) sign.
  */
-double xstr_to_double(const char * src, size_t len)
+double xstr_to_double(const char * str)
 {
-    char * pt = (char *) src;
-    assert (len);
-    double d = 0;
-    double convert;
-    uint64_t r1 = 0;
+    double d;
+    double negative = 0;
 
-    switch (*pt)
+    switch (*str)
     {
     case '-':
-        assert (len > 1);
-        convert = -1.0;
-        ++pt;
-        --len;
+        negative = -1.0;
+        ++str;
         break;
     case '+':
-        assert (len > 1);
-        convert = 1.0;
-        ++pt;
-        --len;
+        ++str;
         break;
-    default:
-        convert = 1.0;
     }
 
-    for (; len && isdigit(*pt); --len, ++pt)
-    {
-        r1 = 10 * r1 + *pt - '0';
-    }
+    if (*str == 'i')
+        return negative ? negative * INFINITY : INFINITY;
+
+    if (*str == 'n')
+        return NAN;
+
+    if (errno == ERANGE)
+        errno = 0;
 
-    d = (double) r1;
+    d = strtod(str, NULL);
 
-    if (len && --len)
+    if (errno == ERANGE)
     {
-        uint64_t r2;
-        double power;
-        ++pt;
-        r2 = *pt - '0';
-        for (power = -1.0f; --len && isdigit(*(++pt)); power--)
-        {
-            r2 = 10 * r2 + *pt - '0';
-        }
+        assert (d == HUGE_VAL || d == -HUGE_VAL);
 
-        d += pow(10.0f, power) * (double) r2;
+        d = d == HUGE_VAL ? INFINITY : -INFINITY;
+        errno = 0;
     }
 
-    return convert * d;
+    return negative ? negative * d : d;
 }
 
 /*
index 0cf3a135644b135be2a9a5305629d4b02f785bc0..2e5121487d0b1322d00eb296f9b6e697b4a18e80 100644 (file)
@@ -8,24 +8,22 @@ int main()
 
     /* xstr_to_double */
     {
-        _assert (xstr_to_double("0.5", 3) == 0.5);
-        _assert (xstr_to_double("0.55", 3) == 0.5);
-        _assert (xstr_to_double("123.456", 7) == 123.456);
-        _assert (xstr_to_double("123", 3) == 123);
-        _assert (xstr_to_double("1234", 3) == 123);
-        _assert (xstr_to_double("123.", 4) == 123);
-        _assert (xstr_to_double("123.", 3) == 123);
-        _assert (xstr_to_double("+1234", 4) == 123);
-        _assert (xstr_to_double("-1234", 4) == -123);
-        _assert (xstr_to_double("123456.", 3) == 123);
-        _assert (xstr_to_double("-0.5", 4) == -0.5);
-        _assert (xstr_to_double("-0.56", 4) == -0.5);
-        _assert (xstr_to_double("+0.5", 4) == 0.5);
-        _assert (xstr_to_double("+0.56", 4) == 0.5);
-        _assert (xstr_to_double("-.5", 3) == -0.5);
-        _assert (xstr_to_double("+.55", 3) == 0.5);
-        _assert (xstr_to_double(".55", 2) == 0.5);
-        _assert (xstr_to_double("-.55", 3) == -0.5);
+        _assert (xstr_to_double("0.5") == 0.5);
+        _assert (xstr_to_double("0.55") == 0.55);
+        _assert (xstr_to_double("123.456") == 123.456);
+        _assert (xstr_to_double("123") == 123.0);
+        _assert (xstr_to_double("123.") == 123.0);
+        _assert (xstr_to_double("123.") == 123.0);
+        _assert (xstr_to_double("+1234") == 1234.0);
+        _assert (xstr_to_double("-1234") == -1234.0);
+        _assert (xstr_to_double("123456.") == 123456.0);
+        _assert (xstr_to_double("-0.5") == -0.5);
+        _assert (xstr_to_double("-0.56") == -0.56);
+        _assert (xstr_to_double("+0.5") == 0.5);
+        _assert (xstr_to_double("-.5") == -0.5);
+        _assert (xstr_to_double("+.55") == 0.55);
+        _assert (xstr_to_double(".55") == 0.55);
+        _assert (xstr_to_double("-.55") == -0.55);
     }
 
     return test_end();