#!/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 "$@"