libobs: Use locale-independent double conversion
Prevents issues on specific locales, especially where decimal points are represented by commas rather than periods.
This commit is contained in:
parent
4abae186ce
commit
d44d3b1f0a
@ -16,6 +16,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include "../util/platform.h"
|
||||
#include "effect-parser.h"
|
||||
#include "effect.h"
|
||||
|
||||
@ -735,7 +736,7 @@ static inline int ep_parse_param_assign_intfloat(struct effect_parser *ep,
|
||||
return code;
|
||||
|
||||
if (is_float) {
|
||||
float f = (float)strtod(ep->cfp.cur_token->str.array, NULL);
|
||||
float f = (float)os_strtod(ep->cfp.cur_token->str.array);
|
||||
if (is_negative) f = -f;
|
||||
da_push_back_array(param->default_val, &f, sizeof(float));
|
||||
} else {
|
||||
|
@ -15,6 +15,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "../util/platform.h"
|
||||
#include "shader-parser.h"
|
||||
|
||||
enum gs_shader_param_type get_shader_param_type(const char *type)
|
||||
@ -489,7 +490,7 @@ static inline int sp_parse_param_assign_intfloat(struct shader_parser *sp,
|
||||
return code;
|
||||
|
||||
if (is_float) {
|
||||
float f = (float)strtod(sp->cfp.cur_token->str.array, NULL);
|
||||
float f = (float)os_strtod(sp->cfp.cur_token->str.array);
|
||||
if (is_negative) f = -f;
|
||||
da_push_back_array(param->default_val, &f, sizeof(float));
|
||||
} else {
|
||||
|
@ -472,10 +472,9 @@ void config_set_bool(config_t *config, const char *section,
|
||||
void config_set_double(config_t *config, const char *section,
|
||||
const char *name, double value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%g", value);
|
||||
config_set_item(&config->sections, section, name, str.array);
|
||||
char *str = bzalloc(64);
|
||||
os_dtostr(value, str, 64);
|
||||
config_set_item(&config->sections, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_default_string(config_t *config, const char *section,
|
||||
@ -591,7 +590,7 @@ double config_get_double(const config_t *config, const char *section,
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return strtod(value, NULL);
|
||||
return os_strtod(value);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
@ -644,7 +643,7 @@ double config_get_default_double(const config_t *config, const char *section,
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
if (value)
|
||||
return strtod(value, NULL);
|
||||
return os_strtod(value);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
#include "c99defs.h"
|
||||
#include "platform.h"
|
||||
#include "bmem.h"
|
||||
@ -414,3 +415,100 @@ size_t os_mbs_to_utf8_ptr(const char *str, size_t len, char **pstr)
|
||||
*pstr = dst;
|
||||
return out_len;
|
||||
}
|
||||
|
||||
/* locale independent double conversion from jansson, credit goes to them */
|
||||
|
||||
static inline void to_locale(char *str)
|
||||
{
|
||||
const char *point;
|
||||
char *pos;
|
||||
|
||||
point = localeconv()->decimal_point;
|
||||
if(*point == '.') {
|
||||
/* No conversion needed */
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strchr(str, '.');
|
||||
if(pos)
|
||||
*pos = *point;
|
||||
}
|
||||
|
||||
static inline void from_locale(char *buffer)
|
||||
{
|
||||
const char *point;
|
||||
char *pos;
|
||||
|
||||
point = localeconv()->decimal_point;
|
||||
if(*point == '.') {
|
||||
/* No conversion needed */
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strchr(buffer, *point);
|
||||
if(pos)
|
||||
*pos = '.';
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
double os_strtod(const char *str)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, 64, "%s", str);
|
||||
to_locale(buf);
|
||||
return strtod(buf, NULL);
|
||||
}
|
||||
|
||||
int os_dtostr(double value, char *dst, size_t size)
|
||||
{
|
||||
int ret;
|
||||
char *start, *end;
|
||||
size_t length;
|
||||
|
||||
ret = snprintf(dst, size, "%.17g", value);
|
||||
if(ret < 0)
|
||||
return -1;
|
||||
|
||||
length = (size_t)ret;
|
||||
if(length >= size)
|
||||
return -1;
|
||||
|
||||
from_locale(dst);
|
||||
|
||||
/* Make sure there's a dot or 'e' in the output. Otherwise
|
||||
a real is converted to an integer when decoding */
|
||||
if(strchr(dst, '.') == NULL && strchr(dst, 'e') == NULL) {
|
||||
if(length + 3 >= size) {
|
||||
/* No space to append ".0" */
|
||||
return -1;
|
||||
}
|
||||
dst[length] = '.';
|
||||
dst[length + 1] = '0';
|
||||
dst[length + 2] = '\0';
|
||||
length += 2;
|
||||
}
|
||||
|
||||
/* Remove leading '+' from positive exponent. Also remove leading
|
||||
zeros from exponents (added by some printf() implementations) */
|
||||
start = strchr(dst, 'e');
|
||||
if(start) {
|
||||
start++;
|
||||
end = start + 1;
|
||||
|
||||
if(*start == '-')
|
||||
start++;
|
||||
|
||||
while(*end == '0')
|
||||
end++;
|
||||
|
||||
if(end != start) {
|
||||
memmove(start, end, length - (size_t)(end - dst));
|
||||
length -= (size_t)(end - start);
|
||||
}
|
||||
}
|
||||
|
||||
return (int)length;
|
||||
}
|
||||
|
@ -65,6 +65,9 @@ EXPORT size_t os_wcs_to_utf8_ptr(const wchar_t *str, size_t len, char **pstr);
|
||||
EXPORT size_t os_utf8_to_mbs_ptr(const char *str, size_t len, char **pstr);
|
||||
EXPORT size_t os_mbs_to_utf8_ptr(const char *str, size_t len, char **pstr);
|
||||
|
||||
EXPORT double os_strtod(const char *str);
|
||||
EXPORT int os_dtostr(double value, char *dst, size_t size);
|
||||
|
||||
EXPORT void *os_dlopen(const char *path);
|
||||
EXPORT void *os_dlsym(void *module, const char *func);
|
||||
EXPORT void os_dlclose(void *module);
|
||||
|
Loading…
x
Reference in New Issue
Block a user