diff options
author | Valentin Bartenev <vbart@nginx.com> | 2017-10-05 16:46:18 +0300 |
---|---|---|
committer | Valentin Bartenev <vbart@nginx.com> | 2017-10-05 16:46:18 +0300 |
commit | 096562c0b14656354fcb0eb7b7c6d524f5fb1f1d (patch) | |
tree | efd6dd7b94951778e132d84591d77ae8d7ecf469 | |
parent | 653e9854637e129cd6a92adaff96784220165eea (diff) | |
download | unit-096562c0b14656354fcb0eb7b7c6d524f5fb1f1d.tar.gz unit-096562c0b14656354fcb0eb7b7c6d524f5fb1f1d.tar.bz2 |
Improved applications versions handling.
-rw-r--r-- | auto/sources | 1 | ||||
-rw-r--r-- | src/nxt_application.c | 12 | ||||
-rw-r--r-- | src/nxt_application.h | 2 | ||||
-rw-r--r-- | src/nxt_main_process.c | 15 | ||||
-rw-r--r-- | src/nxt_runtime.c | 2 | ||||
-rw-r--r-- | src/nxt_string.c | 120 | ||||
-rw-r--r-- | src/nxt_string.h | 9 | ||||
-rw-r--r-- | test/nxt_strverscmp_test.c | 94 | ||||
-rw-r--r-- | test/nxt_tests.c | 4 | ||||
-rw-r--r-- | test/nxt_tests.h | 1 |
10 files changed, 244 insertions, 16 deletions
diff --git a/auto/sources b/auto/sources index f2760ad6..473fe2f3 100644 --- a/auto/sources +++ b/auto/sources @@ -218,6 +218,7 @@ NXT_TEST_SRCS=" \ test/nxt_utf8_test.c \ test/nxt_rbtree1_test.c \ test/nxt_http_parse_test.c \ + test/nxt_strverscmp_test.c \ " NXT_LIB_UTF8_FILE_NAME_TEST_SRCS=" \ diff --git a/src/nxt_application.c b/src/nxt_application.c index 36e855b8..2ecec636 100644 --- a/src/nxt_application.c +++ b/src/nxt_application.c @@ -291,8 +291,8 @@ nxt_app_start(nxt_task_t *task, void *data) nxt_app = lang->module; if (nxt_app == NULL) { - nxt_debug(task, "application language module: %V \"%s\"", - &lang->version, lang->file); + nxt_debug(task, "application language module: %s \"%s\"", + lang->version, lang->file); nxt_app = nxt_app_module_load(task, lang->file); } @@ -1020,8 +1020,14 @@ nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name) n = rt->languages->nelts; for (i = 0; i < n; i++) { + + /* + * Versions are sorted in descending order + * so first match chooses the highest version. + */ + if (nxt_str_eq(&lang[i].type, name->start, type_length) - && nxt_str_start(&lang[i].version, version, version_length)) + && nxt_strvers_match(lang[i].version, version, version_length)) { return &lang[i]; } diff --git a/src/nxt_application.h b/src/nxt_application.h index 02e7edeb..5561d854 100644 --- a/src/nxt_application.h +++ b/src/nxt_application.h @@ -24,7 +24,7 @@ typedef struct nxt_app_module_s nxt_app_module_t; typedef struct { nxt_str_t type; - nxt_str_t version; + u_char *version; char *file; nxt_application_module_t *module; } nxt_app_lang_module_t; diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c index ba916abf..4a185a54 100644 --- a/src/nxt_main_process.c +++ b/src/nxt_main_process.c @@ -1010,7 +1010,7 @@ static nxt_conf_map_t nxt_app_lang_module_map[] = { { nxt_string("version"), - NXT_CONF_MAP_STR_COPY, + NXT_CONF_MAP_CSTRZ, offsetof(nxt_app_lang_module_t, version), }, @@ -1091,8 +1091,8 @@ nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) goto fail; } - nxt_debug(task, "lang %V %V \"%s\"", - &lang->type, &lang->version, lang->file); + nxt_debug(task, "lang %V %s \"%s\"", + &lang->type, lang->version, lang->file); } qsort(rt->languages->elts, rt->languages->nelts, @@ -1114,7 +1114,6 @@ static int nxt_cdecl nxt_app_lang_compare(const void *v1, const void *v2) { int n; - size_t length; const nxt_app_lang_module_t *lang1, *lang2; lang1 = v1; @@ -1130,13 +1129,7 @@ nxt_app_lang_compare(const void *v1, const void *v2) return n; } - length = nxt_min(lang1->version.length, lang2->version.length); - - n = nxt_strncmp(lang1->version.start, lang2->version.start, length); - - if (n == 0) { - n = lang1->version.length - lang2->version.length; - } + n = nxt_strverscmp(lang1->version, lang2->version); /* Negate result to move higher versions to the beginning. */ diff --git a/src/nxt_runtime.c b/src/nxt_runtime.c index b1b80865..168f4f19 100644 --- a/src/nxt_runtime.c +++ b/src/nxt_runtime.c @@ -91,7 +91,7 @@ nxt_runtime_create(nxt_task_t *task) /* Should not fail. */ lang = nxt_array_add(rt->languages); lang->type = (nxt_str_t) nxt_string("go"); - lang->version = (nxt_str_t) nxt_null_string; + lang->version = (u_char *) ""; lang->file = NULL; lang->module = &nxt_go_module; diff --git a/src/nxt_string.c b/src/nxt_string.c index 4690851c..28b9f887 100644 --- a/src/nxt_string.c +++ b/src/nxt_string.c @@ -315,3 +315,123 @@ nxt_str_strip(u_char *start, u_char *end) return (p + 1) - start; } + + +nxt_int_t +nxt_strverscmp(const u_char *s1, const u_char *s2) +{ + u_char c1, c2; + nxt_int_t diff; + + enum { + st_str = 0, + st_num, + st_zero, + st_frac, + } state; + + state = st_str; + + for ( ;; ) { + c1 = *s1++; + c2 = *s2++; + + diff = c1 - c2; + + if (diff != 0) { + break; + } + + if (c1 == '\0') { + return 0; + } + + if (!nxt_isdigit(c1)) { + state = st_str; + continue; + } + + if (state == st_str) { + state = (c1 != '0') ? st_num : st_zero; + continue; + } + + if (state == st_zero && c1 != '0') { + state = st_frac; + continue; + } + } + + switch (state) { + + case st_str: + + if ((u_char) (c1 - '1') > 8 || (u_char) (c2 - '1') > 8) { + return diff; + } + + c1 = *s1++; + c2 = *s2++; + + /* Fall through. */ + + case st_num: + + while (nxt_isdigit(c1) && nxt_isdigit(c2)) { + c1 = *s1++; + c2 = *s2++; + } + + if (nxt_isdigit(c1)) { + return 1; + } + + if (nxt_isdigit(c2)) { + return -1; + } + + return diff; + + case st_zero: + + if (c1 == '0' || c2 == '\0') { + return -1; + } + + if (c2 == '0' || c1 == '\0') { + return 1; + } + + /* Fall through. */ + + case st_frac: + return diff; + } + + nxt_unreachable(); +} + + +nxt_bool_t +nxt_strvers_match(u_char *version, u_char *prefix, size_t length) +{ + u_char next, last; + + if (nxt_strncmp(version, prefix, length) == 0) { + + next = version[length]; + + if (next == '\0') { + return 1; + } + + last = version[length - 1]; + + if (nxt_isdigit(last) != nxt_isdigit(next)) { + /* This is a version part boundary. */ + return 1; + } + } + + return 0; +} diff --git a/src/nxt_string.h b/src/nxt_string.h index 56dc18d7..2a3d55ea 100644 --- a/src/nxt_string.h +++ b/src/nxt_string.h @@ -16,6 +16,10 @@ nxt_lowcase(c) \ nxt_upcase(c) \ (u_char) ((c >= 'a' && c <= 'z') ? c & ~0x20 : c) +#define \ +nxt_isdigit(c) \ + ((u_char) ((c) - '0') <= 9) + #define NXT_CR (u_char) 13 #define NXT_LF (u_char) 10 @@ -171,4 +175,9 @@ nxt_strchr_start(s, c) \ (((s)->length != 0) && ((s)->start[0] == c)) +NXT_EXPORT nxt_int_t nxt_strverscmp(const u_char *s1, const u_char *s2); +NXT_EXPORT nxt_bool_t nxt_strvers_match(u_char *version, u_char *prefix, + size_t length); + + #endif /* _NXT_STRING_H_INCLUDED_ */ diff --git a/test/nxt_strverscmp_test.c b/test/nxt_strverscmp_test.c new file mode 100644 index 00000000..40adbfb2 --- /dev/null +++ b/test/nxt_strverscmp_test.c @@ -0,0 +1,94 @@ + +/* + * Copyright (C) NGINX, Inc. + * Copyright (C) Valentin V. Bartenev + */ + +#include <nxt_main.h> +#include "nxt_tests.h" + + +typedef struct { + const char *v1; + const char res; + const char *v2; +} nxt_strverscmp_test_t; + + +nxt_int_t +nxt_strverscmp_test(nxt_thread_t *thr) +{ + nxt_int_t ret; + nxt_uint_t i; + + static const nxt_strverscmp_test_t tests[] = { + { "word", '=', "word" }, + { "42", '=', "42" }, + { "000", '=', "000" }, + { "2", '>', "1" }, + { "2", '<', "10" }, + { "rc2", '>', "rc" }, + { "rc2", '<', "rc3" }, + { "1.13.8", '>', "1.1.9" }, + { "1.9", '<', "1.13.8" }, + { "9.9", '<', "10.0" }, + { "1", '>', "007" }, + { "2b01", '<', "2b013" }, + { "011", '>', "01" }, + { "011", '>', "01.1" }, + { "011", '>', "01+1" }, + { "011", '<', "01:1" }, + { "011", '<', "01b" }, + { "020", '>', "01b" }, + { "a0", '>', "a01" }, + { "b00", '<', "b01" }, + { "c000", '<', "c01" }, + { "000", '<', "00" }, + { "000", '<', "00a" }, + { "00.", '>', "000" }, + { "a.0", '<', "a0" }, + { "b11", '>', "b0" }, + }; + + nxt_thread_time_update(thr); + + for (i = 0; i < nxt_nitems(tests); i++) { + + ret = nxt_strverscmp((u_char *) tests[i].v1, (u_char *) tests[i].v2); + + switch (tests[i].res) { + + case '<': + if (ret < 0) { + continue; + } + + break; + + case '=': + if (ret == 0) { + continue; + } + + break; + + case '>': + if (ret > 0) { + continue; + } + + break; + } + + nxt_log_alert(thr->log, + "nxt_strverscmp() test \"%s\" %c \"%s\" failed: %i", + tests[i].v1, tests[i].res, tests[i].v2, ret); + + return NXT_ERROR; + } + + nxt_log_error(NXT_LOG_NOTICE, thr->log, + "nxt_strverscmp() test passed"); + + return NXT_OK; +} diff --git a/test/nxt_tests.c b/test/nxt_tests.c index 655192ab..7cba0f69 100644 --- a/test/nxt_tests.c +++ b/test/nxt_tests.c @@ -158,5 +158,9 @@ main(int argc, char **argv) return 1; } + if (nxt_strverscmp_test(thr) != NXT_OK) { + return 1; + } + return 0; } diff --git a/test/nxt_tests.h b/test/nxt_tests.h index 508ddbe4..be4168cf 100644 --- a/test/nxt_tests.h +++ b/test/nxt_tests.h @@ -63,6 +63,7 @@ nxt_int_t nxt_sprintf_test(nxt_thread_t *thr); nxt_int_t nxt_malloc_test(nxt_thread_t *thr); nxt_int_t nxt_utf8_test(nxt_thread_t *thr); nxt_int_t nxt_http_parse_test(nxt_thread_t *thr); +nxt_int_t nxt_strverscmp_test(nxt_thread_t *thr); #endif /* _NXT_TESTS_H_INCLUDED_ */ |