varmod-subst.mk revision 1.14.2.1       1  1.14.2.1  perseant # $NetBSD: varmod-subst.mk,v 1.14.2.1 2025/08/02 05:58:39 perseant Exp $
      2       1.1    rillig #
      3       1.2    rillig # Tests for the :S,from,to, variable modifier.
      4       1.1    rillig 
      5       1.2    rillig all: mod-subst
      6       1.2    rillig all: mod-subst-delimiter
      7       1.2    rillig all: mod-subst-chain
      8       1.2    rillig all: mod-subst-dollar
      9       1.1    rillig 
     10       1.2    rillig WORDS=		sequences of letters
     11       1.7    rillig 
     12      1.13    rillig # The empty pattern never matches anything, except if it is anchored at the
     13      1.13    rillig # beginning or the end of the word.
     14       1.2    rillig .if ${WORDS:S,,,} != ${WORDS}
     15      1.12    rillig .  error
     16       1.2    rillig .endif
     17       1.7    rillig 
     18      1.12    rillig # The :S modifier flag '1' is applied exactly once.
     19       1.2    rillig .if ${WORDS:S,e,*,1} != "s*quences of letters"
     20      1.12    rillig .  error
     21       1.2    rillig .endif
     22       1.7    rillig 
     23      1.12    rillig # The :S modifier flag '1' is applied to the first occurrence, no matter if
     24      1.12    rillig # the occurrence is in the first word or not.
     25       1.3    rillig .if ${WORDS:S,f,*,1} != "sequences o* letters"
     26      1.12    rillig .  error
     27       1.3    rillig .endif
     28       1.7    rillig 
     29      1.12    rillig # The :S modifier replaces every first match per word.
     30       1.2    rillig .if ${WORDS:S,e,*,} != "s*quences of l*tters"
     31      1.12    rillig .  error
     32       1.2    rillig .endif
     33       1.7    rillig 
     34      1.12    rillig # The :S modifier flag 'g' replaces every occurrence.
     35       1.2    rillig .if ${WORDS:S,e,*,g} != "s*qu*nc*s of l*tt*rs"
     36      1.12    rillig .  error
     37       1.2    rillig .endif
     38       1.7    rillig 
     39      1.12    rillig # The '^' in the search pattern anchors the pattern at the beginning of each
     40      1.12    rillig # word, thereby matching a prefix.
     41       1.2    rillig .if ${WORDS:S,^sequ,occurr,} != "occurrences of letters"
     42      1.12    rillig .  error
     43       1.2    rillig .endif
     44       1.7    rillig 
     45      1.12    rillig # The :S modifier with a '^' anchor replaces the whole word if that word is
     46      1.12    rillig # exactly the pattern.
     47       1.2    rillig .if ${WORDS:S,^of,with,} != "sequences with letters"
     48      1.12    rillig .  error
     49       1.2    rillig .endif
     50       1.7    rillig 
     51      1.12    rillig # The :S modifier does not match if the pattern is longer than the word.
     52       1.2    rillig .if ${WORDS:S,^office,does not match,} != ${WORDS}
     53      1.12    rillig .  warning
     54       1.2    rillig .endif
     55       1.7    rillig 
     56      1.12    rillig # The '$' in the search pattern anchors the pattern at the end of each word,
     57      1.12    rillig # thereby matching a suffix.
     58       1.2    rillig .if ${WORDS:S,f$,r,} != "sequences or letters"
     59      1.12    rillig .  error
     60       1.2    rillig .endif
     61       1.7    rillig 
     62      1.12    rillig # The :S modifier with a '$' anchor replaces at most one occurrence per word.
     63       1.2    rillig .if ${WORDS:S,s$,,} != "sequence of letter"
     64      1.12    rillig .  error
     65       1.2    rillig .endif
     66       1.7    rillig 
     67      1.12    rillig # The :S modifier with a '$' anchor replaces the whole word if that word is
     68      1.12    rillig # exactly the pattern.
     69       1.2    rillig .if ${WORDS:S,of$,,} != "sequences letters"
     70      1.12    rillig .  error
     71       1.2    rillig .endif
     72       1.7    rillig 
     73      1.12    rillig # The :S modifier with a '$' anchor and a pattern that is longer than a word
     74      1.12    rillig # cannot match that word.
     75       1.2    rillig .if ${WORDS:S,eof$,,} != ${WORDS}
     76      1.12    rillig .  warning
     77       1.2    rillig .endif
     78       1.7    rillig 
     79      1.12    rillig # The :S modifier with the '^' and '$' anchors matches an exact word.
     80       1.2    rillig .if ${WORDS:S,^of$,,} != "sequences letters"
     81      1.12    rillig .  error
     82       1.2    rillig .endif
     83       1.7    rillig 
     84      1.12    rillig # The :S modifier with the '^' and '$' anchors does not match a word that
     85      1.12    rillig # starts with the pattern but is longer than the pattern.
     86       1.2    rillig .if ${WORDS:S,^o$,,} != ${WORDS}
     87      1.12    rillig .  error
     88       1.2    rillig .endif
     89       1.7    rillig 
     90      1.12    rillig # The :S modifier with the '^' and '$' anchors does not match a word that ends
     91      1.12    rillig # with the pattern but is longer than the pattern.
     92       1.2    rillig .if ${WORDS:S,^f$,,} != ${WORDS}
     93      1.12    rillig .  error
     94       1.2    rillig .endif
     95       1.7    rillig 
     96      1.12    rillig # The :S modifier with the '^' and '$' anchors does not match a word if the
     97      1.12    rillig # pattern ends with the word but is longer than the word.
     98       1.2    rillig .if ${WORDS:S,^eof$,,} != ${WORDS}
     99      1.12    rillig .  error
    100       1.2    rillig .endif
    101       1.7    rillig 
    102      1.12    rillig # The :S modifier with the '^' and '$' anchors does not match a word if the
    103      1.12    rillig # pattern starts with the word but is longer than the word.
    104       1.2    rillig .if ${WORDS:S,^office$,,} != ${WORDS}
    105      1.12    rillig .  error
    106       1.2    rillig .endif
    107       1.2    rillig 
    108      1.12    rillig # Except for the '^' and '$' anchors, the pattern does not contain any special
    109      1.12    rillig # characters, so the '*' from the pattern would only match a literal '*' in a
    110      1.12    rillig # word.
    111       1.8    rillig .if ${WORDS:S,*,replacement,} != ${WORDS}
    112      1.12    rillig .  error
    113       1.8    rillig .endif
    114       1.8    rillig 
    115      1.12    rillig # Except for the '^' and '$' anchors, the pattern does not contain any special
    116      1.12    rillig # characters, so the '.' from the pattern would only match a literal '.' in a
    117      1.12    rillig # word.
    118       1.8    rillig .if ${WORDS:S,.,replacement,} != ${WORDS}
    119      1.12    rillig .  error
    120       1.8    rillig .endif
    121       1.8    rillig 
    122      1.12    rillig # The '&' in the replacement is a placeholder for the text matched by the
    123      1.12    rillig # pattern.
    124       1.9    rillig .if ${:Uvalue:S,^val,&,} != "value"
    125       1.9    rillig .  error
    126       1.9    rillig .endif
    127       1.9    rillig .if ${:Uvalue:S,ue$,&,} != "value"
    128       1.9    rillig .  error
    129       1.9    rillig .endif
    130       1.9    rillig .if ${:Uvalue:S,^val,&-&-&,} != "val-val-value"
    131       1.9    rillig .  error
    132       1.9    rillig .endif
    133       1.9    rillig .if ${:Uvalue:S,ue$,&-&-&,} != "value-ue-ue"
    134       1.9    rillig .  error
    135       1.9    rillig .endif
    136       1.9    rillig 
    137      1.10    rillig 
    138      1.10    rillig # When a word is replaced with nothing, the remaining words are separated by a
    139      1.10    rillig # single space, not two.
    140      1.10    rillig .if ${1 2 3:L:S,2,,} != "1 3"
    141      1.10    rillig .  error
    142      1.10    rillig .endif
    143      1.10    rillig 
    144      1.10    rillig 
    145      1.14    rillig # In an empty expression, the ':S' modifier matches a single time, but only if
    146      1.14    rillig # the search string is empty and anchored at either the beginning or the end
    147      1.14    rillig # of the word.
    148      1.13    rillig .if ${:U:S,,out-of-nothing,} != ""
    149      1.13    rillig .  error
    150      1.13    rillig .endif
    151      1.13    rillig .if ${:U:S,^,out-of-nothing,} != "out-of-nothing"
    152      1.13    rillig .  error
    153      1.13    rillig .endif
    154      1.13    rillig .if ${:U:S,$,out-of-nothing,} != "out-of-nothing"
    155      1.13    rillig .  error
    156      1.13    rillig .endif
    157      1.13    rillig .if ${:U:S,^$,out-of-nothing,} != "out-of-nothing"
    158      1.13    rillig .  error
    159      1.13    rillig .endif
    160      1.14    rillig .if ${:U:S,,out-of-nothing,g} != ""
    161      1.14    rillig .  error
    162      1.14    rillig .endif
    163      1.14    rillig .if ${:U:S,^,out-of-nothing,g} != "out-of-nothing"
    164      1.14    rillig .  error
    165      1.14    rillig .endif
    166      1.14    rillig .if ${:U:S,$,out-of-nothing,g} != "out-of-nothing"
    167      1.14    rillig .  error
    168      1.14    rillig .endif
    169      1.14    rillig .if ${:U:S,^$,out-of-nothing,g} != "out-of-nothing"
    170      1.14    rillig .  error
    171      1.14    rillig .endif
    172      1.14    rillig .if ${:U:S,,out-of-nothing,W} != ""
    173      1.14    rillig .  error
    174      1.14    rillig .endif
    175      1.14    rillig .if ${:U:S,^,out-of-nothing,W} != "out-of-nothing"
    176      1.14    rillig .  error
    177      1.14    rillig .endif
    178      1.14    rillig .if ${:U:S,$,out-of-nothing,W} != "out-of-nothing"
    179      1.14    rillig .  error
    180      1.14    rillig .endif
    181      1.14    rillig .if ${:U:S,^$,out-of-nothing,W} != "out-of-nothing"
    182      1.14    rillig .  error
    183      1.14    rillig .endif
    184      1.13    rillig 
    185      1.13    rillig 
    186       1.2    rillig mod-subst:
    187       1.2    rillig 	@echo $@:
    188       1.2    rillig 	@echo :${:Ua b b c:S,a b,,:Q}:
    189       1.2    rillig 	@echo :${:Ua b b c:S,a b,,1:Q}:
    190       1.2    rillig 	@echo :${:Ua b b c:S,a b,,W:Q}:
    191       1.2    rillig 	@echo :${:Ua b b c:S,b,,g:Q}:
    192       1.2    rillig 	@echo :${:U1 2 3 1 2 3:S,1 2,___,Wg:S,_,x,:Q}:
    193       1.2    rillig 	@echo ${:U12345:S,,sep,g:Q}
    194       1.2    rillig 
    195       1.2    rillig # The :S and :C modifiers accept an arbitrary character as the delimiter,
    196       1.2    rillig # including characters that are otherwise used as escape characters or
    197       1.2    rillig # interpreted in a special way.  This can be used to confuse humans.
    198       1.2    rillig mod-subst-delimiter:
    199       1.2    rillig 	@echo $@:
    200       1.2    rillig 	@echo ${:U1 2 3:S	2	two	:Q} horizontal tabulator
    201       1.2    rillig 	@echo ${:U1 2 3:S 2 two :Q} space
    202       1.2    rillig 	@echo ${:U1 2 3:S!2!two!:Q} exclamation mark
    203       1.5    rillig 	@echo ${:U1 2 3:S"2"two":Q} quotation mark
    204       1.2    rillig 	# In shell command lines, the hash does not need to be escaped.
    205       1.2    rillig 	# It needs to be escaped in variable assignment lines though.
    206       1.5    rillig 	@echo ${:U1 2 3:S#2#two#:Q} number sign
    207       1.5    rillig 	@echo ${:U1 2 3:S$2$two$:Q} dollar sign
    208       1.5    rillig 	@echo ${:U1 2 3:S%2%two%:Q} percent sign
    209       1.5    rillig 	@echo ${:U1 2 3:S&2&two&:Q} ampersand
    210       1.2    rillig 	@echo ${:U1 2 3:S'2'two':Q} apostrophe
    211       1.5    rillig 	@echo ${:U1 2 3:S(2(two(:Q} left parenthesis
    212       1.5    rillig 	@echo ${:U1 2 3:S)2)two):Q} right parenthesis
    213       1.5    rillig 	@echo ${:U1 2 3:S*2*two*:Q} asterisk
    214       1.5    rillig 	@echo ${:U1 2 3:S+2+two+:Q} plus sign
    215       1.5    rillig 	@echo ${:U1 2 3:S,2,two,:Q} comma
    216       1.5    rillig 	@echo ${:U1 2 3:S-2-two-:Q} hyphen-minus
    217       1.5    rillig 	@echo ${:U1 2 3:S.2.two.:Q} full stop
    218       1.5    rillig 	@echo ${:U1 2 3:S/2/two/:Q} solidus
    219       1.2    rillig 	@echo ${:U1 2 3:S121two1:Q} digit
    220       1.2    rillig 	@echo ${:U1 2 3:S:2:two::Q} colon
    221       1.5    rillig 	@echo ${:U1 2 3:S;2;two;:Q} semicolon
    222       1.5    rillig 	@echo ${:U1 2 3:S<2<two<:Q} less-than sign
    223       1.5    rillig 	@echo ${:U1 2 3:S=2=two=:Q} equals sign
    224       1.5    rillig 	@echo ${:U1 2 3:S>2>two>:Q} greater-than sign
    225       1.2    rillig 	@echo ${:U1 2 3:S?2?two?:Q} question mark
    226       1.5    rillig 	@echo ${:U1 2 3:S@2@two@:Q} commercial at
    227       1.5    rillig 	@echo ${:U1 2 3:SA2AtwoA:Q} capital letter
    228       1.5    rillig 	@echo ${:U1 2 3:S[2[two[:Q} left square bracket
    229       1.5    rillig 	@echo ${:U1 2 3:S\2\two\:Q} reverse solidus
    230       1.5    rillig 	@echo ${:U1 2 3:S]2]two]:Q} right square bracket
    231       1.5    rillig 	@echo ${:U1 2 3:S^2^two^:Q} circumflex accent
    232       1.5    rillig 	@echo ${:U1 2 3:S_2_two_:Q} low line
    233       1.5    rillig 	@echo ${:U1 2 3:S`2`two`:Q} grave accent
    234       1.5    rillig 	@echo ${:U1 2 3:Sa2atwoa:Q} small letter
    235       1.5    rillig 	@echo ${:U1 2 3:S{2{two{:Q} left curly bracket
    236       1.2    rillig 	@echo ${:U1 2 3:S|2|two|:Q} vertical line
    237       1.5    rillig 	@echo ${:U1 2 3:S}2}two}:Q} right curly bracket
    238       1.2    rillig 	@echo ${:U1 2 3:S~2~two~:Q} tilde
    239       1.2    rillig 
    240       1.2    rillig # The :S and :C modifiers can be chained without a separating ':'.
    241       1.2    rillig # This is not documented in the manual page.
    242       1.2    rillig # It works because ApplyModifier_Subst scans for the known modifiers g1W
    243       1.2    rillig # and then just returns to ApplyModifiers.  There, the colon is optionally
    244       1.2    rillig # skipped (see the *st.next == ':' at the end of the loop).
    245       1.2    rillig #
    246       1.2    rillig # Most other modifiers cannot be chained since their parsers skip until
    247       1.2    rillig # the next ':' or '}' or ')'.
    248       1.2    rillig mod-subst-chain:
    249       1.2    rillig 	@echo $@:
    250       1.2    rillig 	@echo ${:Ua b c:S,a,A,S,b,B,}.
    251       1.2    rillig 	# There is no 'i' modifier for the :S or :C modifiers.
    252       1.2    rillig 	# The error message is "make: Unknown modifier 'i'", which is
    253       1.2    rillig 	# kind of correct, although it is mixing the terms for variable
    254       1.2    rillig 	# modifiers with the matching modifiers.
    255  1.14.2.1  perseant # expect: make: Unknown modifier ":i"
    256       1.2    rillig 	@echo ${:Uvalue:S,a,x,i}.
    257       1.2    rillig 
    258       1.6    rillig # No matter how many dollar signs there are, they all get merged
    259       1.2    rillig # into a single dollar by the :S modifier.
    260       1.2    rillig #
    261       1.2    rillig # As of 2020-08-09, this is because ParseModifierPart sees a '$' and
    262       1.2    rillig # calls Var_Parse to expand the variable.  In all other places, the "$$"
    263       1.2    rillig # is handled outside of Var_Parse.  Var_Parse therefore considers "$$"
    264       1.2    rillig # one of the "really stupid names", skips the first dollar, and parsing
    265       1.2    rillig # continues with the next character.  This repeats for the other dollar
    266       1.2    rillig # signs, except the one before the delimiter.  That one is handled by
    267       1.2    rillig # the code that optionally interprets the '$' as the end-anchor in the
    268       1.2    rillig # first part of the :S modifier.  That code doesn't call Var_Parse but
    269       1.2    rillig # simply copies the dollar to the result.
    270       1.2    rillig mod-subst-dollar:
    271       1.2    rillig 	@echo $@:${:U1:S,^,$,:Q}:
    272       1.2    rillig 	@echo $@:${:U2:S,^,$$,:Q}:
    273       1.2    rillig 	@echo $@:${:U3:S,^,$$$,:Q}:
    274       1.2    rillig 	@echo $@:${:U4:S,^,$$$$,:Q}:
    275       1.2    rillig 	@echo $@:${:U5:S,^,$$$$$,:Q}:
    276       1.2    rillig 	@echo $@:${:U6:S,^,$$$$$$,:Q}:
    277       1.2    rillig 	@echo $@:${:U7:S,^,$$$$$$$,:Q}:
    278       1.2    rillig 	@echo $@:${:U8:S,^,$$$$$$$$,:Q}:
    279       1.2    rillig 	@echo $@:${:U40:S,^,$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$,:Q}:
    280       1.2    rillig # This generates no dollar at all:
    281       1.2    rillig 	@echo $@:${:UU8:S,^,${:U$$$$$$$$},:Q}:
    282       1.6    rillig # Here is an alternative way to generate dollar signs.
    283       1.2    rillig # It's unexpectedly complicated though.
    284       1.2    rillig 	@echo $@:${:U:range=5:ts\x24:C,[0-9],,g:Q}:
    285       1.2    rillig # In modifiers, dollars are escaped using the backslash, not using another
    286       1.2    rillig # dollar sign.  Therefore, creating a dollar sign is pretty simple:
    287       1.2    rillig 	@echo $@:${:Ugood3:S,^,\$\$\$,:Q}
    288