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