1#! /bin/sh 2# $NetBSD: msg_xlat.sh,v 1.6 2021/10/11 18:46:34 rillig Exp $ 3 4#- 5# Copyright (c) 2003 The NetBSD Foundation, Inc. 6# All rights reserved. 7# 8# This code is derived from software contributed to The NetBSD Foundation 9# by David Laight. 10# 11# Redistribution and use in source and binary forms, with or without 12# modification, are permitted provided that the following conditions 13# are met: 14# 1. Redistributions of source code must retain the above copyright 15# notice, this list of conditions and the following disclaimer. 16# 2. Redistributions in binary form must reproduce the above copyright 17# notice, this list of conditions and the following disclaimer in the 18# documentation and/or other materials provided with the distribution. 19# 20# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30# POSSIBILITY OF SUCH DAMAGE. 31# 32 33PROG=$(basename "$0") 34usage() 35{ 36 echo "Usage: $PROG [-ci] [-d msg_defs.h] [-f fmt_count]" >&2 37 exit 1 38} 39 40error() 41{ 42 echo "$PROG: ERROR $@" >&2 43} 44 45IGNORE_MISSING_TRANSLATIONS=false 46count_fmtargs=false 47msg_defs=msg_defs.h 48 49while getopts cd:f:i f 50do 51 case "$f" in 52 c) count_fmtargs=true;; 53 d) msg_defs=$OPTARG;; 54 f) fmt_count=$OPTARG;; 55 i) IGNORE_MISSING_TRANSLATIONS=true;; 56 *) usage;; 57 esac 58done 59shift $(($OPTIND - 1)) 60if [ "$#" -ne 0 ]; then usage; fi 61 62nl=' 63' 64msg_long='((msg)(long)' 65close_paren=')' 66open_brace='{' 67close_brace='}' 68slash=/ 69 70rval=0 71 72# save stdin while we read the other files 73exec 3<&0 74 75# Read existing list of format arg counts 76if [ -n "$fmt_count" ]; then 77 exec <$fmt_count || exit 2 78 while read name count 79 do 80 eval count_$name=\$count 81 done 82fi 83 84# Read header file and set up map of message names to numbers 85 86exec <$msg_defs || exit 2 87 88while read define MSG_name number rest 89do 90 if [ -z "$number" ] || [ -n "$rest" ]; then continue; fi 91 if [ "$define" != "#define" ]; then continue; fi 92 93 name="${MSG_name#MSG_}" 94 if [ "$name" = "${MSG_name}" ]; then continue; fi 95 96 msg_number="${number#$msg_long}" 97 if [ "$msg_number" = "$number" ]; then continue; fi 98 msg_number="${msg_number%$close_paren}" 99 100 eval $MSG_name=$msg_number 101 eval MSGNUM_$msg_number=\$MSG_name 102 # eval echo \$$MSG_name \$MSGNUM_$msg_number 103done 104 105last_msg_number="$msg_number" 106 107# Read message definition file and set up map of numbers to strings 108 109exec <&3 3<&- 110 111name= 112msg= 113while 114 IFS= 115 read -r line 116do 117 if [ -z "$name" ]; then 118 IFS=" " 119 set -- $line 120 if [ "$1" != message ]; then continue; fi 121 name="$2" 122 eval number=\$MSG_$name 123 if [ -z "$number" ]; then 124 error "unknown message \"$name\"" 125 $IGNORE_MISSING_TRANSLATIONS || rval=1 126 number=unknown 127 fi 128 l=${line#*$open_brace} 129 if [ "$l" = "$line" ]; then continue; fi 130 line="{$l" 131 fi 132 if [ -z "$msg" ]; then 133 l=${line#$open_brace} 134 if [ "$l" = "$line" ]; then continue; fi 135 msg="$line" 136 else 137 msg="$msg$nl$line" 138 fi 139 m=${msg%$close_brace} 140 if [ "$m" = "$msg" ]; then 141 # Allow <tab>*/* comment */ (eg XXX translate) 142 m=${msg%%$close_brace*$slash[*]*[*]$slash} 143 if [ "$m" = "$msg" ]; then continue; fi 144 fi 145 # We need the %b to expand the \n that exist in the message file 146 msg=$(printf %bz "${m#$open_brace}") 147 msg=${msg%z} 148 eval old=\"\$MSGTEXT_$number\" 149 if [ -n "$old" ] && [ "$number" != unknown ]; then 150 error "Two translations for message \"$name\"" 151 $IGNORE_MISSING_TRANSLATIONS || rval=1 152 fi 153 eval MSGTEXT_$number=\"\${msg}\" 154 # echo $number $msg 155 sv_name="$name" 156 sv_msg="$msg" 157 name= 158 msg= 159 if ! $count_fmtargs && [ -z "$fmt_count" ]; then continue; fi 160 161 IFS=% 162 set -- $sv_msg 163 164 # For our purposes, empty messages are the same as words without % 165 if [ $# -eq 0 ]; then set -- x; fi 166 167 if $count_fmtargs; then 168 echo $number $# 169 continue 170 fi 171 eval count=\${count_$number:-unknown} 172 if [ "$count" -ne $# ]; then 173 error "Wrong number of format specifiers in \"$sv_name\", got $#, expected $count" 174 $IGNORE_MISSING_TRANSLATIONS || rval=1 175 fi 176done 177unset IFS 178 179if $count_fmtargs; then exit $rval; fi 180 181# Output the total number of messages and the offset of each in the file. 182# Use ascii numbers because generating target-ordered binary numbers 183# is just a smidgen tricky in the shell. 184 185offset=$(( 8 + $last_msg_number * 8 + 8 )) 186printf 'MSGTXTS\0%-7d\0' $last_msg_number 187 188msgnum=0 189while 190 msgnum=$(( $msgnum + 1 )) 191 [ "$msgnum" -le "$last_msg_number" ] 192do 193 eval msg=\${MSGTEXT_$msgnum} 194 if [ -z "$msg" ]; then 195 eval error "No translation for message \$MSGNUM_$msgnum" 196 printf '%-7d\0' 0 197 $IGNORE_MISSING_TRANSLATIONS || rval=1 198 continue 199 fi 200 printf '%-7d\0' $offset 201 offset=$(( $offset + ${#msg} + 1 )) 202done 203 204# Finally output and null terminate the messages. 205 206msgnum=0 207while 208 msgnum=$(( $msgnum + 1 )) 209 [ "$msgnum" -le "$last_msg_number" ] 210do 211 eval msg=\${MSGTEXT_$msgnum} 212 if [ -z "$msg" ]; then continue; fi 213 printf '%s\0' "$msg" 214done 215 216exit $rval 217