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 33 PROG=$(basename "$0") 34 usage() 35 { 36 echo "Usage: $PROG [-ci] [-d msg_defs.h] [-f fmt_count]" >&2 37 exit 1 38 } 39 40 error() 41 { 42 echo "$PROG: ERROR $@" >&2 43 } 44 45 IGNORE_MISSING_TRANSLATIONS=false 46 count_fmtargs=false 47 msg_defs=msg_defs.h 48 49 while getopts cd:f:i f 50 do 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 58 done 59 shift $(($OPTIND - 1)) 60 if [ "$#" -ne 0 ]; then usage; fi 61 62 nl=' 63 ' 64 msg_long='((msg)(long)' 65 close_paren=')' 66 open_brace='{' 67 close_brace='}' 68 slash=/ 69 70 rval=0 71 72 # save stdin while we read the other files 73 exec 3<&0 74 75 # Read existing list of format arg counts 76 if [ -n "$fmt_count" ]; then 77 exec <$fmt_count || exit 2 78 while read name count 79 do 80 eval count_$name=\$count 81 done 82 fi 83 84 # Read header file and set up map of message names to numbers 85 86 exec <$msg_defs || exit 2 87 88 while read define MSG_name number rest 89 do 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 103 done 104 105 last_msg_number="$msg_number" 106 107 # Read message definition file and set up map of numbers to strings 108 109 exec <&3 3<&- 110 111 name= 112 msg= 113 while 114 IFS= 115 read -r line 116 do 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 176 done 177 unset IFS 178 179 if $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 185 offset=$(( 8 + $last_msg_number * 8 + 8 )) 186 printf 'MSGTXTS\0%-7d\0' $last_msg_number 187 188 msgnum=0 189 while 190 msgnum=$(( $msgnum + 1 )) 191 [ "$msgnum" -le "$last_msg_number" ] 192 do 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 )) 202 done 203 204 # Finally output and null terminate the messages. 205 206 msgnum=0 207 while 208 msgnum=$(( $msgnum + 1 )) 209 [ "$msgnum" -le "$last_msg_number" ] 210 do 211 eval msg=\${MSGTEXT_$msgnum} 212 if [ -z "$msg" ]; then continue; fi 213 printf '%s\0' "$msg" 214 done 215 216 exit $rval 217