diff options
author | Valentin Bartenev <vbart@nginx.com> | 2020-03-30 19:37:58 +0300 |
---|---|---|
committer | Valentin Bartenev <vbart@nginx.com> | 2020-03-30 19:37:58 +0300 |
commit | 68c6b67ffc840c78eddd27a65e9bf1370aaf5631 (patch) | |
tree | e53b36a7d4f40976daf52fe7c644c2d311bbb83b | |
parent | 0935630cba069d6619e967404bb6c7c2a93fbe7e (diff) | |
download | unit-68c6b67ffc840c78eddd27a65e9bf1370aaf5631.tar.gz unit-68c6b67ffc840c78eddd27a65e9bf1370aaf5631.tar.bz2 |
Configuration: support for rational numbers.
Diffstat (limited to '')
-rw-r--r-- | src/nxt_conf.c | 257 | ||||
-rw-r--r-- | src/nxt_conf.h | 2 | ||||
-rw-r--r-- | src/nxt_conf_validation.c | 14 | ||||
-rw-r--r-- | src/nxt_errno.h | 1 | ||||
-rw-r--r-- | src/nxt_http_route.c | 2 | ||||
-rw-r--r-- | src/nxt_string.c | 18 | ||||
-rw-r--r-- | src/nxt_string.h | 5 | ||||
-rw-r--r-- | src/test/nxt_clone_test.c | 6 |
8 files changed, 135 insertions, 170 deletions
diff --git a/src/nxt_conf.c b/src/nxt_conf.c index 3e1130be..7f09dac9 100644 --- a/src/nxt_conf.c +++ b/src/nxt_conf.c @@ -7,13 +7,13 @@ #include <nxt_main.h> #include <nxt_conf.h> -#if 0 -#include <math.h> + #include <float.h> -#endif +#include <math.h> #define NXT_CONF_MAX_SHORT_STRING 14 +#define NXT_CONF_MAX_NUMBER_LEN 14 #define NXT_CONF_MAX_STRING NXT_INT32_T_MAX #define NXT_CONF_MAX_TOKEN_LEN 256 @@ -46,8 +46,7 @@ typedef struct nxt_conf_object_s nxt_conf_object_t; struct nxt_conf_value_s { union { uint8_t boolean; /* 1 bit. */ - int64_t integer; - double number; + u_char number[NXT_CONF_MAX_NUMBER_LEN + 1];; struct { u_char start[NXT_CONF_MAX_SHORT_STRING]; @@ -130,8 +129,6 @@ static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, nxt_conf_value_t *src); -static size_t nxt_conf_json_integer_length(nxt_conf_value_t *value); -static u_char *nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value); static size_t nxt_conf_json_string_length(nxt_conf_value_t *value); static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value); static size_t nxt_conf_json_array_length(nxt_conf_value_t *value, @@ -221,10 +218,10 @@ nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str) } -int64_t -nxt_conf_get_integer(nxt_conf_value_t *value) +double +nxt_conf_get_number(nxt_conf_value_t *value) { - return value->u.integer; + return nxt_strtod(value->u.number, NULL); } @@ -312,13 +309,19 @@ void nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name, int64_t value, uint32_t index) { + u_char *p, *end; nxt_conf_object_member_t *member; member = &object->u.object->members[index]; nxt_conf_set_string(&member->name, name); - member->value.u.integer = value; + p = member->value.u.number; + end = p + NXT_CONF_MAX_NUMBER_LEN; + + end = nxt_sprintf(p, end, "%L", value); + *end = '\0'; + member->value.type = NXT_CONF_VALUE_INTEGER; } @@ -551,6 +554,7 @@ nxt_int_t nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, nxt_uint_t n, void *data) { + double num; nxt_str_t str, *s; nxt_uint_t i; nxt_conf_value_t *v; @@ -600,30 +604,32 @@ nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, break; } + num = nxt_strtod(v->u.number, NULL); + switch (map[i].type) { case NXT_CONF_MAP_INT32: - ptr->i32 = v->u.integer; + ptr->i32 = num; break; case NXT_CONF_MAP_INT64: - ptr->i64 = v->u.integer; + ptr->i64 = num; break; case NXT_CONF_MAP_INT: - ptr->i = v->u.integer; + ptr->i = num; break; case NXT_CONF_MAP_SIZE: - ptr->size = v->u.integer; + ptr->size = num; break; case NXT_CONF_MAP_OFF: - ptr->off = v->u.integer; + ptr->off = num; break; case NXT_CONF_MAP_MSEC: - ptr->msec = v->u.integer * 1000; + ptr->msec = (nxt_msec_t) num * 1000; break; default: @@ -635,11 +641,7 @@ nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, case NXT_CONF_MAP_DOUBLE: if (v->type == NXT_CONF_VALUE_NUMBER) { - ptr->dbl = v->u.number; - - } else if (v->type == NXT_CONF_VALUE_INTEGER) { - ptr->dbl = v->u.integer; - + ptr->dbl = nxt_strtod(v->u.number, NULL); } break; @@ -2036,56 +2038,51 @@ static u_char * nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, u_char *end, nxt_conf_json_error_t *error) { - u_char *p, ch; - uint64_t integer; - nxt_int_t sign; -#if 0 - uint64_t frac, power - nxt_int_t e, negative; -#endif - - static const uint64_t cutoff = NXT_INT64_T_MAX / 10; - static const uint64_t cutlim = NXT_INT64_T_MAX % 10; + u_char *p, *s, ch, c, *dot_pos; + size_t size; + double num; - ch = *start; + s = start; + ch = *s; if (ch == '-') { - sign = -1; - start++; - - } else { - sign = 1; + s++; } - integer = 0; + dot_pos = NULL; - for (p = start; nxt_fast_path(p != end); p++) { + for (p = s; nxt_fast_path(p != end); p++) { ch = *p; /* Values below '0' become >= 208. */ - ch = ch - '0'; + c = ch - '0'; + + if (c > 9) { + if (ch == '.' && nxt_fast_path(dot_pos == NULL)) { + dot_pos = p; + continue; + } - if (ch > 9) { break; } + } - if (nxt_slow_path(integer >= cutoff - && (integer > cutoff || ch > cutlim))) - { - nxt_conf_json_parse_error(error, start, - "The integer is too large. Such a large JSON integer value " - "is not supported." + if (dot_pos != NULL) { + if (nxt_slow_path(p - dot_pos <= 1)) { + nxt_conf_json_parse_error(error, s, + "The number is invalid. A fraction part in JSON numbers " + "must contain at least one digit." ); return NULL; } - integer = integer * 10 + ch; + } else { + dot_pos = p; } - if (nxt_slow_path(p - start > 1 && *start == '0')) { - - nxt_conf_json_parse_error(error, start, + if (nxt_slow_path(dot_pos - s > 1 && *start == '0')) { + nxt_conf_json_parse_error(error, s, "The number is invalid. Leading zeros are not allowed in JSON " "numbers." ); @@ -2093,101 +2090,77 @@ nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, return NULL; } - if (ch != '.') { - value->type = NXT_CONF_VALUE_INTEGER; - value->u.integer = sign * integer; - return p; - } + if (ch == 'e' || ch == 'E') { + p++; + s = p; -#if 0 - start = p + 1; + if (nxt_fast_path(s != end)) { + ch = *s; - frac = 0; - power = 1; + if (ch == '-' || ch == '+') { + s++; + } - for (p = start; nxt_fast_path(p != end); p++) { - ch = *p; + for (p = s; nxt_fast_path(p != end); p++) { + ch = *p; - /* Values below '0' become >= 208. */ - ch = ch - '0'; + /* Values below '0' become >= 208. */ + c = ch - '0'; - if (ch > 9) { - break; + if (c > 9) { + break; + } + } } - if (nxt_slow_path((frac >= cutoff && (frac > cutoff || ch > cutlim)) - || power > cutoff)) - { + if (nxt_slow_path(p == s)) { + nxt_conf_json_parse_error(error, start, + "The number is invalid. An exponent part in JSON numbers " + "must contain at least one digit." + ); + return NULL; } - - frac = frac * 10 + ch; - power *= 10; } - if (nxt_slow_path(p == start)) { - return NULL; - } - - value->type = NXT_CONF_VALUE_NUMBER; - value->u.number = integer + (double) frac / power; - - value->u.number = copysign(value->u.number, sign); - - if (ch == 'e' || ch == 'E') { - start = p + 1; + size = p - start; - ch = *start; - - if (ch == '-' || ch == '+') { - start++; - } - - negative = (ch == '-') ? 1 : 0; - e = 0; + if (size > NXT_CONF_MAX_NUMBER_LEN) { + nxt_conf_json_parse_error(error, start, + "The number is too long. Such a long JSON number value " + "is not supported." + ); - for (p = start; nxt_fast_path(p != end); p++) { - ch = *p; + return NULL; + } - /* Values below '0' become >= 208. */ - ch = ch - '0'; + nxt_memcpy(value->u.number, start, size); + value->u.number[size] = '\0'; - if (ch > 9) { - break; - } + nxt_errno = 0; + end = NULL; - e = e * 10 + ch; + num = nxt_strtod(value->u.number, &end); - if (nxt_slow_path(e > DBL_MAX_10_EXP)) { - return NULL; - } - } - - if (nxt_slow_path(p == start)) { - return NULL; - } - - if (negative) { - value->u.number /= exp10(e); + if (nxt_slow_path(nxt_errno == NXT_ERANGE || fabs(num) > NXT_INT64_T_MAX)) { + nxt_conf_json_parse_error(error, start, + "The number is out of representable range. Such JSON number " + "value is not supported." + ); - } else { - value->u.number *= exp10(e); - } + return NULL; } - if (nxt_fast_path(isfinite(value->u.number))) { - return p; + if (nxt_slow_path(end == NULL || *end != '\0')) { + nxt_thread_log_alert("strtod(\"%s\", %s) failed %E", value->u.number, + end == NULL ? (u_char *) "NULL" : end, nxt_errno); + return NULL; } -#else - nxt_conf_json_parse_error(error, start, - "The number is not an integer. JSON numbers with decimals and " - "exponents are not supported." - ); - -#endif + value->type = (num == trunc(num)) ? NXT_CONF_VALUE_INTEGER + : NXT_CONF_VALUE_NUMBER; - return NULL; + return p; } @@ -2216,11 +2189,8 @@ nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty) return value->u.boolean ? nxt_length("true") : nxt_length("false"); case NXT_CONF_VALUE_INTEGER: - return nxt_conf_json_integer_length(value); - case NXT_CONF_VALUE_NUMBER: - /* TODO */ - return 0; + return nxt_strlen(value->u.number); case NXT_CONF_VALUE_SHORT_STRING: case NXT_CONF_VALUE_STRING: @@ -2253,11 +2223,8 @@ nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, : nxt_cpymem(p, "false", 5); case NXT_CONF_VALUE_INTEGER: - return nxt_conf_json_print_integer(p, value); - case NXT_CONF_VALUE_NUMBER: - /* TODO */ - return p; + return nxt_cpystr(p, value->u.number); case NXT_CONF_VALUE_SHORT_STRING: case NXT_CONF_VALUE_STRING: @@ -2277,32 +2244,6 @@ nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, static size_t -nxt_conf_json_integer_length(nxt_conf_value_t *value) -{ - int64_t num; - - num = llabs(value->u.integer); - - if (num <= 9999) { - return nxt_length("-9999"); - } - - if (num <= 99999999999LL) { - return nxt_length("-99999999999"); - } - - return NXT_INT64_T_LEN; -} - - -static u_char * -nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value) -{ - return nxt_sprintf(p, p + NXT_INT64_T_LEN, "%L", value->u.integer); -} - - -static size_t nxt_conf_json_string_length(nxt_conf_value_t *value) { nxt_str_t str; diff --git a/src/nxt_conf.h b/src/nxt_conf.h index 66201fee..201a3a14 100644 --- a/src/nxt_conf.h +++ b/src/nxt_conf.h @@ -114,7 +114,7 @@ NXT_EXPORT void nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str); NXT_EXPORT void nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str); NXT_EXPORT nxt_int_t nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str); -NXT_EXPORT int64_t nxt_conf_get_integer(nxt_conf_value_t *value); +NXT_EXPORT double nxt_conf_get_number(nxt_conf_value_t *value); NXT_EXPORT uint8_t nxt_conf_get_boolean(nxt_conf_value_t *value); // FIXME reimplement and reorder functions below diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 3227a7e9..aa48845a 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -17,7 +17,7 @@ typedef enum { NXT_CONF_VLDT_NULL = 1 << NXT_CONF_NULL, NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN, NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER, - NXT_CONF_VLDT_NUMBER = 1 << NXT_CONF_NUMBER, + NXT_CONF_VLDT_NUMBER = (1 << NXT_CONF_NUMBER) | NXT_CONF_VLDT_INTEGER, NXT_CONF_VLDT_STRING = 1 << NXT_CONF_STRING, NXT_CONF_VLDT_ARRAY = 1 << NXT_CONF_ARRAY, NXT_CONF_VLDT_OBJECT = 1 << NXT_CONF_OBJECT, @@ -773,8 +773,8 @@ nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name, static nxt_str_t type_name[] = { nxt_string("a null"), nxt_string("a boolean"), - nxt_string("an integer"), - nxt_string("a number"), + nxt_string("an integer number"), + nxt_string("a fractional number"), nxt_string("a string"), nxt_string("an array"), nxt_string("an object"), @@ -1138,7 +1138,7 @@ nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, { int64_t status; - status = nxt_conf_get_integer(value); + status = nxt_conf_get_number(value); if (status < NXT_HTTP_INVALID || status > NXT_HTTP_STATUS_MAX) { return nxt_conf_vldt_error(vldt, "The \"return\" value is out of " @@ -1626,8 +1626,8 @@ nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, nxt_int_t ret; nxt_conf_vldt_processes_conf_t proc; - if (nxt_conf_type(value) == NXT_CONF_INTEGER) { - int_value = nxt_conf_get_integer(value); + if (nxt_conf_type(value) == NXT_CONF_NUMBER) { + int_value = nxt_conf_get_number(value); if (int_value < 1) { return nxt_conf_vldt_error(vldt, "The \"processes\" number must be " @@ -2062,7 +2062,7 @@ nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, { int64_t int_value; - int_value = nxt_conf_get_integer(value); + int_value = nxt_conf_get_number(value); if (int_value <= 0) { return nxt_conf_vldt_error(vldt, "The \"weight\" number must be " diff --git a/src/nxt_errno.h b/src/nxt_errno.h index 1b29ef2f..40bcfa3f 100644 --- a/src/nxt_errno.h +++ b/src/nxt_errno.h @@ -47,6 +47,7 @@ typedef int nxt_err_t; #define NXT_ETIME ETIME #define NXT_ENOMOREFILES 0 #define NXT_ENOBUFS ENOBUFS +#define NXT_ERANGE ERANGE #if (NXT_HPUX) /* HP-UX uses EWOULDBLOCK instead of EAGAIN. */ diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index ee22f48d..ca43c060 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -630,7 +630,7 @@ nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv, if (accf.ret != NULL) { action->handler = nxt_http_return_handler; - action->u.return_code = nxt_conf_get_integer(accf.ret); + action->u.return_code = nxt_conf_get_number(accf.ret); if (accf.location.length > 0) { if (nxt_is_complex_uri_encoded(accf.location.start, diff --git a/src/nxt_string.c b/src/nxt_string.c index 667146d6..54f96abc 100644 --- a/src/nxt_string.c +++ b/src/nxt_string.c @@ -110,6 +110,24 @@ nxt_memcpy_upcase(u_char *dst, const u_char *src, size_t length) u_char * +nxt_cpystr(u_char *dst, const u_char *src) +{ + for ( ;; ) { + *dst = *src; + + if (*dst == '\0') { + break; + } + + dst++; + src++; + } + + return dst; +} + + +u_char * nxt_cpystrn(u_char *dst, const u_char *src, size_t length) { if (length == 0) { diff --git a/src/nxt_string.h b/src/nxt_string.h index d10658f7..7863c60e 100644 --- a/src/nxt_string.h +++ b/src/nxt_string.h @@ -20,6 +20,10 @@ nxt_upcase(c) \ nxt_isdigit(c) \ ((u_char) ((c) - '0') <= 9) +#define \ +nxt_strtod(s, endptr) \ + strtod((char *) s, (char **) endptr) + #define \ nxt_strlen(s) \ @@ -83,6 +87,7 @@ nxt_strncmp(s1, s2, length) \ strncmp((char *) s1, (char *) s2, length) +NXT_EXPORT u_char *nxt_cpystr(u_char *dst, const u_char *src); NXT_EXPORT u_char *nxt_cpystrn(u_char *dst, const u_char *src, size_t length); NXT_EXPORT nxt_int_t nxt_strcasecmp(const u_char *s1, const u_char *s2); NXT_EXPORT nxt_int_t nxt_strncasecmp(const u_char *s1, const u_char *s2, diff --git a/src/test/nxt_clone_test.c b/src/test/nxt_clone_test.c index 15d36557..64b9ddea 100644 --- a/src/test/nxt_clone_test.c +++ b/src/test/nxt_clone_test.c @@ -588,13 +588,13 @@ nxt_clone_test_parse_map(nxt_task_t *task, nxt_str_t *map_str, obj = nxt_conf_get_array_element(array, i); value = nxt_conf_get_object_member(obj, &host_name, NULL); - map->map[i].host = nxt_conf_get_integer(value); + map->map[i].host = nxt_conf_get_number(value); value = nxt_conf_get_object_member(obj, &cont_name, NULL); - map->map[i].container = nxt_conf_get_integer(value); + map->map[i].container = nxt_conf_get_number(value); value = nxt_conf_get_object_member(obj, &size_name, NULL); - map->map[i].size = nxt_conf_get_integer(value); + map->map[i].size = nxt_conf_get_number(value); } return NXT_OK; |