1#!/bin/sh -eu
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-2018 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		LC_ALL=C sed -r -n 's/^([[:alpha:]_][[:alnum:]_]*).*$/\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		DIAG_PUSH_IGNORE_TAUTOLOGICAL_COMPARE
58		static_assert(($val) == ($def), "$val != $def");
59		DIAG_POP_IGNORE_TAUTOLOGICAL_COMPARE
60		#else
61		# define $val $def
62		#endif
63		EOF
64	fi
65}
66
67print_xlat()
68{
69	local val
70	val="$1"; shift
71
72	[ 1 = "$value_indexed" ] && printf " [%s] =" "${val}"
73	if [ -z "${val_type-}" ]; then
74		echo " XLAT(${val}),"
75	else
76		echo " XLAT_TYPE(${val_type}, ${val}),"
77	fi
78}
79
80print_xlat_pair()
81{
82	local val str
83	val="$1"; shift
84	str="$1"; shift
85
86	[ 1 = "$value_indexed" ] && printf " [%s] =" "${val}"
87	if [ -z "${val_type-}" ]; then
88		echo " XLAT_PAIR(${val}, \"${str}\"),"
89	else
90		echo " XLAT_TYPE_PAIR(${val_type}, ${val}, \"${str}\"),"
91	fi
92}
93
94cond_xlat()
95{
96	local line val m def xlat
97	line="$1"; shift
98
99	val="$(printf %s "${line}" | sed -r -n 's/^([^[:space:]]+).*$/\1/p')"
100	m="${val%%|*}"
101	def="$(printf %s "${line}" |
102	       sed -r -n 's/^[^[:space:]]+[[:space:]]+([^[:space:]].*)$/\1/p')"
103
104	if [ "${m}" = "${m#1<<}" ]; then
105		xlat="$(print_xlat "${val}")"
106	else
107		xlat="$(print_xlat_pair "1ULL<<${val#1<<}" "${val}")"
108		m="${m#1<<}"
109	fi
110
111	if [ -z "${def}" ]; then
112		cat <<-EOF
113		#if defined(${m}) || (defined(HAVE_DECL_${m}) && HAVE_DECL_${m})
114		 ${xlat}
115		#endif
116		EOF
117	else
118		echo "$xlat"
119	fi
120}
121
122gen_header()
123{
124	local input="$1" output="$2" name="$3"
125	echo "generating ${output}"
126	(
127	local defs="${0%/*}/../defs.h"
128	local mpers="${0%/*}/../mpers_xlat.h"
129	local decl="extern const struct xlat ${name}[];"
130	local in_defs= in_mpers=
131
132	value_indexed=0
133
134	if grep -F -x "$decl" "$defs" > /dev/null; then
135		in_defs=1
136	elif grep -F -x "$decl" "$mpers" > /dev/null; then
137		in_mpers=1
138	fi
139
140	cat <<-EOF
141	/* Generated by $0 from $1; do not edit. */
142
143	#include "gcc_compat.h"
144	#include "static_assert.h"
145
146	EOF
147
148	local unconditional= line
149	# 1st pass: output directives.
150	while read line; do
151		LC_COLLATE=C
152		line=$(printf "%s" "$line" | \
153			sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||")
154
155		case $line in
156		'#stop')
157			exit 0
158			;;
159		'#conditional')
160			unconditional=
161			;;
162		'#unconditional')
163			unconditional=1
164			;;
165		'#val_type '*)
166			# to be processed during 2nd pass
167			;;
168		'#value_indexed')
169			value_indexed=1
170			;;
171		'#'*)
172			echo "${line}"
173			;;
174		[A-Z_]*)
175			[ -n "$unconditional" ] ||
176				cond_def "$line"
177			;;
178		esac
179	done < "$input"
180
181	cat <<-EOF
182
183		#ifndef XLAT_MACROS_ONLY
184
185	EOF
186
187	if [ -n "$in_defs" ]; then
188		cat <<-EOF
189			# ifndef IN_MPERS
190
191		EOF
192	elif [ -n "$in_mpers" ]; then
193		cat <<-EOF
194			# ifdef IN_MPERS
195
196			${decl}
197
198			# else
199
200			#  if !(defined HAVE_M32_MPERS || defined HAVE_MX32_MPERS)
201			static
202			#  endif
203		EOF
204	else
205		cat <<-EOF
206			# ifdef IN_MPERS
207
208			#  error static const struct xlat ${name} in mpers mode
209
210			# else
211
212			static
213		EOF
214	fi
215
216	echo "const struct xlat ${name}[] = {"
217
218	unconditional= val_type=
219	# 2nd pass: output everything.
220	while read line; do
221		LC_COLLATE=C
222		line=$(printf "%s" "$line" | \
223			sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||")
224
225		case ${line} in
226		'#conditional')
227			unconditional=
228			;;
229		'#unconditional')
230			unconditional=1
231			;;
232		'#value_indexed')
233			;;
234		'#val_type '*)
235			val_type="${line#\#val_type }"
236			;;
237		[A-Z_]*)	# symbolic constants
238			if [ -n "${unconditional}" ]; then
239				print_xlat "${line}"
240			else
241				cond_xlat "${line}"
242			fi
243			;;
244		'1<<'[A-Z_]*)	# symbolic constants with shift
245			if [ -n "${unconditional}" ]; then
246				print_xlat_pair "1ULL<<${line#1<<}" "${line}"
247			else
248				cond_xlat "${line}"
249			fi
250			;;
251		[0-9]*)	# numeric constants
252			print_xlat "${line}"
253			;;
254		*)	# verbatim lines
255			echo "${line}"
256			;;
257		esac
258	done < "${input}"
259	echo ' XLAT_END'
260
261	cat <<-EOF
262		};
263
264		# endif /* !IN_MPERS */
265
266		#endif /* !XLAT_MACROS_ONLY */
267	EOF
268	) >"${output}"
269}
270
271gen_make()
272{
273	local output="$1"
274	local name
275	shift
276	echo "generating ${output}"
277	(
278		printf "XLAT_INPUT_FILES = "
279		printf 'xlat/%s.in ' "$@"
280		echo
281		printf "XLAT_HEADER_FILES = "
282		printf 'xlat/%s.h ' "$@"
283		echo
284		for name; do
285			printf '$(top_srcdir)/xlat/%s.h: $(top_srcdir)/xlat/%s.in $(top_srcdir)/xlat/gen.sh\n' \
286				"${name}" "${name}"
287			echo '	$(AM_V_GEN)$(top_srcdir)/xlat/gen.sh $< $@'
288		done
289	) >"${output}"
290}
291
292gen_git()
293{
294	local output="$1"
295	shift
296	echo "generating ${output}"
297	(
298		printf '/%s\n' .gitignore Makemodule.am
299		printf '/%s.h\n' "$@"
300	) >"${output}"
301}
302
303main()
304{
305	case $# in
306	0) set -- "${0%/*}" "${0%/*}" ;;
307	2) ;;
308	*) usage ;;
309	esac
310
311	local input="$1"
312	local output="$2"
313	local name
314	local jobs=0
315	local ncpus="$(getconf _NPROCESSORS_ONLN)"
316	local pids=
317	[ "${ncpus}" -ge 1 ] ||
318		ncpus=1
319
320	if [ -d "${input}" ]; then
321		local f names=
322		for f in "${input}"/*.in; do
323			[ -f "${f}" ] || continue
324			name=${f##*/}
325			name=${name%.in}
326			gen_header "${f}" "${output}/${name}.h" "${name}" &
327			pids="$pids $!"
328			names="${names} ${name}"
329			: $(( jobs += 1 ))
330			if [ "${jobs}" -gt "$(( ncpus * 2 ))" ]; then
331				read wait_pid rest
332				pids="$rest"
333				wait -n 2>/dev/null || wait "$wait_pid"
334				: $(( jobs -= 1 ))
335			fi <<- EOF
336			$pids
337			EOF
338		done
339		gen_git "${output}/.gitignore" ${names} &
340		gen_make "${output}/Makemodule.am" ${names} &
341		wait
342	else
343		name=${input##*/}
344		name=${name%.in}
345		gen_header "${input}" "${output}" "${name}"
346	fi
347}
348
349main "$@"
350