From 64504e8b8fb097d6e849953eb0e4721321c41a27 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Mon, 11 Sep 2023 10:21:36 +0200 Subject: add optional operator to rpmcmpver for consistency with version_compare --- package.xml | 2 +- rpminfo.c | 50 ++++++++++++++++++++++++++++++++++------- rpminfo.stub.php | 2 +- rpminfo_arginfo.h | 5 +++-- tests/002-rpmvercmp.phpt | 44 +++++++++++++++++++++++++++++++++++- tests/010-rpmvercmp_error7.phpt | 10 ++++++--- tests/011-rpmvercmp_error8.phpt | 12 +++++++--- 7 files changed, 106 insertions(+), 19 deletions(-) diff --git a/package.xml b/package.xml index 38dc60e..4756ce4 100644 --- a/package.xml +++ b/package.xml @@ -24,7 +24,7 @@ Documentation: https://www.php.net/rpminfo PHP-3.01 -- +- add optional operator to rpmcmpver for consistency with version_compare diff --git a/rpminfo.c b/rpminfo.c index 53b9c6c..1ba0123 100644 --- a/rpminfo.c +++ b/rpminfo.c @@ -37,6 +37,11 @@ #define ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, type_hint, allow_null, default_value) \ ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) #endif +/* only used for rpmvercmp */ +#ifndef ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX +#define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(name, return_reference, required_num_args, type) \ + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, IS_LONG, 0) +#endif #ifndef RETURN_THROWS #define RETURN_THROWS() return @@ -469,10 +474,11 @@ PHP_FUNCTION(rpmvercmp) char *in_evr1, *evr1, *v1, *r1; char *in_evr2, *evr2, *v2, *r2; char *p, empty[] = ""; + char *op = NULL; long e1, e2, r; - size_t len1, len2; + size_t len1, len2, oplen; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &in_evr1, &len1, &in_evr2, &len2) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|s", &in_evr1, &len1, &in_evr2, &len2, &op, &oplen) == FAILURE) { RETURN_THROWS(); } evr1 = estrdup(in_evr1); @@ -498,9 +504,9 @@ PHP_FUNCTION(rpmvercmp) e2 = 0; } if (e1 < e2) { - RETVAL_LONG(-1); + r = -1; } else if (e1 > e2) { - RETVAL_LONG(1); + r = 1; } else { // Version p = strchr(v1, '-'); @@ -518,16 +524,44 @@ PHP_FUNCTION(rpmvercmp) r2 = empty; } r = rpmvercmp(v1, v2); - if (r) { - RETVAL_LONG(r); - } else { + if (!r) { // Release r = rpmvercmp(r1, r2); - RETVAL_LONG(r); } } efree(evr1); efree(evr2); + + if (!op) { + RETURN_LONG(r); + } + + if (!strcmp(op, "<") || !strcmp(op, "lt")) { + RETURN_BOOL(r < 0); + } + if (!strcmp(op, "<=") || !strcmp(op, "le")) { + RETURN_BOOL(r <= 0); + } + if (!strcmp(op, ">") || !strcmp(op, "gt")) { + RETURN_BOOL(r > 0); + } + if (!strcmp(op, ">=") || !strcmp(op, "ge")) { + RETURN_BOOL(r >= 0); + } + if (!strcmp(op, "==") || !strcmp(op, "=") || !strcmp(op, "eq")) { + RETURN_BOOL(r == 0); + } + if (!strcmp(op, "!=") || !strcmp(op, "<>") || !strcmp(op, "ne")) { + RETURN_BOOL(r != 0); + } + +#if PHP_VERSION_ID < 80000 + php_error_docref(NULL, E_WARNING, "%s is not a valid comparison operator", op); + RETURN_NULL(); +#else + zend_argument_value_error(3, "must be a valid comparison operator"); + RETURN_THROWS(); +#endif } /* }}} */ diff --git a/rpminfo.stub.php b/rpminfo.stub.php index 543cc5f..022ccd4 100644 --- a/rpminfo.stub.php +++ b/rpminfo.stub.php @@ -10,6 +10,6 @@ function rpmdbsearch(string $pattern, int $rpmtag = RPMTAG_NAME, int $rpmmire = function rpminfo(string $path, bool $full = false, ?string &$error = null): Array|null {} -function rpmvercmp(string $evr1, string $evr2): int {} +function rpmvercmp(string $evr1, string $evr2, ?string $operator = null): int|bool {} diff --git a/rpminfo_arginfo.h b/rpminfo_arginfo.h index 20c501f..03fa650 100644 --- a/rpminfo_arginfo.h +++ b/rpminfo_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 6b4dfeada2b5de5c5453d2b38c1a861e01bf958e */ + * Stub hash: 8636be19a4c17d1ed16247fb265a923ee7c89104 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmaddtag, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, rpmtag, IS_LONG, 0) @@ -23,9 +23,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpminfo, 0, 1, IS_ARRAY, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(1, error, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmvercmp, 0, 2, IS_LONG, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_rpmvercmp, 0, 2, MAY_BE_LONG|MAY_BE_BOOL) ZEND_ARG_TYPE_INFO(0, evr1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, evr2, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, operator, IS_STRING, 1, "null") ZEND_END_ARG_INFO() diff --git a/tests/002-rpmvercmp.phpt b/tests/002-rpmvercmp.phpt index d83cf67..c53a183 100644 --- a/tests/002-rpmvercmp.phpt +++ b/tests/002-rpmvercmp.phpt @@ -29,11 +29,53 @@ $ok = true; foreach ($cases as $case) { list($a,$b,$expected) = $case; $result = rpmvercmp($a,$b); - if ($result != $expected) { + if ($result !== $expected) { $ok = false; printf("rpmvercmp(%s, %s) = %d when %d expected\n", $a, $b, $result, $expected); } } + +$cases = [ + ['1', '2', '>', false], + ['1', '2', 'gt', false], + ['1', '2', '>=', false], + ['1', '2', 'ge', false], + ['1', '1', '>=', true], + ['1', '1', 'ge', true], + + ['1', '2', '<', true], + ['1', '2', 'lt', true], + ['1', '2', '<=', true], + ['1', '2', 'le', true], + ['1', '1', '<=', true], + ['1', '1', 'le', true], + + ['1', '1', '=', true], + ['1', '1', '==', true], + ['1', '1', 'eq', true], + + ['1', '2', '=', false], + ['1', '2', '==', false], + ['1', '2', 'eq', false], + + ['1', '1', '!=', false], + ['1', '1', '<>', false], + ['1', '1', 'ne', false], + + ['1', '2', '!=', true], + ['1', '2', '<>', true], + ['1', '2', 'ne', true], +]; +foreach ($cases as $case) { + list($a,$b,$op,$expected) = $case; + $result = rpmvercmp($a,$b,$op); + if ($result !== $expected) { + $ok = false; + printf("rpmvercmp(%s, %s, %s) = %s when %s expected\n", + $a, $b, $op, $result ? "true" : "false", $expected ? "true" : "false"); + } +} + if ($ok) echo "OK\n"; ?> Done diff --git a/tests/010-rpmvercmp_error7.phpt b/tests/010-rpmvercmp_error7.phpt index c9b3875..2d5c220 100644 --- a/tests/010-rpmvercmp_error7.phpt +++ b/tests/010-rpmvercmp_error7.phpt @@ -10,16 +10,20 @@ if (PHP_VERSION_ID >= 80000) print "skip only for PHP 7"; var_dump(rpmvercmp()); var_dump(rpmvercmp("a")); var_dump(rpmvercmp("a", "b", "c")); +var_dump(rpmvercmp("a", "b", "c", "d")); ?> Done --EXPECTF-- -Warning: rpmvercmp() expects exactly 2 parameters, 0 given in %s +Warning: rpmvercmp() expects at least 2 parameters, 0 given in %s NULL -Warning: rpmvercmp() expects exactly 2 parameters, 1 given in %s +Warning: rpmvercmp() expects at least 2 parameters, 1 given in %s NULL -Warning: rpmvercmp() expects exactly 2 parameters, 3 given in %s +Warning: rpmvercmp(): c is not a valid comparison operator in %s +NULL + +Warning: rpmvercmp() expects at most 3 parameters, 4 given in %s NULL Done diff --git a/tests/011-rpmvercmp_error8.phpt b/tests/011-rpmvercmp_error8.phpt index 4430975..2fe6aa1 100644 --- a/tests/011-rpmvercmp_error8.phpt +++ b/tests/011-rpmvercmp_error8.phpt @@ -19,13 +19,19 @@ try { } try { var_dump(rpmvercmp("a", "b", "c")); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(rpmvercmp("a", "b", "c", "d")); } catch (ArgumentCountError $e) { echo $e->getMessage(), "\n"; } ?> Done --EXPECTF-- -rpmvercmp() expects exactly 2 %s, 0 given -rpmvercmp() expects exactly 2 %s, 1 given -rpmvercmp() expects exactly 2 %s, 3 given +rpmvercmp() expects at least 2 %s, 0 given +rpmvercmp() expects at least 2 %s, 1 given +rpmvercmp(): Argument #3 ($operator) must be a valid comparison operator +rpmvercmp() expects at most 3 %s, 4 given Done -- cgit