Home | History | Annotate | Download | only in xlat
      1 #!/bin/sh -eu
      2 #
      3 # Copyright (c) 2014-2015 Mike Frysinger <vapier (at] gentoo.org>
      4 # Copyright (c) 2014-2015 Dmitry V. Levin <ldv (at] 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 
     30 usage()
     31 {
     32 	cat <<EOF
     33 Usage: $0 <input> <output>
     34 
     35 Generate xlat header files from <input> (a file or dir of files) and write
     36 the generated headers to <output>.
     37 EOF
     38 	exit 1
     39 }
     40 
     41 cond_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 
     67 print_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 
     80 print_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 
     94 cond_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 
    122 gen_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 
    271 gen_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 
    292 gen_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 
    303 main()
    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 
    349 main "$@"
    350