[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 3/3] Introduce $(compare ...) for numerical comparison
From: |
Jouke Witteveen |
Subject: |
[PATCH 3/3] Introduce $(compare ...) for numerical comparison |
Date: |
Fri, 16 Jul 2021 14:04:41 +0200 |
Numbers can come from $(words ...), automatic variables such as
$(MAKELEVEL), from environment variables, or from shell output such as
through $(shell expr ...). The $(compare ...) function allows
conditional evaluation controlled by numerical variables.
* NEWS: Announce this feature.
* doc/make.texi (Functions for Conditionals): Document 'compare'.
* src/function.c (func_compare): Create the 'compare' built-in function.
* tests/scripts/functions/compare: Test the 'compare' built-in function.
---
This is a cleaned-up and documented version of a proposal submitted a
year ago. The interface was conceived by Edward Welbourne and myself.
Personally, I would not introduce mathematical operators to make, but
given that numbers are a thing and they do pop up in variables, a
comparison function makes sense to me.
Thanks for considering!
- Jouke
NEWS | 4 +++
doc/make.texi | 36 ++++++++++++++++++++-
src/function.c | 46 ++++++++++++++++++++++++++
tests/scripts/functions/compare | 57 +++++++++++++++++++++++++++++++++
4 files changed, 142 insertions(+), 1 deletion(-)
create mode 100644 tests/scripts/functions/compare
diff --git a/NEWS b/NEWS
index 5356260..6a3a744 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,10 @@
https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
user-defined function and they will not impact global variable assignments.
Implementation provided by Jouke Witteveen <j.witteveen@gmail.com>
+* New feature: The $(compare ...) function
+ This function allows conditional evaluation controlled by a numerical
+ comparison.
+
* New debug option "print" will show the recipe to be run, even when silent
mode is set.
diff --git a/doc/make.texi b/doc/make.texi
index 1ebf6ae..14a59f6 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -7654,7 +7654,7 @@ the file names to refer to an existing file or directory.
Use the
@section Functions for Conditionals
@findex if
@cindex conditional expansion
-There are three functions that provide conditional expansion. A key
+There are four functions that provide conditional expansion. A key
aspect of these functions is that not all of the arguments are
expanded initially. Only those arguments which need to be expanded,
will be expanded.
@@ -7701,6 +7701,32 @@ empty string the processing stops and the result of the
expansion is
the empty string. If all arguments expand to a non-empty string then
the result of the expansion is the expansion of the last argument.
+@item $(compare
@var{lhs},@var{rhs},@var{lt-part}[,@var{eq-part}[,@var{gt-part}]])
+@findex compare
+The @code{compare} function provides support for numerical comparison of
+integers. This function has no counterpart among the GNU @code{make}
+makefile conditionals.
+
+The left-hand side, @var{lhs}, and right-hand side, @var{rhs}, are
+expanded and parsed as integral numbers in base 10. Expansion of the
+remaining arguments is controlled by how the numerical left-hand side
+compares to the numerical right-hand side.
+
+If the left-hand side is strictly less than the right-hand side, the
+entire @code{compare} function evaluates to the expansion of the third
+argument, @var{lt-part}. If both sides compare equal, then the fourth
+argument, @var{eq-part}, is expanded and becomes the result of the
+@code{compare} function. If the left-hand side is strictly greater than
+the right-hand side, then the @code{compare} function evaluates to the
+expansion of the fifth argument, @var{gt-part}.
+
+In case of missing arguments, @var{gt-part} defaults to @var{eq-part},
+and @var{eq-part} defaults to the empty string. Thus both
+@samp{$(compare 9,7,hello)} and @samp{$(compare 9,7,hello,world,)}
+evaluate to the empty string, while @samp{$(compare 9,7,hello,world)}
+(notice the absence of a comma after @code{world}) evaluates to
+@samp{world}.
+
@end table
@node Let Function, Foreach Function, Conditional Functions, Functions
@@ -12523,6 +12549,14 @@ all expansions result in a non-empty string,
substitute the expansion
of the last @var{condition}.@*
@xref{Conditional Functions, ,Functions for Conditionals}.
+@item $(compare
@var{lhs},@var{rhs},@var{lt-part}[,@var{eq-part}[,@var{gt-part}]])
+Compare @var{lhs} and @var{rhs} numerically; substitute the expansion of
+@var{lt-part}, @var{eq-part}, or @var{gt-part} depending on whether the
+left-hand side is less-than, equal-to, or greater-than the right-hand
+side, respectively. If @var{gt-part} is left out, it defaults to
+@var{eq-part}.@*
+@xref{Conditional Functions, ,Functions for Conditionals}.
+
@item $(call @var{var},@var{param},@dots{})
Evaluate the variable @var{var} replacing any references to @code{$(1)},
@code{$(2)} with the first, second, etc.@: @var{param} values.@*
diff --git a/src/function.c b/src/function.c
index 964169a..587786a 100644
--- a/src/function.c
+++ b/src/function.c
@@ -1272,6 +1272,51 @@ func_sort (char *o, char **argv, const char *funcname
UNUSED)
return o;
}
+/*
+ $(compare lhs,rhs,lt-part[,eq-part[,gt-part]])
+
+ LT-PART is evaluated when LHS is strictly less than RHS, EQ-PART is evaluated
+ when LHS is equal to RHS, and GT-part is evaluated when LHS is strictly
+ greater than RHS. If GT-PART is not provided, it defaults to EQ-PART. When
+ neither EQ-PART nor GT-PART are provided, nothing is evaluated if LHS is not
+ strictly less than RHS. Thus, $(compare ...) can be used to create
+ side-effects (with $(shell ...), for example).
+*/
+
+static char *
+func_compare (char *o, char **argv, const char *funcname UNUSED)
+{
+ char *lhs_str = expand_argument (argv[0], NULL);
+ char *rhs_str = expand_argument (argv[1], NULL);
+ long lhs, rhs;
+
+ lhs = parse_numeric (lhs_str,
+ _("non-numeric first argument to 'compare' function"));
+ rhs = parse_numeric (rhs_str,
+ _("non-numeric second argument to 'compare' function"));
+ free (lhs_str);
+ free (rhs_str);
+
+ argv += 2;
+ if (lhs >= rhs)
+ {
+ ++argv;
+ if (lhs > rhs && *argv && *(argv + 1))
+ ++argv;
+ }
+
+ if (*argv)
+ {
+ char *expansion = expand_argument (*argv, NULL);
+
+ o = variable_buffer_output (o, expansion, strlen (expansion));
+
+ free (expansion);
+ }
+
+ return o;
+}
+
/*
$(if condition,true-part[,false-part])
@@ -2438,6 +2483,7 @@ static struct function_table_entry function_table_init[] =
FT_ENTRY ("info", 0, 1, 1, func_error),
FT_ENTRY ("error", 0, 1, 1, func_error),
FT_ENTRY ("warning", 0, 1, 1, func_error),
+ FT_ENTRY ("compare", 3, 5, 0, func_compare),
FT_ENTRY ("if", 2, 3, 0, func_if),
FT_ENTRY ("or", 1, 0, 0, func_or),
FT_ENTRY ("and", 1, 0, 0, func_and),
diff --git a/tests/scripts/functions/compare b/tests/scripts/functions/compare
new file mode 100644
index 0000000..574397f
--- /dev/null
+++ b/tests/scripts/functions/compare
@@ -0,0 +1,57 @@
+# -*-perl-*-
+$description = "Test the compare function.\n";
+
+$details = "Try various uses of compare and ensure they all give the correct
+results.\n";
+
+open(MAKEFILE, "> $makefile");
+
+print MAKEFILE <<'EOF';
+# Negative
+n = -10
+# Zero
+z = 0
+# Positive
+p = 1000000000
+
+all:
+ @echo 1_1 $(compare $n,$n,$(shell echo lt))
+ @echo 1_2 $(compare $n,$z,$(shell echo lt))
+ @echo 1_3 $(compare $z,$n,$(shell echo lt))
+ @echo 2_1 $(compare $n,$p,lt,ge)
+ @echo 2_2 $(compare $z,$z,lt,ge)
+ @echo 2_3 $(compare $p,$n,lt,ge)
+ @echo 3_0 $(compare $p,$n,lt,eq,)
+ @echo 3_1 $(compare $z,$p,lt,eq,gt)
+ @echo 3_2 $(compare $p,$z,lt,eq,gt)
+ @echo 3_3 $(compare $p,$p,lt,eq,gt)
+EOF
+close(MAKEFILE);
+
+&run_make_with_options($makefile, "", &get_logfile);
+$answer = "1_1\n1_2 lt\n1_3\n2_1 lt\n2_2 ge\n2_3 ge\n3_0\n3_1 lt\n3_2 gt\n3_3
eq\n";
+&compare_output($answer, &get_logfile(1));
+
+
+# Test error conditions
+
+run_make_test('
+compare-e1: ; @echo $(compare 12a,1,foo)
+compare-e2: ; @echo $(compare 0,,foo)
+compare-e3: ; @echo $(compare -1,9999999999999999999,foo)',
+ 'compare-e1',
+ "#MAKEFILE#:2: *** non-numeric first argument to 'compare'
function: '12a'. Stop.",
+ 512);
+
+run_make_test(undef,
+ 'compare-e2',
+ "#MAKEFILE#:3: *** non-numeric second argument to 'compare'
function: ''. Stop.",
+ 512);
+
+run_make_test(undef,
+ 'compare-e3',
+ "#MAKEFILE#:4: *** Numerical result out of range:
'9999999999999999999'. Stop.",
+ 512);
+
+
+1;
--
2.32.0
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH 3/3] Introduce $(compare ...) for numerical comparison,
Jouke Witteveen <=