aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2023-07-05 10:42:17 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2023-07-05 10:42:21 -0400
commit6b0ddba545ca578903fe856af6d820883121bb1e (patch)
tree7e8a485e89bc23075e084fe16c44e5e280c5855c
parenta70733d9a64320eac8038d733df67467cd97976c (diff)
downloadversion_compare-master.tar.gz
Bug fix:HEADmaster
* Pad first element of a version to avoid small versions being detected as greater than larger versions * before: 1.0.3 > 2.0.0 == TRUE * after: 1.0.3 > 2.0.0 == FALSE
-rw-r--r--tests.c45
-rw-r--r--version_compare.c48
-rw-r--r--version_compare.h1
3 files changed, 85 insertions, 9 deletions
diff --git a/tests.c b/tests.c
index 0eb56ef..f91f072 100644
--- a/tests.c
+++ b/tests.c
@@ -77,6 +77,13 @@ static struct TestCase_version_compare test_cases_version_compare[] = {
{"1.0a", ">=", "1.0.0", 1},
{"1.0a", "!=", "1.0.0", 1},
+ {"1.0.3", "=", "2.0.0", 0},
+ {"1.0.3", "<", "2.0.0", 1},
+ {"1.0.3", "<=", "2.0.0", 1},
+ {"1.0.3", ">", "2.0.0", 0},
+ {"1.0.3", ">=", "2.0.0", 0},
+ {"1.0.3", "!=", "2.0.0", 1},
+
{"2022.1", "=", "2022.4", 0},
{"2022.1", "<", "2022.4", 1},
{"2022.1", "<=", "2022.4", 1},
@@ -84,6 +91,34 @@ static struct TestCase_version_compare test_cases_version_compare[] = {
{"2022.1", ">=", "2022.4", 0},
{"2022.1", "!=", "2022.4", 1},
+ {"1:2022.1", "=", "2022.4", 0},
+ {"1:2022.1", "<", "2022.4", 1},
+ {"1:2022.1", "<=", "2022.4", 1},
+ {"1:2022.1", ">", "2022.4", 0},
+ {"1:2022.1", ">=", "2022.4", 0},
+ {"1:2022.1", "!=", "2022.4", 1},
+
+ {"1:2022.1", "=", "2:2022.4", 0},
+ {"1:2022.1", "<", "2:2022.4", 1},
+ {"1:2022.1", "<=", "2:2022.4", 1},
+ {"1:2022.1", ">", "2:2022.4", 0},
+ {"1:2022.1", ">=", "2:2022.4", 0},
+ {"1:2022.1", "!=", "2:2022.4", 1},
+
+ {"2:2022.4", "=", "1:2022.1", 0},
+ {"2:2022.4", "<", "1:2022.1", 0},
+ {"2:2022.4", "<=", "1:2022.1", 0},
+ {"2:2022.4", ">", "1:2022.1", 1},
+ {"2:2022.4", ">=", "1:2022.1", 1},
+ {"2:2022.4", "!=", "1:2022.1", 1},
+
+ {"2022.1", "=", "2:2022.1", 0},
+ {"2022.1", "<", "2:2022.1", 1},
+ {"2022.1", "<=", "2:2022.1", 1},
+ {"2022.1", ">", "2:2022.1", 0},
+ {"2022.1", ">=", "2:2022.1", 0},
+ {"2022.1", "!=", "2:2022.1", 1},
+
{"2022.4", "=", "2022.1", 0},
{"2022.4", "<", "2022.1", 0},
{"2022.4", "<=", "2022.1", 0},
@@ -109,7 +144,7 @@ static int run_cases_version_compare(struct TestCase_version_compare tests[], si
int op = version_parse_operator(test->op);
result = version_compare(op, test->a, test->b);
- printf("%s %s %s is %s", test->a, test->op, test->b, result ? "TRUE" : "FALSE" );
+ printf("%s %s %s is %s (%d)", test->a, test->op, test->b, result ? "TRUE" : "FALSE" , result);
if (test->result != result) {
printf(" [FAILED: got %d, expected %d]\n", result, test->result);
failed++;
@@ -132,7 +167,7 @@ static int run_cases_string(struct TestCase_strings tests[], size_t size, strfn
fn(&s);
result = strcmp(test->result, s);
- printf("'%s' is %s", s, !result ? "CORRECT" : "INCORRECT" );
+ printf("'%s' is %s (%d)", s, !result ? "CORRECT" : "INCORRECT", !result );
if (result) {
printf(" [FAILED: got '%s', expected '%s']\n", s, test->result);
failed++;
@@ -144,7 +179,6 @@ static int run_cases_string(struct TestCase_strings tests[], size_t size, strfn
return failed;
}
-
char **make_argv(int *argc, char *argv[]) {
char **args;
*argc = 0;
@@ -153,7 +187,6 @@ char **make_argv(int *argc, char *argv[]) {
*argc = *argc + 1;
}
- //char **args = calloc(*argc + 1, sizeof(*argv));
args = calloc(*argc + 1, sizeof(*argv));
if (!args) {
perror("unable to allocate args array");
@@ -279,7 +312,7 @@ static int run_cases_program_split(struct TestCase_version_compare tests[], size
struct TestCase_version_compare *test = &tests[i];
result = run_program((char *[]){test->a, test->op, test->b, NULL});
- printf("%s %s %s is %s", test->a, test->op, test->b, result ? "TRUE" : "FALSE" );
+ printf("%s %s %s is %s (%d)", test->a, test->op, test->b, result ? "TRUE" : "FALSE", result);
if (test->result != result) {
printf(" [FAILED: got %d, expected %d]\n", result, test->result);
failed++;
@@ -300,7 +333,7 @@ static int run_cases_program_standalone(struct TestCase_version_compare tests[],
snprintf(data, sizeof(data) - 1, "%s %s %s", test->a, test->op, test->b);
result = run_program((char *[]){data, NULL});
- printf("%s %s %s is %s", test->a, test->op, test->b, result ? "TRUE" : "FALSE" );
+ printf("%s %s %s is %s (%d)", test->a, test->op, test->b, result ? "TRUE" : "FALSE", result);
if (test->result != result) {
printf(" [FAILED: got %d, expected %d]\n", result, test->result);
failed++;
diff --git a/version_compare.c b/version_compare.c
index c6aaca7..7e63024 100644
--- a/version_compare.c
+++ b/version_compare.c
@@ -128,7 +128,7 @@ char *collapse_whitespace(char **s) {
* @return -1 on error
*/
int version_sum(const char *str) {
- int result;
+ int i, result, epoch;
char *s, *ptr, *end;
if (!str || isempty(str)) {
@@ -136,6 +136,7 @@ int version_sum(const char *str) {
}
result = 0;
+ epoch = 0;
s = strdup(str);
if (!s) {
return -1;
@@ -146,17 +147,44 @@ int version_sum(const char *str) {
// Parsing stops at the first non-alpha, non-'.' character
// Digits are processed until the first invalid character
// I'm torn whether this should be considered an error
+ i = 0;
while (end != NULL) {
- result += (int) strtoul(ptr, &end, 10);
+ int tmp_result = 0;
+
+ tmp_result = (int) strtoul(ptr, &end, 10);
+
+ // Circumvent a bug which allows a smaller version to be greater
+ // than a larger version
+ // Bug:
+ // 1.0.3 == 1 + 0 + 3 = 4
+ // 2.0.0 == 2 + 0 + 0 = 2
+ // Correction:
+ // ((1 * EPOCH_MOD) + 1).0.3 = 104
+ // ((2 * EPOCH_MOD) + 2).0.0 = 202
+ if (!i && tmp_result && *end != ':') {
+ result += tmp_result * EPOCH_MOD;
+ i++;
+ }
+
ptr = end;
- if (*ptr == '.')
+ if (*ptr == '.' || *ptr == '-') {
ptr++;
+ }
+ else if (!epoch && *ptr == ':') {
+ epoch = 1;
+ result += EPOCH_MOD;
+ ptr++;
+ }
else if (isalpha(*ptr)) {
result += *ptr - ('a' - 1);
ptr++;
}
else
end = NULL;
+
+ if (tmp_result) {
+ result += tmp_result;
+ }
}
free(s);
@@ -204,6 +232,12 @@ int version_parse_operator(char *str) {
return result;
}
+int version_has_epoch(const char *str) {
+ char *result;
+ result = strchr(str, ':');
+ return result ? 1 : 0;
+}
+
/**
* Compare version strings based on flag(s)
* @param flags verison operators
@@ -227,6 +261,14 @@ int version_compare(int flags, const char *aa, const char *bb) {
if (result_b < 0)
return -1;
+
+ if ((version_has_epoch(aa) && !version_has_epoch(bb))) {
+ result_a -= EPOCH_MOD;
+ }
+ if (!version_has_epoch(aa) && version_has_epoch(bb)) {
+ result_b -= EPOCH_MOD;
+ }
+
result = 0;
if (flags & GT && flags & EQ)
result |= result_a >= result_b;
diff --git a/version_compare.h b/version_compare.h
index a951e53..cf873ad 100644
--- a/version_compare.h
+++ b/version_compare.h
@@ -5,6 +5,7 @@
#define LT 1 << 2
#define EQ 1 << 3
#define NOT 1 << 4
+#define EPOCH_MOD 100
int isempty(char *str);
char *lstrip(char **s);