diff options
author | Werner Koch <wk@gnupg.org> | 2016-01-08 08:58:21 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2016-01-08 08:58:21 +0100 |
commit | 4d7ac43ff71fdadfd2e04621f74840a82fbe788a (patch) | |
tree | acdc15bbc063cec98d836327a8129ccbf0aaaef2 | |
parent | common: New function get_assuan_server_version. (diff) | |
download | gnupg2-4d7ac43ff71fdadfd2e04621f74840a82fbe788a.tar.xz gnupg2-4d7ac43ff71fdadfd2e04621f74840a82fbe788a.zip |
common: New function compare_version_strings.
* common/stringhelp.c (parse_version_number): New.
(parse_version_string): New.
(compare_version_strings): New.
* common/t-stringhelp.c (test_compare_version_strings): New.
(main): Call test. Return ERRCOUNT instead of 0.
--
The code for that function is based on code from libgcrypt. Similar
code is in all GnuPG related libraries this function is
a candidates for inclusion in libgpg-error.
Signed-off-by: Werner Koch <wk@gnupg.org>
-rw-r--r-- | common/stringhelp.c | 85 | ||||
-rw-r--r-- | common/stringhelp.h | 3 | ||||
-rw-r--r-- | common/t-stringhelp.c | 63 |
3 files changed, 150 insertions, 1 deletions
diff --git a/common/stringhelp.c b/common/stringhelp.c index e8b990a13..8b47a1c7b 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -1329,6 +1329,91 @@ strtokenize (const char *string, const char *delim) } + +/* Version number parsing. */ + +/* This function parses the first portion of the version number S and + stores it in *NUMBER. On success, this function returns a pointer + into S starting with the first character, which is not part of the + initial number portion; on failure, NULL is returned. */ +static const char* +parse_version_number (const char *s, int *number) +{ + int val = 0; + + if (*s == '0' && digitp (s+1)) + return NULL; /* Leading zeros are not allowed. */ + for (; digitp (s); s++) + { + val *= 10; + val += *s - '0'; + } + *number = val; + return val < 0 ? NULL : s; +} + + +/* This function breaks up the complete string-representation of the + version number S, which is of the following struture: <major + number>.<minor number>.<micro number><patch level>. The major, + minor and micro number components will be stored in *MAJOR, *MINOR + and *MICRO. + + On success, the last component, the patch level, will be returned; + in failure, NULL will be returned. */ +static const char * +parse_version_string (const char *s, int *major, int *minor, int *micro) +{ + s = parse_version_number (s, major); + if (!s || *s != '.') + return NULL; + s++; + s = parse_version_number (s, minor); + if (!s) + return NULL; + if (*s == '.') + { + s++; + s = parse_version_number (s, micro); + if (!s) + return NULL; + } + else + *micro = 0; + return s; /* Patchlevel. */ +} + + +/* Check that the version string MY_VERSION is greater or equal than + REQ_VERSION. Returns true if the condition is satisfied or false + if not. This works with 3 part and two part version strings; for a + two part version string the micor part is assumed to be 0. */ +int +compare_version_strings (const char *my_version, const char *req_version) +{ + int my_major, my_minor, my_micro; + int rq_major, rq_minor, rq_micro; + + if (!my_version || !req_version) + return 0; + + if (!parse_version_string (my_version, &my_major, &my_minor, &my_micro)) + return 0; + if (!parse_version_string(req_version, &rq_major, &rq_minor, &rq_micro)) + return 0; + + if (my_major > rq_major + || (my_major == rq_major && my_minor > rq_minor) + || (my_major == rq_major && my_minor == rq_minor + && my_micro >= rq_micro)) + { + return 1; + } + return 0; +} + + + /* Format a string so that it fits within about TARGET_COLS columns. If IN_PLACE is 0, then TEXT is copied to a new buffer, which is returned. Otherwise, TEXT is modified in place and returned. diff --git a/common/stringhelp.h b/common/stringhelp.h index c813662c7..d9225a3bb 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -148,6 +148,9 @@ char **strsplit (char *string, char delim, char replacement, int *count); /* Tokenize STRING using the set of delimiters in DELIM. */ char **strtokenize (const char *string, const char *delim); +/* Return True if MYVERSION is greater or equal than REQ_VERSION. */ +int compare_version_strings (const char *my_version, const char *req_version); + /* Format a string so that it fits within about TARGET_COLS columns. */ char *format_text (char *text, int in_place, int target_cols, int max_cols); diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c index af79cb5cd..b4a41ac39 100644 --- a/common/t-stringhelp.c +++ b/common/t-stringhelp.c @@ -705,6 +705,7 @@ stresc (char *s) return p; } + static void test_format_text (void) { @@ -813,6 +814,65 @@ test_format_text (void) fail(0); } + +static void +test_compare_version_strings (void) +{ + struct { const char *a; const char *b; int okay; } tests[] = { + { "1.0.0", "1.0.0", 1 }, + { "1.0.0-", "1.0.0", 1 }, + { "1.0.0-1", "1.0.0", 1 }, + { "1.0.0.1", "1.0.0", 1 }, + { "1.0.0", "1.0.1", 0 }, + { "1.0.0-", "1.0.1", 0 }, + { "1.0.0-1", "1.0.1", 0 }, + { "1.0.0.1", "1.0.1", 0 }, + { "1.0.0", "1.1.0", 0 }, + { "1.0.0-", "1.1.0", 0 }, + { "1.0.0-1", "1.1.0", 0 }, + { "1.0.0.1", "1.1.0", 0 }, + + { "1.0.0", "1.0.0-", 1 }, + { "1.0.0", "1.0.0-1", 1 }, + { "1.0.0", "1.0.0.1", 1 }, + { "1.1.0", "1.0.0", 1 }, + { "1.1.1", "1.1.0", 1 }, + { "1.1.2", "1.1.2", 1 }, + { "1.1.2", "1.0.2", 1 }, + { "1.1.2", "0.0.2", 1 }, + { "1.1.2", "1.1.3", 0 }, + + { "0.99.1", "0.9.9", 1 }, + { "0.9.1", "0.91.0", 0 }, + + { "1.5.3", "1.5", 1 }, + { "1.5.0", "1.5", 1 }, + { "1.4.99", "1.5", 0 }, + { "1.5", "1.4.99", 1 }, + { "1.5", "1.5.0", 1 }, + { "1.5", "1.5.1", 0 }, + + { "1.5.3-x17", "1.5-23", 1 }, + + { "1.5.3a", "1.5.3", 1 }, + { "1.5.3a", "1.5.3b", 1 }, + + { NULL, NULL, 0 } + }; + int idx; + int res; + + for (idx=0; idx < DIM(tests); idx++) + { + res = compare_version_strings (tests[idx].a, tests[idx].b); + /* printf ("test %d: '%s' '%s' %d -> %d\n", */ + /* idx, tests[idx].a, tests[idx].b, tests[idx].okay, res); */ + if (res != tests[idx].okay) + fail (idx); + } +} + + int main (int argc, char **argv) { @@ -827,8 +887,9 @@ main (int argc, char **argv) test_make_absfilename_try (); test_strsplit (); test_strtokenize (); + test_compare_version_strings (); test_format_text (); xfree (home_buffer); - return 0; + return !!errcount; } |