1# $Id: varmisc.mk,v 1.23 2021/02/05 20:02:30 sjg Exp $
2# $NetBSD: varmisc.mk,v 1.30 2021/02/04 21:42:47 rillig Exp $
3#
4# Miscellaneous variable tests.
5
6all: unmatched_var_paren D_true U_true D_false U_false Q_lhs Q_rhs NQ_none \
7	strftime cmpv manok
8all: save-dollars
9all: export-appended
10all: parse-dynamic
11all: varerror-unclosed
12
13unmatched_var_paren:
14	@echo ${foo::=foo-text}
15
16True=	${echo true >&2:L:sh}TRUE
17False=	${echo false >&2:L:sh}FALSE
18
19VSET=	is set
20.undef UNDEF
21
22U_false:
23	@echo :U skipped when var set
24	@echo ${VSET:U${False}}
25
26D_false:
27	@echo :D skipped if var undef
28	@echo ${UNDEF:D${False}}
29
30U_true:
31	@echo :U expanded when var undef
32	@echo ${UNDEF:U${True}}
33
34D_true:
35	@echo :D expanded when var set
36	@echo ${VSET:D${True}}
37
38Q_lhs:
39	@echo :? only lhs when value true
40	@echo ${1:L:?${True}:${False}}
41
42Q_rhs:
43	@echo :? only rhs when value false
44	@echo ${0:L:?${True}:${False}}
45
46NQ_none:
47	@echo do not evaluate or expand :? if discarding
48	@echo ${VSET:U${1:L:?${True}:${False}}}
49
50April1=	1459494000
51
52# slightly contorted syntax to use utc via variable
53strftime:
54	@echo ${year=%Y month=%m day=%d:L:gmtime=1459494000}
55	@echo date=${%Y%m%d:L:${gmtime=${April1}:L}}
56
57# big jumps to handle 3 digits per step
58M_cmpv.units=	1 1000 1000000
59M_cmpv=		S,., ,g:_:range:@i@+ $${_:[-$$i]} \* $${M_cmpv.units:[$$i]}@:S,^,expr 0 ,1:sh
60
61Version=	123.456.789
62cmpv.only=	target specific vars
63
64cmpv:
65	@echo Version=${Version} == ${Version:${M_cmpv}}
66	@echo Literal=3.4.5 == ${3.4.5:L:${M_cmpv}}
67	@echo We have ${${.TARGET:T}.only}
68
69# catch misshandling of nested vars in .for loop
70MAN=
71MAN1=	make.1
72.for s in 1 2
73.  if defined(MAN$s) && !empty(MAN$s)
74MAN+=	${MAN$s}
75.  endif
76.endfor
77
78manok:
79	@echo MAN=${MAN}
80
81# begin .MAKE.SAVE_DOLLARS; see Var_SetWithFlags and ParseBoolean.
82SD_VALUES=	0 1 2 False True false true Yes No yes no On Off ON OFF on off
83SD_4_DOLLARS=	$$$$
84
85.for val in ${SD_VALUES}
86.MAKE.SAVE_DOLLARS:=	${val}	# Must be := since a simple = has no effect.
87SD.${val}:=		${SD_4_DOLLARS}
88.endfor
89.MAKE.SAVE_DOLLARS:=	yes
90
91save-dollars:
92.for val in ${SD_VALUES}
93	@printf '%s: %-8s = %s\n' $@ ${val} ${SD.${val}:Q}
94.endfor
95
96# Appending to an undefined variable does not add a space in front.
97.undef APPENDED
98APPENDED+=	value
99.if ${APPENDED} != "value"
100.  error "${APPENDED}"
101.endif
102
103# Appending to an empty variable adds a space between the old value
104# and the additional value.
105APPENDED=	# empty
106APPENDED+=	value
107.if ${APPENDED} != " value"
108.  error "${APPENDED}"
109.endif
110
111# Appending to parameterized variables works as well.
112PARAM=		param
113VAR.${PARAM}=	1
114VAR.${PARAM}+=	2
115.if ${VAR.param} != "1 2"
116.  error "${VAR.param}"
117.endif
118
119# The variable name can contain arbitrary characters.
120# If the expanded variable name ends in a +, this still does not influence
121# the parser. The assignment operator is still a simple assignment.
122# Therefore, there is no need to add a space between the variable name
123# and the assignment operator.
124PARAM=		+
125VAR.${PARAM}=	1
126VAR.${PARAM}+=	2
127.if ${VAR.+} != "1 2"
128.  error "${VAR.+}"
129.endif
130.for param in + ! ?
131VAR.${param}=	${param}
132.endfor
133.if ${VAR.+} != "+" || ${VAR.!} != "!" || ${VAR.?} != "?"
134.  error "${VAR.+}" "${VAR.!}" "${VAR.?}"
135.endif
136
137# Appending to a variable from the environment creates a copy of that variable
138# in the global scope.
139# The appended value is not exported automatically.
140# When a variable is exported, the exported value is taken at the time of the
141# .export directive. Later changes to the variable have no effect.
142.export FROM_ENV_BEFORE
143FROM_ENV+=		mk
144FROM_ENV_BEFORE+=	mk
145FROM_ENV_AFTER+=	mk
146.export FROM_ENV_AFTER
147
148export-appended:
149	@echo $@: "$$FROM_ENV"
150	@echo $@: "$$FROM_ENV_BEFORE"
151	@echo $@: "$$FROM_ENV_AFTER"
152
153# begin parse-dynamic
154#
155# Demonstrate that the target-specific variables are not evaluated in
156# the global scope. Their expressions are preserved until there is a local
157# scope in which resolving them makes sense.
158
159# There are different code paths for short names ...
160${:U>}=		before
161GS_TARGET:=	$@
162GS_MEMBER:=	$%
163GS_PREFIX:=	$*
164GS_ARCHIVE:=	$!
165GS_ALLSRC:=	$>
166${:U>}=		after
167# ... and for braced short names ...
168GB_TARGET:=	${@}
169GB_MEMBER:=	${%}
170GB_PREFIX:=	${*}
171GB_ARCHIVE:=	${!}
172GB_ALLSRC:=	${>}
173# ... and for long names.
174GL_TARGET:=	${.TARGET}
175GL_MEMBER:=	${.MEMBER}
176GL_PREFIX:=	${.PREFIX}
177GL_ARCHIVE:=	${.ARCHIVE}
178GL_ALLSRC:=	${.ALLSRC}
179
180parse-dynamic:
181	@echo $@: ${GS_TARGET} ${GS_MEMBER} ${GS_PREFIX} ${GS_ARCHIVE} ${GS_ALLSRC}
182	@echo $@: ${GB_TARGET} ${GB_MEMBER} ${GB_PREFIX} ${GB_ARCHIVE} ${GB_ALLSRC}
183	@echo $@: ${GL_TARGET} ${GL_MEMBER} ${GL_PREFIX} ${GL_ARCHIVE} ${GL_ALLSRC}
184
185# Since 2020-07-28, make complains about unclosed variables.
186# Before that, it had complained about unclosed variables only when
187# parsing the modifiers, but not when parsing the variable name.
188
189UNCLOSED_INDIR_1=	${UNCLOSED_ORIG
190UNCLOSED_INDIR_2=	${UNCLOSED_INDIR_1}
191
192FLAGS=	one two
193FLAGS+=	${FLAGS.${.ALLSRC:M*.c:T:u}}
194FLAGS.target2.c= three four
195
196target1.c:
197target2.c:
198
199all: target1-flags target2-flags
200target1-flags: target1.c
201	@echo $@: we have: ${FLAGS}
202
203target2-flags: target2.c
204	@echo $@: we have: ${FLAGS}
205
206varerror-unclosed:
207	@echo $@:begin
208	@echo $(
209	@echo $(UNCLOSED
210	@echo ${UNCLOSED
211	@echo ${UNCLOSED:M${PATTERN
212	@echo ${UNCLOSED.${param
213	@echo $
214.for i in 1 2 3
215	@echo ${UNCLOSED.${i}
216.endfor
217	@echo ${UNCLOSED_INDIR_2}
218	@echo $@:end
219