topgit_*_prepare.awk: do not append ^{} to missing
[topgit/pro.git] / gnomake.sh
blob72c8e0ff736ef9b3520eceef72f209755f8bbb2c
1 # gnomake.sh - POSIX Makefile.sh utility functions
2 # Copyright (C) 2017 Kyle J. McKay
3 # All rights reserved
4 # License GPL2
6 ##
7 ## Utility functions for Makefile.sh scripts
8 ##
10 # prevent crazy "sh" implementations from exporting functions into environment
11 set +a
13 # always run in errexit mode
14 set -e
16 # configsh sources config.sh if it exists and then sets
17 # CONFIGMAK to either Makefile.mt (if there is no config.mak)
18 # or "config.mak" if there is.
20 # If MKTOP is set, they are looked for there instead of in
21 # the current directory.
23 # The CONFIGDEPS variable will be set to the ones that exist
24 # (for use in dependency lines).
26 # wrap it up for safety
27 configsh() {
28 [ z"$MKTOP" = z"/" ] || MKTOP="${MKTOP%/}"
29 CONFIGDEPS=
30 ! [ -f "${MKTOP:+$MKTOP/}config.sh" ] || {
31 . ./"${MKTOP:+$MKTOP/}config.sh"
32 CONFIGDEPS="${CONFIGDEPS:+$CONFIGDEPS }${MKTOP:+$MKTOP/}config.sh"
34 # now set CONFIGMAK and make it an absolute path
35 [ -n "$CONFIGMAK" ] || CONFIGMAK="${MKTOP:+$MKTOP/}config.mak"
36 if [ -f "$CONFIGMAK" ]; then
37 CONFIGDEPS="${CONFIGDEPS:+$CONFIGDEPS }$CONFIGMAK"
38 else
39 CONFIGMAK="${MKTOP:+$MKTOP/}Makefile.mt"
41 case "$CONFIGMAK" in */?*);;*) CONFIGMAK="./$CONFIGMAK"; esac
42 CONFIGMAK="$(cd "${CONFIGMAK%/*}" && pwd)/${CONFIGMAK##*/}"
45 # "which" but using only POSIX shell built-ins
46 cmd_path() (
47 { "unset" -f command unset unalias "$1"; } >/dev/null 2>&1 || :
48 { "unalias" -a || unalias -m "*"; } >/dev/null 2>&1 || :
49 command -v "$1"
52 # set GNO_PD_OPT to --no-print-directory
53 # - unless GNO_PD_OPT is already set (even if to empty)
54 # - unless "w" appears in MAKEFLAGS (check skipped if first arg is not-empty)
55 # - the $(MAKE) binary does NOT contain GNUmakefile
56 # - the $(MAKE) binary does NOT produce a "GNU Make ..." --version line
57 set_gno_pd_opt() {
58 if test z"$GNO_PD_OPT" = z"--no-print-directory"; then
59 # It likes to sneak back in so rip it back out
60 case "$MAKEFLAGS" in "w"*)
61 MAKEFLAGS="${MAKEFLAGS#w}"
62 esac
63 return 0
65 test z"${GNO_PD_OPT+set}" != z"set" || return 0
66 GNO_PD_OPT=
67 if test z"$1" = z; then
68 case "${MAKEFLAGS%%[ =]*}" in *w*)
69 return 0
70 esac
72 set -- "$("${MAKE:-make}" --no-print-directory --version 2>/dev/null)" || :
73 case "$1" in "GNU "[Mm]"ake "*)
74 GNO_PD_OPT="--no-print-directory"
75 esac
76 return 0
79 # VAR += VAL
80 # => vplus VAR VAL
82 # vplus appends the second and following arguments (concatenated with a space)
83 # to the variable named by the first with a space if it's set and non-empty
84 # or otherwise it's just set. If there are no arguments nothing is done but
85 # appending an empty string will set the variable to empty if it's not set
86 vplus() {
87 test z"$1" != z || return 1
88 test $# -ge 2 || return 0
89 vplus_v_="$1"
90 shift
91 vplus_val_="$*"
92 set -- "$vplus_v_" "" "$vplus_val_"
93 unset vplus_v_ vplus_val_
94 eval set -- '"$1"' "\"\$$1\"" '"$3"'
95 set -- "$1" "${2:+$2 }$3"
96 eval "$1="'"$2"'
99 # vpre prepends the second and following arguments (concatenated with a space)
100 # to the variable named by the first with a space if it's set and non-empty
101 # or otherwise it's just set. If there are no arguments nothing is done but
102 # appending an empty string will set the variable to empty if it's not set
103 vpre() {
104 test z"$1" != z || return 1
105 test $# -ge 2 || return 0
106 vpre_v_="$1"
107 shift
108 vpre_val_="$*"
109 set -- "$vpre_v_" "" "$vpre_val_"
110 unset vpre_v_ vpre_val_
111 eval set -- '"$1"' "\"\$$1\"" '"$3"'
112 set -- "$1" "$3${2:+ $2}"
113 eval "$1="'"$2"'
116 # stores the single-quoted value of the variable name passed as
117 # the first argument into the variable name passed as the second
118 # (use quotevar 3 varname "$value" to quote a value directly)
119 quotevar() {
120 eval "set -- \"\${$1}\" \"$2\""
121 case "$1" in *"'"*)
122 set -- "$(printf '%s\nZ\n' "$1" | sed "s/'/'\\\''/g")" "$2"
123 set -- "${1%??}" "$2"
124 esac
125 eval "$2=\"'$1'\""
128 # The result(s) of stripping the second argument from the end of the
129 # third and following argument(s) is joined using a space and stored
130 # in the variable named by the first argument
131 v_strip_sfx() {
132 _var="$1"
133 _sfx="$2"
134 shift 2
135 _result=
136 for _item in "$@"; do
137 _result="$_result ${_item%$_sfx}"
138 done
139 eval "$_var="'"${_result# }"'
140 unset _var _sfx _result _item
143 # The result(s) of appending the second argument to the end of the
144 # third and following argument(s) is joined using a space and stored
145 # in the variable named by the first argument
146 v_add_sfx() {
147 _var="$1"
148 _sfx="$2"
149 shift 2
150 _result=
151 for _item in "$@"; do
152 _result="$_result $_item$_sfx"
153 done
154 eval "$_var="'"${_result# }"'
155 unset _var _sfx _result _item
158 # The result(s) of stripping the second argument from the end of the
159 # fourth and following argument(s) and then appending the third argument is
160 # joined using a space and stored in the variable named by the first argument
161 v_stripadd_sfx() {
162 _var2="$1"
163 _stripsfx="$2"
164 _addsfx="$3"
165 shift 3
166 v_strip_sfx _result2 "$_stripsfx" "$@"
167 v_add_sfx "$_var2" "$_addsfx" $_result2
168 unset _var2 _stripsfx _addsfx _result2
171 # The second and following argument(s) are joined with a space and
172 # stored in the variable named by the first argument
173 v_strip_() {
174 _var="$1"
175 shift
176 eval "$_var="'"$*"'
177 unset _var
180 # The second and following argument(s) are joined with a space and then
181 # the result has leading and trailing whitespace removed and internal
182 # whitespace sequences replaced with a single space and is then stored
183 # in the variable named by the first argument and pathname expansion is
184 # disabled during the stripping process
185 v_strip() {
186 _var="$1"
187 shift
188 set -f
189 v_strip_ "$_var" $*
190 set +f
193 # Expand the second and following argument(s) using pathname expansion but
194 # skipping any that have no match and join all the results using a space and
195 # store that in the variable named by the first argument
196 v_wildcard() {
197 _var="$1"
198 shift
199 _result=
200 for _item in "$@"; do
201 eval "_exp=\"\$(printf ' %s' $_item)\""
202 [ " $_item" = "$_exp" ] && ! [ -e "$_item" ] || _result="$_result$_exp"
203 done
204 eval "$_var="'"${_result# }"'
205 unset _var _result _item _exp
208 # Sort the second and following argument(s) removing duplicates and join all the
209 # results using a space and store that in the variable named by the first argument
210 v_sort() {
211 _var="$1"
212 _saveifs="$IFS"
213 shift
214 IFS='
216 set -- $(printf '%s\n' "$@" | LC_ALL=C sort -u)
217 IFS="$_saveifs"
218 eval "$_var="'"$*"'
219 unset _var _saveifs
222 # Filter the fourth and following argument(s) according to the space-separated
223 # list of '%' pattern(s) in the third argument doing a "filter-out" instead of
224 # a "filter" if the second argument is true and join all the results using a
225 # space and store that in the variable named by the first argument
226 v_filter_() {
227 _var="$1"
228 _fo="$2"
229 _pat="$3"
230 _saveifs="$IFS"
231 shift 3
232 IFS='
234 set -- $(awk -v "fo=$_fo" -f - "$_pat" "$*"<<'EOT'
235 function qr(p) {
236 gsub(/[][*?+.|{}()^$\\]/, "\\\\&", p)
237 return p
239 function qp(p) {
240 if (match(p, /\\*%/)) {
241 return qr(substr(p, 1, RSTART - 1)) \
242 substr(p, RSTART, RLENGTH - (2 - RLENGTH % 2)) \
243 (RLENGTH % 2 ? ".*" : "%") \
244 qr(substr(p, RSTART + RLENGTH))
246 else
247 return qr(p)
249 function qm(s, _l, _c, _a, _i, _g) {
250 if (!(_c = split(s, _l, " "))) return "^$"
251 if (_c == 1) return "^" qp(_l[1]) "$"
252 _a = ""
253 _g = "^("
254 for (_i = 1; _i <= _c; ++_i) {
255 _a = _a _g qp(_l[_i])
256 _g = "|"
258 return _a ")$"
260 BEGIN {exit}
261 END {
262 pat = ARGV[1]
263 vals = ARGV[2]
264 qpat = qm(pat)
265 cnt = split(vals, va, " ")
266 for (i=1; i<=cnt; ++i)
267 if ((va[i] ~ qpat) == !fo) print va[i]
271 IFS="$_saveifs"
272 eval "$_var="'"$*"'
273 unset _var _fo _pat _saveifs
276 # Filter the third and following argument(s) according to the space-separated
277 # list of '%' pattern(s) in the second argument and join all the results using
278 # a space and store that in the variable named by the first argument
279 v_filter() {
280 _var="$1"
281 shift
282 v_filter_ "$_var" "" "$@"
285 # Filter out the third and following argument(s) according to the space-separated
286 # list of '%' pattern(s) in the second argument and join all the results using
287 # a space and store that in the variable named by the first argument
288 v_filter_out() {
289 _var="$1"
290 shift
291 v_filter_ "$_var" "1" "$@"
294 # Write the third and following target arguments out as target with a dependency
295 # line(s) to standard output where each line is created by stripping the target
296 # argument suffix specified by the first argument ('' to strip nothing) and
297 # adding the suffix specified by the second argument ('' to add nothing).
298 # Does nothing if "$1" = "$2". (Set $1 = " " and $2 = "" to write out
299 # dependency lines with no prerequisites.)
300 write_auto_deps() {
301 [ "$1" != "$2" ] || return 0
302 _strip="$1"
303 _add="$2"
304 shift 2
305 for _targ in "$@"; do
306 printf '%s: %s\n' "$_targ" "${_targ%$_strip}$_add"
307 done
308 unset _strip _add _targ
311 # always turn on allexport now
312 set -a