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