350 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
| #!/bin/sh -eu
 | |
| #
 | |
| # Copyright (c) 2014-2015 Mike Frysinger <vapier@gentoo.org>
 | |
| # Copyright (c) 2014-2015 Dmitry V. Levin <ldv@altlinux.org>
 | |
| # Copyright (c) 2014-2018 The strace developers.
 | |
| # All rights reserved.
 | |
| #
 | |
| # Redistribution and use in source and binary forms, with or without
 | |
| # modification, are permitted provided that the following conditions
 | |
| # are met:
 | |
| # 1. Redistributions of source code must retain the above copyright
 | |
| #    notice, this list of conditions and the following disclaimer.
 | |
| # 2. Redistributions in binary form must reproduce the above copyright
 | |
| #    notice, this list of conditions and the following disclaimer in the
 | |
| #    documentation and/or other materials provided with the distribution.
 | |
| # 3. The name of the author may not be used to endorse or promote products
 | |
| #    derived from this software without specific prior written permission.
 | |
| #
 | |
| # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | |
| # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
| # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
| # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
| # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
| # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
| # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
| 
 | |
| usage()
 | |
| {
 | |
| 	cat <<EOF
 | |
| Usage: $0 <input> <output>
 | |
| 
 | |
| Generate xlat header files from <input> (a file or dir of files) and write
 | |
| the generated headers to <output>.
 | |
| EOF
 | |
| 	exit 1
 | |
| }
 | |
| 
 | |
| cond_def()
 | |
| {
 | |
| 	local line
 | |
| 	line="$1"; shift
 | |
| 
 | |
| 	local val
 | |
| 	val="$(printf %s "$line" |
 | |
| 		LC_ALL=C sed -r -n 's/^([[:alpha:]_][[:alnum:]_]*).*$/\1/p')"
 | |
| 
 | |
| 	local def
 | |
| 	def="$(printf %s "${line}" |
 | |
| 		sed -r -n 's/^[^[:space:]]+[[:space:]]+([^[:space:]].*)$/\1/p')"
 | |
| 
 | |
| 	if [ -n "$def" ]; then
 | |
| 		cat <<-EOF
 | |
| 		#if defined($val) || (defined(HAVE_DECL_$val) && HAVE_DECL_$val)
 | |
| 		DIAG_PUSH_IGNORE_TAUTOLOGICAL_COMPARE
 | |
| 		static_assert(($val) == ($def), "$val != $def");
 | |
| 		DIAG_POP_IGNORE_TAUTOLOGICAL_COMPARE
 | |
| 		#else
 | |
| 		# define $val $def
 | |
| 		#endif
 | |
| 		EOF
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| print_xlat()
 | |
