msg_xlat.sh revision 1.5 1 1.1 dholland #! /bin/sh
2 1.5 kre # $NetBSD: msg_xlat.sh,v 1.5 2021/07/12 19:03:20 kre 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.1 dholland # Read message definition file and set up map of munbers 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.3 cjep
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