diff --git a/CMakeLists.txt b/CMakeLists.txt index 43488ce..0732e7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,10 @@ foreach(TARGET ${PROJECT_NAME}_shared ${PROJECT_NAME}_static) else() target_compile_options(${TARGET} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token) endif() + + if(NOT MSVC) + target_link_libraries(${TARGET} PRIVATE m) + endif() endforeach() # Install libraries diff --git a/build.sh b/build.sh index f1b3bf8..2dac85e 100755 --- a/build.sh +++ b/build.sh @@ -4,7 +4,7 @@ set -e BUILD_DIR="BUILD" INSTALL_DIR="$(pwd)/install" -CFLAGS="-std=c99 -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token" +CFLAGS="-std=c99 -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token -lm" BUILD_SHARED=1 PTHREAD_SUPPORT=1 POSIX_SUPPORT=1 diff --git a/src/dcfg.c b/src/dcfg.c index eaff302..5819494 100644 --- a/src/dcfg.c +++ b/src/dcfg.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -65,70 +66,154 @@ void pthread_mutex_unlock(pthread_mutex_t *); int64_t dcfg_strtoll(const char *s, char **end, int base) { - size_t n = strlen(s); - char *clean = malloc(n + 1); - if (!clean) { - errno = ENOMEM; + char const *p = s; + while (isspace((unsigned char)*p)) + p++; + bool neg = false; + if (*p == '+' || *p == '-') { + neg = (*p == '-'); + p++; + } + + if (base == 0) { + if (*p == '0') { + if (p[1] == 'x' || p[1] == 'X') { + base = 16; + p += 2; + } else { + base = 8; + p++; + } + } else { + base = 10; + } + } else if (base == 16 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + } + + int64_t val = 0; + char const *q = p, *last = p; + while (*q) { + char c = *q; + if (c == '_' || c == '\'') { + q++; + continue; + } + int d; + if (c >= '0' && c <= '9') + d = c - '0'; + else if (c >= 'a' && c <= 'z') + d = c - 'a' + 10; + else if (c >= 'A' && c <= 'Z') + d = c - 'A' + 10; + else + break; + if (d >= base) + break; + val = val * base + d; + last = q + 1; + q++; + } + if (last == p) { if (end) *end = (char *)s; return 0; } - - size_t w = 0; - for (size_t r = 0; r < n && s[r]; ++r) - if (s[r] != '_' && s[r] != '\'') - clean[w++] = s[r]; - clean[w] = '\0'; - - char *tmp_end; - int64_t v = strtoll(clean, &tmp_end, base); - - if (end) { - size_t consumed = (size_t)(tmp_end - clean); - size_t i = 0, c = 0; - while (i < n && c < consumed) { - if (s[i] != '_' && s[i] != '\'') - ++c; - ++i; - } - *end = (char *)s + i; - } - free(clean); - return v; + if (end) + *end = (char *)last; + return neg ? -val : val; } double dcfg_strtod(char const *s, char **end) { - size_t n = strlen(s); - char *clean = malloc(n + 1); - if (!clean) { - errno = ENOMEM; + char const *p = s; + while (isspace((unsigned char)*p)) + p++; + bool neg = false; + if (*p == '+' || *p == '-') { + neg = (*p == '-'); + p++; + } + + char const *fd = strchr(p, '.'); + char const *fc = strchr(p, ','); + char dec = '.'; + if (!fd && fc) + dec = ','; + else if (fd && fc && fc < fd) + dec = ','; + + int64_t ip = 0; + double frac = 0.0, div = 1.0; + bool any = false, in_frac = false; + bool in_exp = false, exp_any = false; + int exp_sign = 1, exp_val = 0; + char const *last = p; + size_t i = p - s; + + for (;; ++i) { + char c = s[i]; + if (!c) + break; + if (!in_exp) { + if (c == '_' || c == '\'') + continue; + if (!in_frac && c == dec) { + in_frac = true; + last = s + i + 1; + continue; + } + if (!in_frac && (c == '.' || c == ',')) + continue; + if (c >= '0' && c <= '9') { + any = true; + int d = c - '0'; + if (!in_frac) + ip = ip * 10 + d; + else { + frac = frac * 10 + d; + div *= 10.0; + } + last = s + i + 1; + continue; + } + if ((c == 'e' || c == 'E') && any) { + in_exp = true; + last = s + i + 1; + continue; + } + break; + } else { + if ((c == '+' || c == '-') && !exp_any) { + if (c == '-') + exp_sign = -1; + last = s + i + 1; + continue; + } + if (c >= '0' && c <= '9') { + exp_any = true; + exp_val = exp_val * 10 + (c - '0'); + last = s + i + 1; + continue; + } + break; + } + } + + if (!any) { if (end) *end = (char *)s; return 0.0; } - size_t w = 0; - for (size_t r = 0; r < n && s[r]; ++r) - if (s[r] != '_' && s[r] != '\'') - clean[w++] = s[r]; - clean[w] = '\0'; - - char *tmp_end; - double v = strtod(clean, &tmp_end); - - if (end) { - size_t consumed = (size_t)(tmp_end - clean); - size_t i = 0, c = 0; - while (i < n && c < consumed) { - if (s[i] != '_' && s[i] != '\'') - ++c; - ++i; - } - *end = (char *)s + i; - } - free(clean); - return v; + double result = (double)ip + frac / div; + if (in_exp && exp_any) + result *= pow(10.0, exp_sign * exp_val); + if (neg) + result = -result; + if (end) + *end = (char *)last; + return result; } typedef dcfg_Value Value; @@ -526,7 +611,7 @@ static void skip_ws_and_comments(Lexer *lx) while (lx->ch != -1) { if (lx->ch == '*' && lx->next == '/') { lex_advance(lx); - lex_advance(lx); /* / */ + lex_advance(lx); break; } lex_advance(lx); @@ -575,7 +660,7 @@ static Token lex_number(Lexer *lx) while (isdigit_cp(lx->ch) || lx->ch == '_' || lx->ch == '\'') lex_advance(lx); - if (lx->ch == '.') { + if (lx->ch == '.' || lx->ch == ',') { real = true; lex_advance(lx); while (isdigit_cp(lx->ch) || lx->ch == '_' || lx->ch == '\'') @@ -1449,7 +1534,7 @@ dcfg_ValueType dcfg_Value_type_ex(dcfg_Value *value, bool evaluate) { if (!value) return dcfg_ValueType_Nil; - (void)evaluate; /* eval ignored for now */ + (void)evaluate; return value->type; }