| {
 | |
| 	local val
 | |
| 	val="$1"; shift
 | |
| 
 | |
| 	[ 1 = "$value_indexed" ] && printf " [%s] =" "${val}"
 | |
| 	if [ -z "${val_type-}" ]; then
 | |
| 		echo " XLAT(${val}),"
 | |
| 	else
 | |
| 		echo " XLAT_TYPE(${val_type}, ${val}),"
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| print_xlat_pair()
 | |
| {
 | |
| 	local val str
 | |
| 	val="$1"; shift
 | |
| 	str="$1"; shift
 | |
| 
 | |
| 	[ 1 = "$value_indexed" ] && printf " [%s] =" "${val}"
 | |
| 	if [ -z "${val_type-}" ]; then
 | |
| 		echo " XLAT_PAIR(${val}, \"${str}\"),"
 | |
| 	else
 | |
| 		echo " XLAT_TYPE_PAIR(${val_type}, ${val}, \"${str}\"),"
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| cond_xlat()
 | |
| {
 | |
| 	local line val m def xlat
 | |
| 	line="$1"; shift
 | |
| 
 | |
| 	val="$(printf %s "${line}" | sed -r -n 's/^([^[:space:]]+).*$/\1/p')"
 | |
| 	m="${val%%|*}"
 | |
| 	def="$(printf %s "${line}" |
 | |
| 	       sed -r -n 's/^[^[:space:]]+[[:space:]]+([^[:space:]].*)$/\1/p')"
 | |
| 
 | |
| 	if [ "${m}" = "${m#1<<}" ]; then
 | |
| 		xlat="$(print_xlat "${val}")"
 | |
| 	else
 | |
| 		xlat="$(print_xlat_pair "1ULL<<${val#1<<}" "${val}")"
 | |
| 		m="${m#1<<}"
 | |
| 	fi
 | |
| 
 | |
| 	if [ -z "${def}" ]; then
 | |
| 		cat <<-EOF
 | |
| 		#if defined(${m}) || (defined(HAVE_DECL_${m}) && HAVE_DECL_${m})
 | |
| 		 ${xlat}
 | |
| 		#endif
 | |
| 		EOF
 | |
| 	else
 | |
| 		echo "$xlat"
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| gen_header()
 | |
| {
 | |
| 	local input="$1" output="$2" name="$3"
 | |
| 	echo "generating ${output}"
 | |
| 	(
 | |
| 	local defs="${0%/*}/../defs.h"
 | |
| 	local mpers="${0%/*}/../mpers_xlat.h"
 | |
| 	local decl="extern const struct xlat ${name}[];"
 | |
| 	local in_defs= in_mpers=
 | |
| 
 | |
| 	value_indexed=0
 | |
| 
 | |
| 	if grep -F -x "$decl" "$defs" > /dev/null; then
 | |
| 		in_defs=1
 | |
| 	elif grep -F -x "$decl" "$mpers" > /dev/null; then
 | |
| 		in_mpers=1
 | |
| 	fi
 | |
| 
 | |
| 	cat <<-EOF
 | |
| 	/* Generated by $0 from $1; do not edit. */
 | |
| 
 | |
| 	#include "gcc_compat.h"
 | |
| 	#include "static_assert.h"
 | |
| 
 | |
| 	EOF
 | |
| 
 | |
| 	local unconditional= line
 | |
| 	# 1st pass: output directives.
 | |
| 	while read line; do
 | |
| 		LC_COLLATE=C
 | |
| 		line=$(printf "%s" "$line" | \
 | |
| 			sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||")
 | |
| 
 | |
| 		case $line in
 | |
| 		'#stop')
 | |
| 			exit 0
 | |
| 			;;
 | |
| 		'#conditional')
 | |
| 			unconditional=
 | |
| 			;;
 | |
| 		'#unconditional')
 | |
| 			unconditional=1
 | |
| 			;;
 | |
| 		'#val_type '*)
 | |
| 			# to be processed during 2nd pass
 | |
| 			;;
 | |
| 		'#value_indexed')
 | |
| 			value_indexed=1
 | |
| 			;;
 | |
| 		'#'*)
 | |
| 			echo "${line}"
 | |
| 			;;
 | |
| 		[A-Z_]*)
 | |
| 			[ -n "$unconditional" ] ||
 | |
| 				cond_def "$line"
 | |
| 			;;
 | |
| 		esac
 | |
| 	done < "$input"
 | |
| 
 | |
| 	cat <<-EOF
 | |
| 
 | |
| 		#ifndef XLAT_MACROS_ONLY
 | |
| 
 | |
| 	EOF
 | |
| 
 | |
| 	if [ -n "$in_defs" ]; then
 | |
| 		cat <<-EOF
 | |
| 			# ifndef IN_MPERS
 | |
| 
 | |
| 		EOF
 | |
| 	elif [ -n "$in_mpers" ]; then
 | |
| 		cat <<-EOF
 | |
| 			# ifdef IN_MPERS
 | |
| 
 | |
| 			${decl}
 | |
| 
 | |
| 			# else
 | |
| 
 | |
| 			#  if !(defined HAVE_M32_MPERS || defined HAVE_MX32_MPERS)
 | |
| 			static
 | |
| 			#  endif
 | |
| 		EOF
 | |
| 	else
 | |
| 		cat <<-EOF
 | |
| 			# ifdef IN_MPERS
 | |
| 
 | |
| 			#  error static const struct xlat ${name} in mpers mode
 | |
| 
 | |
| 			# else
 | |
| 
 | |
| 			static
 | |
| 		EOF
 | |
| 	fi
 | |
| 
 | |
| 	echo "const struct xlat ${name}[] = {"
 | |
| 
 | |
| 	unconditional= val_type=
 | |
| 	# 2nd pass: output everything.
 | |
| 	while read line; do
 | |
| 		LC_COLLATE=C
 | |
| 		line=$(printf "%s" "$line" | \
 | |
| 			sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||")
 | |
| 
 | |
| 		case ${line} in
 | |
| 		'#conditional')
 | |
| 			unconditional=
 | |
| 			;;
 | |
| 		'#unconditional')
 | |
| 			unconditional=1
 | |
| 			;;
 | |
| 		'#value_indexed')
 | |
| 			;;
 | |
| 		'#val_type '*)
 | |
| 			val_type="${line#\#val_type }"
 | |
| 			;;
 | |
| 		[A-Z_]*)	# symbolic constants
 | |
