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