xref: /rk3399_ARM-atf/make_helpers/utilities.mk (revision 6eb35c602d8fd0d841d202a682eddce5926911f9)
14731c00bSChris Kay#
2c3273703SChris Kay# Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
34731c00bSChris Kay#
44731c00bSChris Kay# SPDX-License-Identifier: BSD-3-Clause
54731c00bSChris Kay#
64731c00bSChris Kay
74731c00bSChris Kayspace :=
84731c00bSChris Kayspace := $(space) $(space)
94731c00bSChris Kaycomma := ,
104731c00bSChris Kay
114731c00bSChris Kaynull := �
124731c00bSChris Kay
134731c00bSChris Kaycompat-path = $(subst $(space),$(null),$(1))
144731c00bSChris Kaydecompat-path = $(subst $(null), ,$(1))
154731c00bSChris Kay
164731c00bSChris Kayabsolute-path = $(call decompat-path,$(abspath $(call compat-path,$(1))))
174731c00bSChris Kayreal-path = $(call decompat-path,$(realpath $(call compat-path,$(1))))
184731c00bSChris Kay
194731c00bSChris Kayfile-name = $(call decompat-path,$(notdir $(call compat-path,$(1))))
204731c00bSChris Kaydirectory-name = $(call decompat-path,$(dir $(call compat-path,$(1))))
214731c00bSChris Kay
224731c00bSChris Kayescape-shell = '$(subst ','\'',$(1))'
233af4eb50SChris Kay
243af4eb50SChris Kay#
25a57b94ecSChris Kay# The grouped-target symbol. Grouped targets are not supported on versions of
26a57b94ecSChris Kay# GNU Make <= 4.2, which was most recently packaged with Ubuntu 20.04.
27a57b94ecSChris Kay#
28a57b94ecSChris Kay
29a57b94ecSChris Kay& := $(if $(filter grouped-target,$(.FEATURES)),&)
30a57b94ecSChris Kay
31a57b94ecSChris Kay#
323af4eb50SChris Kay# Upper-case a string value.
333af4eb50SChris Kay#
343af4eb50SChris Kay# Parameters:
353af4eb50SChris Kay#
363af4eb50SChris Kay#   - $(1): The string to upper-case.
373af4eb50SChris Kay#
383af4eb50SChris Kay# Example usage:
393af4eb50SChris Kay#
403af4eb50SChris Kay#     $(call uppercase,HeLlO wOrLd) # "HELLO WORLD"
413af4eb50SChris Kay#
423af4eb50SChris Kay
433af4eb50SChris Kayuppercase = $(shell echo $(call escape-shell,$(1)) | tr '[:lower:]' '[:upper:]')
443af4eb50SChris Kay
453af4eb50SChris Kay#
463af4eb50SChris Kay# Lower-case a string value.
473af4eb50SChris Kay#
483af4eb50SChris Kay# Parameters:
493af4eb50SChris Kay#
503af4eb50SChris Kay#   - $(1): The string to lower-case.
513af4eb50SChris Kay#
523af4eb50SChris Kay# Example usage:
533af4eb50SChris Kay#
543af4eb50SChris Kay#     $(call lowercase,HeLlO wOrLd) # "hello world"
553af4eb50SChris Kay#
563af4eb50SChris Kay
573af4eb50SChris Kaylowercase = $(shell echo $(call escape-shell,$(1)) | tr '[:upper:]' '[:lower:]')
580dfa3deaSChris Kay
590dfa3deaSChris Kay#
600dfa3deaSChris Kay# Determine the "truthiness" of a value.
610dfa3deaSChris Kay#
620dfa3deaSChris Kay# Parameters:
630dfa3deaSChris Kay#
640dfa3deaSChris Kay#   - $(1): The value to determine the truthiness of.
650dfa3deaSChris Kay#
660dfa3deaSChris Kay# A value is considered to be falsy if it is:
670dfa3deaSChris Kay#
680dfa3deaSChris Kay#   - empty, or
690dfa3deaSChris Kay#   - equal to "0", "N", "NO", "F" or "FALSE" after upper-casing.
700dfa3deaSChris Kay#
710dfa3deaSChris Kay# If the value is truthy then the value is returned as-is, otherwise no value
720dfa3deaSChris Kay# is returned.
730dfa3deaSChris Kay#
740dfa3deaSChris Kay# Example usage:
750dfa3deaSChris Kay#
760dfa3deaSChris Kay#     truthy := y
770dfa3deaSChris Kay#     truthy-bool := $(call bool,$(truthy)) # "y"
780dfa3deaSChris Kay#
790dfa3deaSChris Kay#     falsy := n
800dfa3deaSChris Kay#     falsy-bool := $(call bool,$(falsy)) # <empty>
810dfa3deaSChris Kay#
820dfa3deaSChris Kay
830dfa3deaSChris Kaybool = $(filter-out 0 n no f false,$(call lowercase,$(1)))
840dfa3deaSChris Kay
850dfa3deaSChris Kay#
860dfa3deaSChris Kay# Determine the "truthiness" of a value, returning 0 or 1.
870dfa3deaSChris Kay#
880dfa3deaSChris Kay# Parameters:
890dfa3deaSChris Kay#
900dfa3deaSChris Kay#   - $(1): The value to determine the truthiness of.
910dfa3deaSChris Kay#
920dfa3deaSChris Kay# A value is considered to be falsy if it is:
930dfa3deaSChris Kay#
940dfa3deaSChris Kay#   - empty, or
950dfa3deaSChris Kay#   - equal to "0", "N", "NO", "F" or "FALSE" after upper-casing.
960dfa3deaSChris Kay#
970dfa3deaSChris Kay# If the value is truthy then the value is returned as-is, otherwise no value
980dfa3deaSChris Kay# is returned.
990dfa3deaSChris Kay#
1000dfa3deaSChris Kay# Example usage:
1010dfa3deaSChris Kay#
1020dfa3deaSChris Kay#     truthy := y
1030dfa3deaSChris Kay#     truthy-bool := $(call bool,$(truthy)) # "1"
1040dfa3deaSChris Kay#
1050dfa3deaSChris Kay#     falsy := n
1060dfa3deaSChris Kay#     falsy-bool := $(call bool,$(falsy)) # "0"
1070dfa3deaSChris Kay#
1080dfa3deaSChris Kay
1090dfa3deaSChris Kaybool-01 = $(if $(call bool,$(1)),1,0)
110d2867397SChris Kay
111d2867397SChris Kay#
112d2867397SChris Kay# Determine whether a variable is defined or not.
113d2867397SChris Kay#
114d2867397SChris Kay# Parameters:
115d2867397SChris Kay#
116d2867397SChris Kay#   - $(1): The variable to check.
117d2867397SChris Kay#
118d2867397SChris Kay# Example usage:
119d2867397SChris Kay#
120d2867397SChris Kay#     xyz-defined := $(call defined,xyz) # <empty>
121d2867397SChris Kay#
122d2867397SChris Kay#     xyz :=
123d2867397SChris Kay#     xyz-defined := $(call defined,xyz) # <non-empty>
124d2867397SChris Kay#
125d2867397SChris Kay#     xyz := hello
126d2867397SChris Kay#     xyz-defined := $(call defined,xyz) # <non-empty>
127d2867397SChris Kay#
128d2867397SChris Kay
129d2867397SChris Kaydefined = $(call bool,$(filter-out undefined,$(origin $(1))))
130c3273703SChris Kay
131c3273703SChris Kay#
1320fcee05fSHarrison Mutai# Extract include directories from compiler flags and convert them to absolute
1330fcee05fSHarrison Mutai# paths.
1340fcee05fSHarrison Mutai#
1350fcee05fSHarrison Mutai# Parameters:
1360fcee05fSHarrison Mutai#
1370fcee05fSHarrison Mutai#   - $(1): A list of C compiler flags.
1380fcee05fSHarrison Mutai#
1390fcee05fSHarrison Mutai# Example:
1400fcee05fSHarrison Mutai#
1410fcee05fSHarrison Mutai#     includes := $(call include-dirs, -nostdlib -Iinclude-dir) # /absolute/path/to/include-dir
1420fcee05fSHarrison Mutai#
1430fcee05fSHarrison Mutai
1440fcee05fSHarrison Mutaiinclude-dirs-pattern := $(call escape-shell,-I\s*("[^"]*"|'[^']*'|\S+))
1450fcee05fSHarrison Mutaiinclude-dirs = $(shell \
1460fcee05fSHarrison Mutai	printf '%s' $(call escape-shell,$1) | \
1470fcee05fSHarrison Mutai	perl -nle 'print $$1 while /'$(include-dirs-pattern)'/g' | \
1480fcee05fSHarrison Mutai	xargs realpath \
1490fcee05fSHarrison Mutai)
1500fcee05fSHarrison Mutai
1510fcee05fSHarrison Mutai#
152c3273703SChris Kay# Determine the path to a program.
153c3273703SChris Kay#
154c3273703SChris Kay# Parameters:
155c3273703SChris Kay#
156c3273703SChris Kay#   - $(1): The program to search for.
157c3273703SChris Kay#
158c3273703SChris Kay# Example usage:
159c3273703SChris Kay#
160c3273703SChris Kay#     path-to-gcc := $(call which,gcc) # "/usr/bin/gcc"
161c3273703SChris Kay#
162c3273703SChris Kay
163c3273703SChris Kaywhich = $(shell command -v $(call escape-shell,$(1)) 2>/dev/null)
164*6eb35c60SChris Kay
165*6eb35c60SChris Kay#
166*6eb35c60SChris Kay# Temporarily bind variables while expanding text (scoped "with").
167*6eb35c60SChris Kay#
168*6eb35c60SChris Kay# Creates temporary variable bindings, expands a body of text with those
169*6eb35c60SChris Kay# bindings in effect, then restores all affected variables to their previous
170*6eb35c60SChris Kay# values and flavors (or undefines them if they did not exist). This provides a
171*6eb35c60SChris Kay# "let"-style scope for variable assignments during text expansion.
172*6eb35c60SChris Kay#
173*6eb35c60SChris Kay# This function is modelled on the `let` function introduced in GNU Make 4.4:
174*6eb35c60SChris Kay#
175*6eb35c60SChris Kay#   https://www.gnu.org/software/make/manual/html_node/Let-Function.html
176*6eb35c60SChris Kay#
177*6eb35c60SChris Kay# Binding specifiers (space-separated in `$(1)`):
178*6eb35c60SChris Kay#
179*6eb35c60SChris Kay#   - l:name  Bind from the word list in `$(2)`. Bindings are applied
180*6eb35c60SChris Kay#             left-to-right; the last `l` binding receives all remaining words
181*6eb35c60SChris Kay#             (which may be empty). If there are more `l` names than words, the
182*6eb35c60SChris Kay#             excess names are bound to empty values.
183*6eb35c60SChris Kay#
184*6eb35c60SChris Kay#   - p:name  Bind from subsequent call arguments (`$(2)`, `$(3)`, `$(4)`, ...),
185*6eb35c60SChris Kay#             in left-to-right order. If `l` bindings are present, these
186*6eb35c60SChris Kay#             arguments instead start from `$(3)`, following the word list.
187*6eb35c60SChris Kay#
188*6eb35c60SChris Kay#   -   name  Treated as `l:name`.
189*6eb35c60SChris Kay#
190*6eb35c60SChris Kay# Parameters:
191*6eb35c60SChris Kay#
192*6eb35c60SChris Kay#   - $(1): Space-separated binding specifiers.
193*6eb35c60SChris Kay#   - $(2): The list value used by `l` bindings, if present.
194*6eb35c60SChris Kay#   - $(2|3..N-1): Values for `p` bindings, in order (optional).
195*6eb35c60SChris Kay#   - $(N): The text to expand with the temporary bindings active.
196*6eb35c60SChris Kay#
197*6eb35c60SChris Kay# Evaluation and restoration:
198*6eb35c60SChris Kay#
199*6eb35c60SChris Kay#   - All function arguments in Make are expanded at the call site. The text
200*6eb35c60SChris Kay#     must therefore be escaped (write `$$` to produce a literal `$`), or
201*6eb35c60SChris Kay#     supplied via `$(value ...)` to avoid premature expansion.
202*6eb35c60SChris Kay#
203*6eb35c60SChris Kay#   - Whitespace in `l`-style bindings is processed in terms of Make words; if
204*6eb35c60SChris Kay#     you need to preserve whitespace then prefer `p` bindings.
205*6eb35c60SChris Kay#
206*6eb35c60SChris Kay#   - Variables are assigned as simple (`:=`) during the text expansion. After
207*6eb35c60SChris Kay#     the text is expanded, each variable is restored to its previous state with
208*6eb35c60SChris Kay#     its original flavor (simple or recursive), or undefined if it did not
209*6eb35c60SChris Kay#     exist. Origins (e.g., command line, environment) are not preserved.
210*6eb35c60SChris Kay#
211*6eb35c60SChris Kay# Examples:
212*6eb35c60SChris Kay#
213*6eb35c60SChris Kay#   # Basic list destructuring (two names from a list):
214*6eb35c60SChris Kay#   $(call with,foo bar,10 20,$$(foo) $$(bar)) # "10 20"
215*6eb35c60SChris Kay#
216*6eb35c60SChris Kay#   # Last list binding receives the remainder:
217*6eb35c60SChris Kay#   $(call with,head tail,1 2 3 4,[$$(head)] [$$(tail)]) # "[1] [2 3 4]"
218*6eb35c60SChris Kay#
219*6eb35c60SChris Kay#   # Extra list names bind to empty values:
220*6eb35c60SChris Kay#   $(call with,x y,9,x=<$$(x)> y=<$$(y)>) # "x=<9> y=<>"
221*6eb35c60SChris Kay#
222*6eb35c60SChris Kay#   # Parameter-only bindings start in `$(2)`:
223*6eb35c60SChris Kay#   $(call with,p:x p:y,foo,bar,$$(x)-$$(y)) # "foo-bar"
224*6eb35c60SChris Kay#
225*6eb35c60SChris Kay#   # Parameter bindings start in `$(3)` when list bindings are specified:
226*6eb35c60SChris Kay#   $(call with,l:lhs p:op l:rhs,10 20,+,$$(lhs) $$(op) $$(rhs)) # "10 + 20"
227*6eb35c60SChris Kay#
228*6eb35c60SChris Kay#   # Variables are restored after expansion, with flavor preserved:
229*6eb35c60SChris Kay#
230*6eb35c60SChris Kay#   x := outer-x
231*6eb35c60SChris Kay#   y  = outer-y
232*6eb35c60SChris Kay#
233*6eb35c60SChris Kay#   $(info $(call with,x y,inner-x inner-y,$$(x) $$(y))) # "inner-x inner-y"
234*6eb35c60SChris Kay#
235*6eb35c60SChris Kay#   $(info $(x) ($(flavor x))) # "outer-x (simple)"
236*6eb35c60SChris Kay#   $(info $(y) ($(flavor y))) # "outer-y (recursive)"
237*6eb35c60SChris Kay#
238*6eb35c60SChris Kay#   # Passing the text via `$(value ...)` to avoid `$$` escaping:
239*6eb35c60SChris Kay#
240*6eb35c60SChris Kay#   text = [$(head)] [$(tail)]
241*6eb35c60SChris Kay#   $(call with,head tail,1 2 3 4,$(value text)) # "[1] [2 3 4]"
242*6eb35c60SChris Kay#
243*6eb35c60SChris Kay#   # Nested usage:
244*6eb35c60SChris Kay#
245*6eb35c60SChris Kay#   $(call with,a b,foo bar, \
246*6eb35c60SChris Kay#       $$(call with,c d,baz qux,$$$$(a) $$$$(b) $$$$(c) $$$$(d)))
247*6eb35c60SChris Kay#   # "foo bar baz qux"
248*6eb35c60SChris Kay#
249*6eb35c60SChris Kay
250*6eb35c60SChris Kaywith = $(with.ns.push)$(eval $(value with.core))$(with.ns.pop)
251*6eb35c60SChris Kay
252*6eb35c60SChris Kaywith.ns = with.ns.$(with.ns.stack.head)
253*6eb35c60SChris Kay
254*6eb35c60SChris Kaywith.ns.stack :=
255*6eb35c60SChris Kaywith.ns.stack.head = $(words $(with.ns.stack))
256*6eb35c60SChris Kay
257*6eb35c60SChris Kaywith.ns.push = $(eval with.ns.stack += $(with.ns.stack.head))
258*6eb35c60SChris Kaywith.ns.pop = $($(with.ns).result)$(eval $(value with.ns.pop.1))
259*6eb35c60SChris Kay
260*6eb35c60SChris Kaydefine with.ns.pop.1 =
261*6eb35c60SChris Kay        $(foreach variable,$(filter $(with.ns).%,$(.VARIABLES)),$\
262*6eb35c60SChris Kay                $(eval undefine $(variable)))
263*6eb35c60SChris Kay
264*6eb35c60SChris Kay        with.ns.stack := $(wordlist 2,$(with.ns.stack.head),$(with.ns.stack))
265*6eb35c60SChris Kayendef
266*6eb35c60SChris Kay
267*6eb35c60SChris Kaywith.bind.norm = $\
268*6eb35c60SChris Kay        $(if $(findstring :,$(1)),$\
269*6eb35c60SChris Kay                $(or $(filter l: p:,$(firstword $(subst :,: ,$(1)))),$\
270*6eb35c60SChris Kay                        $(error invalid binding specifier: $(1)))$\
271*6eb35c60SChris Kay                $(or $(filter-out %:,$(word 2,$(subst :,: ,$(1)))),$\
272*6eb35c60SChris Kay                        $(error invalid binding specifier: $(1))),$\
273*6eb35c60SChris Kay                l:$(1))
274*6eb35c60SChris Kay
275*6eb35c60SChris Kaywith.bind.kind = $(word 1,$(subst :, ,$(call with.bind.norm,$(1))))
276*6eb35c60SChris Kaywith.bind.name = $(word 2,$(subst :, ,$(call with.bind.norm,$(1))))
277*6eb35c60SChris Kay
278*6eb35c60SChris Kaydefine with.core =
279*6eb35c60SChris Kay        # Parse and record binding list/kinds/names from `$(1)`
280*6eb35c60SChris Kay        $(with.ns).bind.list := $(foreach b,$(1),$(call with.bind.norm,$(b)))
281*6eb35c60SChris Kay        $(with.ns).bind.names := $(foreach b,$(1),$(call with.bind.name,$(b)))
282*6eb35c60SChris Kay        $(with.ns).bind.kinds := $(foreach b,$(1),$(call with.bind.kind,$(b)))
283*6eb35c60SChris Kay
284*6eb35c60SChris Kay        # Create a 1..=(N_bindings) list of binding indices
285*6eb35c60SChris Kay        $(with.ns).bind.idx :=
286*6eb35c60SChris Kay        $(with.ns).bind.next = $(words 0 $($(with.ns).bind.idx))
287*6eb35c60SChris Kay
288*6eb35c60SChris Kay        $(foreach bind,$($(with.ns).bind.list),$\
289*6eb35c60SChris Kay                $(eval $(with.ns).bind.idx += $($(with.ns).bind.next)))
290*6eb35c60SChris Kay
291*6eb35c60SChris Kay        # Create a 2..=(N_arguments) list pointing to the text argument
292*6eb35c60SChris Kay        $(with.ns).text.idx :=
293*6eb35c60SChris Kay        $(with.ns).text.next = $(words 1 2 $($(with.ns).text.idx))
294*6eb35c60SChris Kay        $(with.ns).text = $($($(with.ns).text.next))
295*6eb35c60SChris Kay
296*6eb35c60SChris Kay        # Snapshot original flavors/values of all variables to be overwritten
297*6eb35c60SChris Kay        $(foreach bind.name,$($(with.ns).bind.names),$\
298*6eb35c60SChris Kay        $(foreach bind.name.ns,$(with.ns).bind.names[$(bind.name)],$\
299*6eb35c60SChris Kay                $(eval $(bind.name.ns).flavor := $(flavor $(bind.name))$\
300*6eb35c60SChris Kay                $(eval $(bind.name.ns).value = $(value $(bind.name))))))
301*6eb35c60SChris Kay
302*6eb35c60SChris Kay        # Initialize per-kind buckets (e.g., `l`, `p`)
303*6eb35c60SChris Kay        $(foreach bind.kind,$(sort $($(with.ns).bind.kinds)),$\
304*6eb35c60SChris Kay                $(eval $(with.ns).bind.kind[$(bind.kind)] := ))
305*6eb35c60SChris Kay
306*6eb35c60SChris Kay        # Distribute binding indices into kind buckets
307*6eb35c60SChris Kay        $(foreach bind.i,$($(with.ns).bind.idx),$\
308*6eb35c60SChris Kay        $(foreach bind.kind,$(word $(bind.i),$($(with.ns).bind.kinds)),$\
309*6eb35c60SChris Kay                $(eval $(with.ns).bind.kind[$(bind.kind)] += $(bind.i))))
310*6eb35c60SChris Kay
311*6eb35c60SChris Kay        # Per-kind setup (e.g., to set up index vectors before binding)
312*6eb35c60SChris Kay        $(foreach bind.kind,$(sort $($(with.ns).bind.kinds)),$\
313*6eb35c60SChris Kay        $(foreach bind.kind.ns,$(with.ns).bind.kind[$(bind.kind)],$\
314*6eb35c60SChris Kay                $(eval $(value with.core.$(bind.kind)))))
315*6eb35c60SChris Kay
316*6eb35c60SChris Kay        # Perform binding from left to right
317*6eb35c60SChris Kay        $(foreach bind.i,$($(with.ns).bind.idx),$\
318*6eb35c60SChris Kay        $(foreach bind.name,$(word $(bind.i),$($(with.ns).bind.names)),$\
319*6eb35c60SChris Kay        $(foreach bind.kind,$(word $(bind.i),$($(with.ns).bind.kinds)),$\
320*6eb35c60SChris Kay        $(foreach bind.kind.ns,$(with.ns).bind.kind[$(bind.kind)],$\
321*6eb35c60SChris Kay                $(eval $(value with.core.$(bind.kind).bind))))))
322*6eb35c60SChris Kay
323*6eb35c60SChris Kay        # Capture the expansion result from the current text pointer
324*6eb35c60SChris Kay        $(eval $(with.ns).result := $($(with.ns).text))
325*6eb35c60SChris Kay
326*6eb35c60SChris Kay        # Restore originals (flavor/value) or undefine if previously absent
327*6eb35c60SChris Kay        $(foreach bind.name,$($(with.ns).bind.names),$\
328*6eb35c60SChris Kay        $(foreach bind.name.ns,$(with.ns).bind.names[$(bind.name)],$\
329*6eb35c60SChris Kay                $(eval $(value with.core.restore))))
330*6eb35c60SChris Kayendef
331*6eb35c60SChris Kay
332*6eb35c60SChris Kaydefine with.core.l =
333*6eb35c60SChris Kay        # Create a 1..=(N_largs) list capturing the unbound `l` words
334*6eb35c60SChris Kay        $(bind.kind.ns).words.idx :=
335*6eb35c60SChris Kay        $(bind.kind.ns).words.next = $(words 1 $($(bind.kind.ns).words.idx))
336*6eb35c60SChris Kay        $(bind.kind.ns).words = $\
337*6eb35c60SChris Kay                $(wordlist $($(bind.kind.ns).words.next),$(words $(2)),$(2))
338*6eb35c60SChris Kay
339*6eb35c60SChris Kay        # Increment the text pointer
340*6eb35c60SChris Kay        $(with.ns).text.idx += $($(with.ns).text.next)
341*6eb35c60SChris Kayendef
342*6eb35c60SChris Kay
343*6eb35c60SChris Kaydefine with.core.l.bind =
344*6eb35c60SChris Kay        # Bind this name to the next unbound word
345*6eb35c60SChris Kay        $(bind.name) := $(firstword $($(bind.kind.ns).words))
346*6eb35c60SChris Kay
347*6eb35c60SChris Kay        # If this is the last `l` binding, absorb the remaining words
348*6eb35c60SChris Kay        ifeq ($($(bind.kind.ns).words.next),$(words $($(bind.kind.ns))))
349*6eb35c60SChris Kay                $(bind.name) := $($(bind.kind.ns).words)
350*6eb35c60SChris Kay        endif
351*6eb35c60SChris Kay
352*6eb35c60SChris Kay        # Nudge the word pointer forward
353*6eb35c60SChris Kay        $(bind.kind.ns).words.idx += $($(bind.kind.ns).words.next)
354*6eb35c60SChris Kayendef
355*6eb35c60SChris Kay
356*6eb35c60SChris Kaydefine with.core.p =
357*6eb35c60SChris Kay        # Compute the parameter index that `p` bindings start at
358*6eb35c60SChris Kay        $(bind.kind.ns).param.offset := 1 2
359*6eb35c60SChris Kay
360*6eb35c60SChris Kay        # When `l` bindings are present, `p` values shift right
361*6eb35c60SChris Kay        ifneq ($(filter l,$($(with.ns).bind.kinds)),)
362*6eb35c60SChris Kay                $(bind.kind.ns).param.offset += 3
363*6eb35c60SChris Kay        endif
364*6eb35c60SChris Kay
365*6eb35c60SChris Kay        # Create an N_poff..=N_pargs list capturing the unbound `p` arguments
366*6eb35c60SChris Kay        $(bind.kind.ns).param.idx :=
367*6eb35c60SChris Kay        $(bind.kind.ns).param.next = $\
368*6eb35c60SChris Kay                $(words $($(bind.kind.ns).param.offset) $\
369*6eb35c60SChris Kay                        $($(bind.kind.ns).param.idx))
370*6eb35c60SChris Kay        $(bind.kind.ns).param = $($(lastword $($(bind.kind.ns).param.idx)))
371*6eb35c60SChris Kayendef
372*6eb35c60SChris Kay
373*6eb35c60SChris Kaydefine with.core.p.bind =
374*6eb35c60SChris Kay        # Mark the next parameter as bound
375*6eb35c60SChris Kay        $(bind.kind.ns).param.idx += $($(bind.kind.ns).param.next)
376*6eb35c60SChris Kay
377*6eb35c60SChris Kay        # Bind this name to the next unbound argument
378*6eb35c60SChris Kay        $(bind.name) := $($(bind.kind.ns).param)
379*6eb35c60SChris Kay
380*6eb35c60SChris Kay        # Increment the text pointer
381*6eb35c60SChris Kay        $(with.ns).text.idx += $($(with.ns).text.next)
382*6eb35c60SChris Kayendef
383*6eb35c60SChris Kay
384*6eb35c60SChris Kaydefine with.core.restore =
385*6eb35c60SChris Kay        ifeq ($($(bind.name.ns).flavor),simple)
386*6eb35c60SChris Kay                $(eval $(bind.name) := $(value $(bind.name.ns).value))
387*6eb35c60SChris Kay        else ifeq ($($(bind.name.ns).flavor),recursive)
388*6eb35c60SChris Kay                $(eval $(bind.name) = $(value $(bind.name.ns).value))
389*6eb35c60SChris Kay        else ifeq ($($(bind.name.ns).flavor),undefined)
390*6eb35c60SChris Kay                undefine $(bind.name)
391*6eb35c60SChris Kay        endif
392*6eb35c60SChris Kayendef
393