| 			if [ -n "${unconditional}" ]; then
 | |
| 				print_xlat "${line}"
 | |
| 			else
 | |
| 				cond_xlat "${line}"
 | |
| 			fi
 | |
| 			;;
 | |
| 		'1<<'[A-Z_]*)	# symbolic constants with shift
 | |
| 			if [ -n "${unconditional}" ]; then
 | |
| 				print_xlat_pair "1ULL<<${line#1<<}" "${line}"
 | |
| 			else
 | |
| 				cond_xlat "${line}"
 | |
| 			fi
 | |
| 			;;
 | |
| 		[0-9]*)	# numeric constants
 | |
| 			print_xlat "${line}"
 | |
| 			;;
 | |
| 		*)	# verbatim lines
 | |
| 			echo "${line}"
 | |
| 			;;
 | |
| 		esac
 | |
| 	done < "${input}"
 | |
| 	echo ' XLAT_END'
 | |
| 
 | |
| 	cat <<-EOF
 | |
| 		};
 | |
| 
 | |
| 		# endif /* !IN_MPERS */
 | |
| 
 | |
| 		#endif /* !XLAT_MACROS_ONLY */
 | |
| 	EOF
 | |
| 	) >"${output}"
 | |
| }
 | |
| 
 | |
| gen_make()
 | |
| {
 | |
| 	local output="$1"
 | |
| 	local name
 | |
| 	shift
 | |
| 	echo "generating ${output}"
 | |
| 	(
 | |
| 		printf "XLAT_INPUT_FILES = "
 | |
| 		printf 'xlat/%s.in ' "$@"
 | |
| 		echo
 | |
| 		printf "XLAT_HEADER_FILES = "
 | |
| 		printf 'xlat/%s.h ' "$@"
 | |
| 		echo
 | |
| 		for name; do
 | |
| 			printf '$(top_srcdir)/xlat/%s.h: $(top_srcdir)/xlat/%s.in $(top_srcdir)/xlat/gen.sh\n' \
 | |
| 				"${name}" "${name}"
 | |
| 			echo '	$(AM_V_GEN)$(top_srcdir)/xlat/gen.sh $< $@'
 | |
| 		done
 | |
| 	) >"${output}"
 | |
| }
 | |
| 
 | |
| gen_git()
 | |
| {
 | |
| 	local output="$1"
 | |
| 	shift
 | |
| 	echo "generating ${output}"
 | |
| 	(
 | |
| 		printf '/%s\n' .gitignore Makemodule.am
 | |
| 		printf '/%s.h\n' "$@"
 | |
| 	) >"${output}"
 | |
| }
 | |
| 
 | |
| main()
 | |
| {
 | |
| 	case $# in
 | |
| 	0) set -- "${0%/*}" "${0%/*}" ;;
 | |
| 	2) ;;
 | |
| 	*) usage ;;
 | |
| 	esac
 | |
| 
 | |
| 	local input="$1"
 | |
| 	local output="$2"
 | |
| 	local name
 | |
| 	local jobs=0
 | |
| 	local ncpus="$(getconf _NPROCESSORS_ONLN)"
 | |
| 	local pids=
 | |
| 	[ "${ncpus}" -ge 1 ] ||
 | |
| 		ncpus=1
 | |
| 
 | |
| 	if [ -d "${input}" ]; then
 | |
| 		local f names=
 | |
| 		for f in "${input}"/*.in; do
 | |
| 			[ -f "${f}" ] || continue
 | |
| 			name=${f##*/}
 | |
| 			name=${name%.in}
 | |
| 			gen_header "${f}" "${output}/${name}.h" "${name}" &
 | |
| 			pids="$pids $!"
 | |
| 			names="${names} ${name}"
 | |
| 			: $(( jobs += 1 ))
 | |
| 			if [ "${jobs}" -gt "$(( ncpus * 2 ))" ]; then
 | |
| 				read wait_pid rest
 | |
| 				pids="$rest"
 | |
| 				wait -n 2>/dev/null || wait "$wait_pid"
 | |
| 				: $(( jobs -= 1 ))
 | |
| 			fi <<- EOF
 | |
| 			$pids
 | |
| 			EOF
 | |
| 		done
 | |
| 		gen_git "${output}/.gitignore" ${names} &
 | |
| 		gen_make "${output}/Makemodule.am" ${names} &
 | |
| 		wait
 | |
| 	else
 | |
| 		name=${input##*/}
 | |
| 		name=${name%.in}
 | |
| 		gen_header "${input}" "${output}" "${name}"
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| main "$@"
 |