Skip to content

Commit

Permalink
Merge pull request #1788 from noxpardalis/master
Browse files Browse the repository at this point in the history
Assorted minor fixes
  • Loading branch information
eboasson authored Aug 30, 2023
2 parents b6fe21d + 4f631a7 commit 7df82fb
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 80 deletions.
22 changes: 9 additions & 13 deletions src/ddsrt/include/dds/ddsrt/strtod.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ extern "C" {
/**
* @brief Convert a string to a double precision floating point number.
*
* This operation handles locale specific manipulation of the floating point
* string and then sets the output double based on the parsing via `strtod`
* from the standard library. The function returns a failure iff:
* - the string to be parsed represents a value that is too large to store in a double.
* - the string contains junk.
* - the string parses to either `-nan` or `nan`.
* - the string parses to either `-inf` or `inf`.
* It is otherwise successful.
*
* @param[in] nptr A string to convert into a double.
* @param[out] endptr If not NULL, a char* where the address of first invalid
* character is stored.
Expand All @@ -38,19 +47,6 @@ extern "C" {
dds_return_t
ddsrt_strtod(const char *nptr, char **endptr, double *dblptr);

/**
* @brief Convert a string to a floating point number.
*
* @param[in] nptr A string to convert into a float.
* @param[in] endptr If not NULL, a char* where the address of first invalid
* character is stored.
* @param[out] fltptr A float where the floating-point number is stored.
*
* @returns A dds_return_t indicating success or failure.
*/
dds_return_t
ddsrt_strtof(const char *nptr, char **endptr, float *fltptr);

/**
* @brief Convert a double-precision floating-point number to a string.
*
Expand Down
13 changes: 8 additions & 5 deletions src/ddsrt/src/hopscotch.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ static bool ddsrt_chh_data_valid_p (void *data)
return data != NULL && data != CHH_BUSY;
}

static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg)
static dds_return_t ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg)
{
uint32_t size;
uint32_t i;
Expand All @@ -328,7 +328,10 @@ static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_ha
rt->gc_buckets = gc_buckets;
rt->gc_buckets_arg = gc_buckets_arg;

buckets = ddsrt_malloc (offsetof (struct ddsrt_chh_bucket_array, bs) + size * sizeof (*buckets->bs));
buckets = ddsrt_malloc_s (offsetof (struct ddsrt_chh_bucket_array, bs) + size * sizeof (*buckets->bs));
if (buckets == NULL) {
return DDS_RETCODE_OUT_OF_RESOURCES;
}
ddsrt_atomic_stvoidp (&rt->buckets, buckets);
buckets->size = size;
for (i = 0; i < size; i++) {
Expand All @@ -338,7 +341,7 @@ static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_ha
ddsrt_atomic_stvoidp (&b->data, NULL);
}
ddsrt_mutex_init (&rt->change_lock);
return 0;
return DDS_RETCODE_OK;
}

static void ddsrt_chh_fini (struct ddsrt_chh *rt)
Expand All @@ -349,8 +352,8 @@ static void ddsrt_chh_fini (struct ddsrt_chh *rt)

struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg)
{
struct ddsrt_chh *hh = ddsrt_malloc (sizeof (*hh));
if (ddsrt_chh_init (hh, init_size, hash, equals, gc_buckets, gc_buckets_arg) < 0) {
struct ddsrt_chh *hh = ddsrt_malloc_s (sizeof (*hh));
if (hh == NULL || ddsrt_chh_init (hh, init_size, hash, equals, gc_buckets, gc_buckets_arg) < 0) {
ddsrt_free (hh);
return NULL;
} else {
Expand Down
4 changes: 3 additions & 1 deletion src/ddsrt/src/retcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ const char *dds_strretcode (dds_return_t ret)
if (ret == INT32_MIN)
return xretcodes[0];

// INT32_MIN has already been handled and so this is safe
// and will guarantee ret >= 0.
if (ret < 0)
ret = -ret;
if (ret >= 0 && ret < nretcodes)
if (ret < nretcodes)
return retcodes[ret];
else if (ret >= (-DDS_XRETCODE_BASE) && ret < (-DDS_XRETCODE_BASE) + nxretcodes)
return xretcodes[ret - (-DDS_XRETCODE_BASE)];
Expand Down
111 changes: 71 additions & 40 deletions src/ddsrt/src/strtod.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include "dds/ddsrt/io.h"
#include "dds/ddsrt/log.h"
Expand Down Expand Up @@ -94,28 +95,17 @@ os_lcNumericReplace(char *str) {
}
}

dds_return_t
ddsrt_strtod(const char *nptr, char **endptr, double *dblptr)
/** @brief Delocalize a floating point string to use '.' as its decimal separator.
* @param[in] nptr the localized floating point string.
* @param[out] nptrCopy the delocalized floating point string (needs to have a length of DOUBLE_STRING_MAX_LENGTH).
* @param[out] nptrCopyEnd a pointer to the end of the delocalized floating point string.
*/
static void delocalize_floating_point_str(const char *nptr, char *nptrCopy, char **nptrCopyEnd)
{
double dbl;
int orig_errno;
dds_return_t ret = DDS_RETCODE_OK;

assert(nptr != NULL);
assert(dblptr != NULL);

orig_errno = errno;
if (os_lcNumericGet() == '.') {
errno = 0;
/* The current locale uses '.', so strtod can be used as is. */
dbl = strtod(nptr, endptr);
} else {
/* The current locale uses ',', so we can not use the standard functions as
is, but have to do extra work because ospl uses "x.x" doubles (notice
the dot). Just copy the string and replace the LC_NUMERIC. */
char nptrCopy[DOUBLE_STRING_MAX_LENGTH];
char *nptrCopyIdx;
char *nptrCopyEnd;
char *nptrIdx;

/* It is possible that the given nptr just starts with a double
Expand All @@ -124,8 +114,8 @@ ddsrt_strtod(const char *nptr, char **endptr, double *dblptr)
doubles' end. */
nptrIdx = (char*)nptr;
nptrCopyIdx = nptrCopy;
nptrCopyEnd = nptrCopyIdx + DOUBLE_STRING_MAX_LENGTH - 1;
while (VALID_DOUBLE_CHAR(*nptrIdx) && (nptrCopyIdx < nptrCopyEnd)) {
*nptrCopyEnd = nptrCopyIdx + DOUBLE_STRING_MAX_LENGTH - 1;
while (VALID_DOUBLE_CHAR(*nptrIdx) && (nptrCopyIdx < *nptrCopyEnd)) {
if (*nptrIdx == '.') {
/* Replace '.' with locale LC_NUMERIC to get strtod to work. */
*nptrCopyIdx = os_lcNumericGet();
Expand All @@ -136,19 +126,78 @@ ddsrt_strtod(const char *nptr, char **endptr, double *dblptr)
nptrCopyIdx++;
}
*nptrCopyIdx = '\0';
}

dds_return_t
ddsrt_strtod(const char *nptr, char **endptr, double *dblptr)
{
double dbl;
int orig_errno;
dds_return_t ret = DDS_RETCODE_OK;
char *string_end = NULL;
bool successfully_parsed = false;

assert(nptr != NULL);
assert(dblptr != NULL);

orig_errno = errno;
if (os_lcNumericGet() == '.') {
errno = 0;
/* The current locale uses '.', so strtod can be used as is. */
dbl = strtod(nptr, &string_end);

/* Check that something was parsed */
if (nptr != string_end) {
successfully_parsed = true;
}

/* Set the proper end char when needed. */
if (endptr != NULL) {
*endptr = string_end;
}
} else {
/* The current locale has to be normalized to use '.' for the floating
point string. */
char nptrCopy[DOUBLE_STRING_MAX_LENGTH];
delocalize_floating_point_str(nptr, nptrCopy, &string_end);

/* Now that we have a copy with the proper locale LC_NUMERIC, we can use
strtod() for the conversion. */
errno = 0;
dbl = strtod(nptrCopy, &nptrCopyEnd);
dbl = strtod(nptrCopy, &string_end);

/* Check that something was parsed */
if (nptrCopy != string_end) {
successfully_parsed = true;
}

/* Calculate the proper end char when needed. */
if (endptr != NULL) {
*endptr = (char*)nptr + (nptrCopyEnd - nptrCopy);
*endptr = (char*)nptr + (string_end - nptrCopy);
}
}

if ((dbl == HUGE_VALF || dbl == HUGE_VALL || dbl == 0) && errno == ERANGE) {
// There are two erroring scenarios from `strtod`.
//
// 1. The floating point value to be parsed is too large:
// In this case `strtod` sets `errno` to `ERANGE` and will return a
// parsed value of either `-HUGE_VAL` or `HUGE_VAL` depending on the
// initial sign present in the string.
//
// 2. The string contains a non-numeric prefix:
// In the case junk is passed in `strtod` parses nothing. As a result,
// the value that is returned corresponds to `0.0`. To differentiate
// between the parsing scenarios of junk being passed in versus a valid
// floating point string that parses to 0 (such as "0.0") `strtod` also
// ensures that the provided end pointer == start pointer in the case
// that a junk prefix is encountered.
//
// The two other scenarios that we want to reject are:
//
// 3. The value being parsed results in `-nan` or `nan`.
// 4. The value being parsed results in `-inf` or `inf`.
if (errno == ERANGE || !successfully_parsed
|| isnan(dbl) || isinf(dbl)) {
ret = DDS_RETCODE_OUT_OF_RANGE;
} else {
errno = orig_errno;
Expand All @@ -159,24 +208,6 @@ ddsrt_strtod(const char *nptr, char **endptr, double *dblptr)
return ret;
}

dds_return_t
ddsrt_strtof(const char *nptr, char **endptr, float *fltptr)
{
/* Just use os_strtod(). */
/* FIXME: This will have to do for now, but a single-precision floating
point number is definitely not a double-precision floating point
number. */
double dbl = 0.0;
dds_return_t ret;

assert(nptr != NULL);
assert(fltptr != NULL);

ret = ddsrt_strtod(nptr, endptr, &dbl);
*fltptr = (float)dbl;
return ret;
}

int
ddsrt_dtostr(double src, char *str, size_t size)
{
Expand Down
56 changes: 35 additions & 21 deletions src/ddsrt/src/xmlparser.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,27 +377,41 @@ static void discard_payload (struct ddsrt_xmlp_state *st)
st->tpescp = 0;
}

static int append_to_payload (struct ddsrt_xmlp_state *st, int c, int islit)
static dds_return_t append_to_payload (struct ddsrt_xmlp_state *st, int c)
{
if (!islit) {
st->tp[st->tpp++] = (char) c;
} else {
if (st->tpescp < st->tpp) {
size_t n = st->tpp - st->tpescp;
if (unescape_insitu (st->tp + st->tpescp, &n) < 0) {
discard_payload (st);
return -1;
}
st->tpp = st->tpescp + n;
}
st->tp[st->tpp++] = (char) c;
st->tpescp = st->tpp;
}
st->tp[st->tpp++] = (char) c;
if (st->tpp == st->tpsz) {
st->tpsz += 1024;
st->tp = ddsrt_realloc (st->tp, st->tpsz);
void *tp_realloc = ddsrt_realloc_s (st->tp, st->tpsz);
if (tp_realloc == NULL) {
return DDS_RETCODE_OUT_OF_RESOURCES;
} else {
st->tp = tp_realloc;
}
}

return DDS_RETCODE_OK;
}

static int append_to_payload_no_unescape (struct ddsrt_xmlp_state *st, int c)
{
if (st->tpescp < st->tpp) {
size_t n = st->tpp - st->tpescp;
if (unescape_insitu (st->tp + st->tpescp, &n) < 0) {
discard_payload (st);
return -1;
}
st->tpp = st->tpescp + n;
}
int result = append_to_payload (st, c);
st->tpescp = st->tpp;

if (result < 0) {
discard_payload (st);
return -1;
} else {
return 0;
}
return 0;
}

static int save_payload (char **payload, struct ddsrt_xmlp_state *st, int trim)
Expand Down Expand Up @@ -444,7 +458,7 @@ static int save_payload (char **payload, struct ddsrt_xmlp_state *st, int trim)
static int next_token_ident (struct ddsrt_xmlp_state *st, char **payload)
{
while (qq_isidentcont (peek_char (st))) {
if (append_to_payload (st, next_char (st), 0) < 0) {
if (append_to_payload (st, next_char(st)) < 0) {
return TOK_ERROR;
}
}
Expand Down Expand Up @@ -483,7 +497,7 @@ static int next_token_string (struct ddsrt_xmlp_state *st, char **payload, const
{
/* positioned at first character of string */
while (!peek_chars (st, endm, 0) && peek_char (st) != TOK_EOF) {
if (append_to_payload (st, next_char (st), 0) < 0) {
if (append_to_payload (st, next_char (st)) < 0) {
return TOK_ERROR;
}
}
Expand Down Expand Up @@ -673,15 +687,15 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo)
do {
/* gobble up content until EOF or markup */
while (peek_char (st) != '<' && peek_char (st) != TOK_EOF) {
if (append_to_payload (st, next_char (st), 0) < 0) {
if (append_to_payload (st, next_char (st)) < 0) {
PE_LOCAL_ERROR ("invalid character sequence", 0);
}
}
/* if the mark-up happens to be a CDATA, consume it, and gobble up characters
until the closing marker is reached, which then also gets consumed */
if (peek_chars (st, cdata_magic, 1)) {
while (!peek_chars (st, "]]>", 1) && peek_char (st) != TOK_EOF) {
if (append_to_payload (st, next_char (st), 1) < 0) {
if (append_to_payload_no_unescape (st, next_char (st)) < 0) {
PE_LOCAL_ERROR ("invalid character sequence", 0);
}
}
Expand Down

0 comments on commit 7df82fb

Please sign in to comment.