1#!/bin/sh
2#
3# Copyright (c) 2014-2015 Mike Frysinger <vapier@gentoo.org>
4# Copyright (c) 2014-2015 Dmitry V. Levin <ldv@altlinux.org>
5# Copyright (c) 2014-2017 The strace developers.
6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16# 3. The name of the author may not be used to endorse or promote products
17#    derived from this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30usage()
31{
32	cat <<EOF
33Usage: $0 <input> <output>
34
35Generate xlat header files from <input> (a file or dir of files) and write
36the generated headers to <output>.
37EOF
38	exit 1
39}
40
41cond_def()
42{
43	local line
44	line="$1"; shift
45
46	local val
47	val="$(printf %s "$line" |
48		sed -r -n 's/^([^[:space:]]+).*$/\1/p')"
49
50	local def
51	def="$(printf %s "${line}" |
52		sed -r -n 's/^[^[:space:]]+[[:space:]]+([^[:space:]].*)$/\1/p')"
53
54	if [ -n "$def" ]; then
55		cat <<-EOF
56		#if !(defined($val) || (defined(HAVE_DECL_$val) && HAVE_DECL_$val))
57		# define $val $def
58		#endif
59		EOF
60	fi
61}
62
63print_xlat()
64{
65	local val
66	val="$1"; shift
67
68	if [ -z "${val_type-}" ]; then
69		echo " XLAT(${val}),"
70	else
71		echo " XLAT_TYPE(${val_type}, ${val}),"
72	fi
73}
74
75print_xlat_pair()
76{
77	local val str
78	val="$1"; shift
79	str="$1"; shift
80
81	if [ -z "${val_type-}" ]; then
82		echo " XLAT_PAIR(${val}, \"${str}\"),"
83	else
84		echo " XLAT_TYPE_PAIR(${val_type}, ${val}, \"${str}\"),"
85	fi
86}
87
88cond_xlat()
89{
90	local line val m def xlat
91	line="$1"; shift
92
93	val="$(printf %s "${line}" | sed -r -n 's/^([^[:space:]]+).*$/\1/p')"
94	m="${val%%|*}"
95	def="$(printf %s "${line}" |
96	       sed -r -n 's/^[^[:space:]]+[[:space:]]+([^[:space:]].*)$/\1/p')"
97
98	if [ "${m}" = "${m#1<<}" ]; then
99		xlat="$(print_xlat "${val}")"
100	else
101		xlat="$(print_xlat_pair "1ULL<<${val#1<<}" "${val}")"
102		m="${m#1<<}"
103	fi
104
105	if [ -z "${def}" ]; then
106		cat <<-EOF
107		#if defined(${m}) || (defined(HAVE_DECL_${m}) && HAVE_DECL_${m})
108		 ${xlat}
109		#endif
110		EOF
111	else
112		echo "$xlat"
113	fi
114}
115
116gen_header()
117{
118	local input="$1" output="$2" name="$3"
119	echo "generating ${output}"
120	(
121	local defs="${0%/*}/../defs.h"
122	local mpers="${0%/*}/../mpers_xlat.h"
123	local decl="extern const struct xlat ${name}[];"
124	local in_defs= in_mpers=
125
126	if grep -F -x "$decl" "$defs" > /dev/null; then
127		in_defs=1
128	elif grep -F -x "$decl" "$mpers" > /dev/null; then
129		in_mpers=1
130	fi
131
132	echo "/* Generated by $0 from $1; do not edit. */"
133
134	local unconditional= unterminated= line
135	# 1st pass: output directives.
136	while read line; do
137		LC_COLLATE=C
138		line=$(printf "%s" "$line" | \
139			sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||")
140
141		case $line in
142		'#stop')
143			exit 0
144			;;
145		'#conditional')
146			unconditional=
147			;;
148		'#unconditional')
149			unconditional=1
150			;;
151		'#unterminated')
152			unterminated=1
153			;;
154		'#val_type '*)
155			# to be processed during 2nd pass
156			;;
157		'#'*)
158			echo "${line}"
159			;;
160		[A-Z_]*)
161			[ -n "$unconditional" ] ||
162				cond_def "$line"
163			;;
164		esac
165	done < "$input"
166
167	echo
168	if [ -n "$in_defs" ]; then
169		cat <<-EOF
170			#ifndef IN_MPERS
171
172		EOF
173	elif [ -n "$in_mpers" ]; then
174		cat <<-EOF
175			#ifdef IN_MPERS
176
177			${decl}
178
179			#else
180
181			# if !(defined HAVE_M32_MPERS || defined HAVE_MX32_MPERS)
182			static
183			# endif
184		EOF
185	else
186		cat <<-EOF
187			#ifdef IN_MPERS
188
189			# error static const struct xlat ${name} in mpers mode
190
191			#else
192
193			static
194		EOF
195	fi
196	echo "const struct xlat ${name}[] = {"
197
198	unconditional= val_type=
199	# 2nd pass: output everything.
200	while read line; do
201		LC_COLLATE=C
202		line=$(printf "%s" "$line" | \
203			sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||")
204
205		case ${line} in
206		'#conditional')
207			unconditional=
208			;;
209		'#unconditional')
210			unconditional=1
211			;;
212		'#unterminated')
213			# processed during 1st pass
214			;;
215		'#val_type '*)
216			val_type="${line#\#val_type }"
217			;;
218		[A-Z_]*)	# symbolic constants
219			if [ -n "${unconditional}" ]; then
220				print_xlat "${line}"
221			else
222				cond_xlat "${line}"
223			fi
224			;;
225		'1<<'[A-Z_]*)	# symbolic constants with shift
226			if [ -n "${unconditional}" ]; then
227				print_xlat_pair "1ULL<<${line#1<<}" "${line}"
228			else
229				cond_xlat "${line}"
230			fi
231			;;
232		[0-9]*)	# numeric constants
233			print_xlat "${line}"
234			;;
235		*)	# verbatim lines
236			echo "${line}"
237			;;
238		esac
239	done < "${input}"
240	if [ -n "${unterminated}" ]; then
241		echo " /* this array should remain not NULL-terminated */"
242	else
243		echo " XLAT_END"
244	fi
245
246	cat <<-EOF
247		};
248
249		#endif /* !IN_MPERS */
250	EOF
251	) >"${output}"
252}
253
254gen_make()
255{
256	local output="$1"
257	local name
258	shift
259	echo "generating ${output}"
260	(
261		printf "XLAT_INPUT_FILES = "
262		printf 'xlat/%s.in ' "$@"
263		echo
264		printf "XLAT_HEADER_FILES = "
265		printf 'xlat/%s.h ' "$@"
266		echo
267		for name; do
268			printf '$(top_srcdir)/xlat/%s.h: $(top_srcdir)/xlat/%s.in $(top_srcdir)/xlat/gen.sh\n' \
269				"${name}" "${name}"
270			echo '	$(AM_V_GEN)$(top_srcdir)/xlat/gen.sh $< $@'
271		done
272	) >"${output}"
273}
274
275gen_git()
276{
277	local output="$1"
278	shift
279	echo "generating ${output}"
280	(
281		printf '/%s\n' .gitignore Makemodule.am
282		printf '/%s.h\n' "$@"
283	) >"${output}"
284}
285
286main()
287{
288	case $# in
289	0) set -- "${0%/*}" "${0%/*}" ;;
290	2) ;;
291	*) usage ;;
292	esac
293
294	local input="$1"
295	local output="$2"
296	local name
297	local jobs=0
298	local ncpus="$(getconf _NPROCESSORS_ONLN)"
299	local pids=
300	[ "${ncpus}" -ge 1 ] ||
301		ncpus=1
302
303	if [ -d "${input}" ]; then
304		local f names=
305		for f in "${input}"/*.in; do
306			[ -f "${f}" ] || continue
307			name=${f##*/}
308			name=${name%.in}
309			gen_header "${f}" "${output}/${name}.h" "${name}" &
310			pids="$pids $!"
311			names="${names} ${name}"
312			: $(( jobs += 1 ))
313			if [ "${jobs}" -gt "$(( ncpus * 2 ))" ]; then
314				read wait_pid rest
315				pids="$rest"
316				wait -n 2>/dev/null || wait "$wait_pid"
317				: $(( jobs -= 1 ))
318			fi <<- EOF
319			$pids
320			EOF
321		done
322		gen_git "${output}/.gitignore" ${names} &
323		gen_make "${output}/Makemodule.am" ${names} &
324		wait
325	else
326		name=${input##*/}
327		name=${name%.in}
328		gen_header "${input}" "${output}" "${name}"
329	fi
330}
331
332main "$@"
333