1#!/usr/bin/ksh93 2export PATH=/usr/ast/bin:/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:${PATH} 3builtin date 4######################################################################## 5# # 6# This software is part of the ast package # 7# Copyright (c) 2000-2011 AT&T Intellectual Property # 8# and is licensed under the # 9# Eclipse Public License, Version 1.0 # 10# by AT&T Intellectual Property # 11# # 12# A copy of the License is available at # 13# http://www.eclipse.org/org/documents/epl-v10.html # 14# (with md5 checksum b35adb5213ca9657e911e9befb180842) # 15# # 16# Information and Software Systems Research # 17# AT&T Research # 18# Florham Park NJ # 19# # 20# Glenn Fowler <gsf@research.att.com> # 21# # 22######################################################################## 23: C language message catalog compiler 24 25# NOTE: all variable names match __*__ to avoid clash with msgcpp def vars 26 27__command__=msgcc 28integer __similar__=30 29 30case `(getopts '[-][123:xyz]' opt --xyz; echo 0$opt) 2>/dev/null` in 310123) ARGV0="-a $__command__" 32 USAGE=$' 33[-? 34@(#)$Id: msgcc (AT&T Labs Research) 2010-10-20 $ 35] 36'$USAGE_LICENSE$' 37[+NAME?msgcc - C language message catalog compiler] 38[+DESCRIPTION?\bmsgcc\b is a C language message catalog compiler. It accepts 39 \bcc\b(1) style options and arguments. A \bmsgcpp\b(1) \b.mso\b file 40 is generated for each input \b.c\b file. If the \b-c\b option is not 41 specified then a \bgencat\b(1) format \b.msg\b file is generated from 42 the input \b.mso\b and \b.msg\b files. If \b-c\b is not specified then 43 a \b.msg\b suffix is appended to the \b-o\b \afile\a if it doesn\'t 44 already have a suffix. The default output is \ba.out.msg\b if \b-c\b 45 and \b-o\b are not specified.] 46[+?If \b-M-new\b is not specified then messages are merged with those in the 47 pre-existing \b-o\b file.] 48[M?Set a \bmsgcc\b specific \aoption\a. \aoption\a may be:]:[-option]{ 49 [+mkmsgs?The \b-o\b file is assumed to be in \bmkmsgs\b(1) format.] 50 [+new?Create a new \b-o\b file.] 51 [+preserve?Messages in the \b-o\b file that are not in new 52 \b.msg\b file arguments are preserved. The default is to 53 either reuse the message numbers with new message text that 54 is similar to the old or to delete the message text, leaving 55 an unused message number.] 56 [+set=\anumber\a?Set the message set number to \anumber\a. The default 57 is \b1\b.] 58 [+similar=\anumber\a?The message text similarity measure threshold. 59 The similarity measure between \aold\a and \anew\a message 60 text is 100*(2*gzip(\aold\a+\anew\a)/(gzip(\aold\a)+gzip(\anew\a))-1), 61 where gzip(\ax\a) is the size of text \ax\a when compressed by 62 \bgzip\b(1). The default threshold is '$__similar__$'. A 63 threshold of \b0\b turns off message replacement, but unused 64 old messages are still deleted. Use \b-M-preserve\b to preserve 65 all old messages.] 66 [+verbose?Trace similar message replacements on the standard error.] 67} 68 69file ... 70 71[+SEE ALSO?\bcc\b(1), \bcpp\b(1), \bgencat\b(1), \bmsggen\b(1), 72 \bmsgcpp\b(1), \bmsgcvt\b(1)] 73' 74 ;; 75*) ARGV0="" 76 USAGE="M:[-option] [ cc-options ] file ..." 77 ;; 78esac 79 80usage() 81{ 82 OPTIND=0 83 getopts $ARGV0 "$USAGE" OPT '-?' 84 exit 2 85} 86 87keys() 88{ 89 $1 --??keys -- 2>&1 | grep '^".*"$' 90} 91 92typeset -A __index__ 93typeset __keep__ __text__ __drop__ __oz__ __nz__ __z__ __hit__ __hit_i__ 94typeset __compile__ __debug__ __mkmsgs__ __preprocess__ 95typeset __merge__=1 __preserve__ __verbose__ 96integer __i__=0 __args__=0 __code__=0 __files__=0 __max__=0 __num__=0 __skip__=0 97integer __set__=1 __sources__=0 __cmds__=0 __ndrop__=0 __new__=0 __old__=0 98__out__=a.out.msg 99__OUT__= 100 101case " $* " in 102*" --"*|*" -?"*) 103 while getopts $ARGV0 "$USAGE" OPT 104 do case $OPT in 105 *) break ;; 106 esac 107 done 108 ;; 109esac 110while : 111do case $# in 112 0) break ;; 113 esac 114 __arg__=$1 115 case $__arg__ in 116 -c) __compile__=1 117 ;; 118 -[DIU]*)__argv__[__args__]=$__arg__ 119 (( __args__++ )) 120 ;; 121 -E) __preprocess__=1 122 ;; 123 -M-debug) 124 __debug__=1 125 ;; 126 -M-mkmsgs) 127 __mkmsgs__=1 128 ;; 129 -M-new) __merge__= 130 ;; 131 -M-perserve) 132 __preserve__=1 133 ;; 134 -M-set=*) 135 __set__=$(msggen -s ${__arg__#*=}.1) 136 ;; 137 -M-similar=*) 138 __similar__=${__arg__#*=} 139 ;; 140 -M-verbose) 141 __verbose__=1 142 ;; 143 -o) case $# in 144 1) print -u2 $"$__command__: output argument expected" 145 exit 1 146 ;; 147 esac 148 shift 149 __out__=${1%.*}.msg 150 __OUT__=$1 151 ;; 152 [-+]*|*.[aAlLsS]*) 153 ;; 154 *.[cCiI]*|*.[oO]*) 155 case $__arg__ in 156 *.[oO]*);; 157 *) __srcv__[__files__]=$__arg__ 158 (( __sources__++ )) 159 ;; 160 esac 161 __arg__=${__arg__##*/} 162 __arg__=${__arg__%.*}.mso 163 __objv__[__files__]=$__arg__ 164 (( __files__++ )) 165 ;; 166 *.ms[go]) 167 __objv__[__files__]=$__arg__ 168 (( __files__++ )) 169 ;; 170 *) __cmdv__[__cmds__]=$__arg__ 171 (( __cmds__++ )) 172 ;; 173 esac 174 shift 175done 176__arg__=${__out__##*/} 177__arg__=${__arg__%.msg} 178if [[ -x $__arg__ ]] 179then __cmdv__[__cmds__]=$__arg__ 180 (( __cmds__++ )) 181fi 182 183# generate the .mso files 184 185if [[ $__OUT__ && $__compile__ ]] 186then __objv__[0]=$__OUT__ 187fi 188 189if (( __sources__ )) 190then for (( __i__=0; __i__<=__files__; __i__++ )) 191 do if [[ ${__srcv__[__i__]} ]] 192 then if (( __sources__ > 1 )) 193 then print "${__srcv__[__i__]}:" 194 fi 195 if [[ $__preprocess__ ]] 196 then msgcpp "${__argv__[@]}" "${__srcv__[__i__]}" 197 else msgcpp "${__argv__[@]}" "${__srcv__[__i__]}" > "${__objv__[__i__]}" 198 fi 199 fi 200 done 201fi 202 203# combine the .mso and .msg files 204 205if [[ ! $__compile__ && ! $__preprocess__ ]] 206then if [[ $__merge__ && -r $__out__ ]] 207 then __tmp__=$__out__.tmp 208 trap '__code__=$?; rm -f ${__tmp__}*; exit $__code__' 0 1 2 209 while read -r __line__ 210 do if (( $__skip__ )) 211 then if [[ $__line__ == '%}'* ]] 212 then __skip__=0 213 fi 214 continue 215 fi 216 if [[ $__mkmsgs__ && $__line__ == '%{'* ]] 217 then __skip__=1 218 continue 219 fi 220 if [[ $__mkmsgs__ ]] 221 then if [[ $__line__ == '%#'*';;'* ]] 222 then __line__=${__line__#'%#'} 223 __num__=${__line__%';;'*} 224 read -r __line__ 225 elif [[ $__line__ == %* ]] 226 then continue 227 else print -u2 $"$__command__: unrecognized line=$__line__" 228 __code__=1 229 fi 230 else case $__line__ in 231 +([0-9])' '*) 232 __num__=${__line__%%' '*} 233 __line__=${__line__#*'"'} 234 __line__=${__line__%'"'} 235 ;; 236 *) continue 237 ;; 238 esac 239 fi 240 __index__["$__line__"]=$__num__ 241 __text__[$__num__]=$__line__ 242 if (( __max__ < __num__ )) 243 then (( __max__=__num__ )) 244 fi 245 done < $__out__ 246 (( __new__=__max__+1 )) 247 else __tmp__=$__out__ 248 (( __new__=1 )) 249 fi 250 if (( __code__ )) 251 then exit $__code__ 252 fi 253 exec 1>$__tmp__ 9>&1 254 print -r -- '$'" ${__out__%.msg} message catalog" 255 print -r -- '$translation'" $__command__ $(date +%Y-%m-%d)" 256 print -r -- '$set'" $__set__" 257 print -r -- '$quote "' 258 sort -u "${__objv__[@]}" | { 259 __raw__= 260 while read -r __line__ 261 do __op__=${__line__%% *} 262 __line__=${__line__#* } 263 case $__op__ in 264 cmd) __a1__=${__line__%% *} 265 case $__a1__ in 266 dot_cmd) __a1__=. ;; 267 esac 268 keys $__a1__ 269 ;; 270 def) __a1__=${__line__%% *} 271 __a2__=${__line__#* } 272 eval $__a1__='$'__a2__ 273 ;; 274 str) print -r -- "$__line__" 275 ;; 276 raw) __raw__=$__raw__$'\n'$__line__ 277 ;; 278 var) __a1__=${__line__%% *} 279 __a2__=${__line__#* } 280 case $__a1__ in 281 [[:digit:]]*) 282 eval __v__='$'$__a2__ 283 __v__='"'${__v__:__a1__+1} 284 ;; 285 *) eval __v__='$'$__a1__ 286 ;; 287 esac 288 if [[ $__v__ == '"'*'"' ]] 289 then print -r -- "$__v__" 290 fi 291 ;; 292 [[:digit:]]*) 293 [[ $__preserve__ ]] && print -r -- "$__line__" 294 ;; 295 '$') print -r -u9 $__op__ include $__line__ 296 ;; 297 esac 298 done 299 for (( __i__=0; __i__ < __cmds__; __i__++ )) 300 do keys ${__cmdv__[__i__]} 301 done 302 [[ $__raw__ ]] && print -r "${__raw__#?}" | sed -e 's/^"//' -e 's/"$//' -e 's/\\/&&/g' -e 's/"/\\"/g' -e 's/.*/$RAW$"&"/' 303 } | { 304 __num__=1 305 while read -r __line__ 306 do case $__line__ in 307 '$RAW$'*) 308 ;; 309 '$'[\ \ ]*) 310 print -r -- "$__line__" 311 continue 312 ;; 313 '$'*|*"@(#)"*|*"<"*([[:word:] .-])"@"*([[:word:] .-])">"*([ ])'"'|"http://"*) 314 continue 315 ;; 316 *[[:alpha:]][[:alpha:]]*) 317 ;; 318 *) continue 319 ;; 320 esac 321 __line__=${__line__#*'"'} 322 __line__=${__line__%'"'} 323 if [[ $__line__ ]] 324 then if [[ ${__index__["$__line__"]} ]] 325 then if [[ ! $__preserve__ ]] 326 then __num__=${__index__["$__line__"]} 327 __keep__[$__num__]=1 328 fi 329 else while [[ ${__text__[$__num__]} ]] 330 do (( __num__++ )) 331 done 332 if (( __max__ < __num__ )) 333 then (( __max__=__num__ )) 334 fi 335 if [[ ! $__preserve__ ]] 336 then __keep__[$__num__]=1 337 fi 338 __text__[$__num__]=$__line__ 339 __index__["$__line__"]=$__num__ 340 (( __num__++ )) 341 fi 342 fi 343 done 344 if (( __max__ < __num__ )) 345 then (( __max__=__num__ )) 346 fi 347 if [[ $__debug__ ]] 348 then for (( __num__=1; __num__<=__max__; __num__++ )) 349 do if [[ ${__text__[$__num__]} ]] 350 then if (( __num__ > __new__ )) 351 then if [[ ! ${__keep__[$__num__]} ]] 352 then print -r -u2 -- $__num__ HUH '"'"${__text__[$__num__]}"'"' 353 else print -r -u2 -- $__num__ NEW '"'"${__text__[$__num__]}"'"' 354 fi 355 elif [[ ${__keep__[$__num__]} ]] 356 then print -r -u2 -- $__num__ OLD '"'"${__text__[$__num__]}"'"' 357 else print -r -u2 -- $__num__ XXX '"'"${__text__[$__num__]}"'"' 358 fi 359 fi 360 done 361 exit 0 362 fi 363 # check for replacements 364 if [[ ! $__preserve__ ]] 365 then for (( __num__=1; __num__<__new__; __num__++ )) 366 do if [[ ${__text__[$__num__]} && ! ${__keep__[$__num__]} ]] 367 then (( __ndrop__++ )) 368 __drop__[__ndrop__]=$__num__ 369 fi 370 done 371 [[ $__verbose__ ]] && print -u2 $__command__: old:1-$((__new__-1)) new:$__new__-$__max__ drop $__ndrop__ add $((__max__-__new__+1)) 372 if (( __ndrop__ )) 373 then for (( __i__=1; __i__<=__ndrop__; __i__++ )) 374 do (( __old__=${__drop__[$__i__]} )) 375 __oz__[__i__]=$(print -r -- "\"${__text__[$__old__]}\"" | gzip | wc -c) 376 done 377 for (( __num__=__new__; __num__<=__max__; __num__++ )) 378 do [[ ${__text__[$__num__]} ]] || continue 379 __nz__=$(print -r -- "\"${__text__[$__num__]}\"" | gzip | wc -c) 380 __hit__=0 381 (( __bz__=__similar__ )) 382 for (( __i__=1; __i__<=__ndrop__; __i__++ )) 383 do if (( __old__=${__drop__[$__i__]} )) 384 then __z__=$(print -r -- "\"${__text__[$__old__]}\"""\"${__text__[$__num__]}\"" | gzip | wc -c) 385 (( __z__ = (__z__ * 200 / (${__oz__[__i__]} + $__nz__)) - 100 )) 386 if (( __z__ < __bz__ )) 387 then (( __bz__=__z__ )) 388 (( __hit__=__old__ )) 389 (( __hit_i__=__i__ )) 390 fi 391 fi 392 done 393 if (( __hit__ )) 394 then [[ $__verbose__ ]] && print -u2 $__command__: $__hit__ $__num__ $__bz__ 395 __text__[$__hit__]=${__text__[$__num__]} 396 __keep__[$__hit__]=1 397 __drop__[$__hit_i__]=0 398 __text__[$__num__]= 399 __keep__[$__num__]= 400 fi 401 done 402 fi 403 fi 404 # final output 405 for (( __num__=1; __num__<=__max__; __num__++ )) 406 do if [[ ${__text__[$__num__]} && ( $__preserve__ || ${__keep__[$__num__]} ) ]] 407 then print -r -- $__num__ "\"${__text__[$__num__]}\"" 408 fi 409 done 410 } 411 if [[ $__tmp__ != $__out__ ]] 412 then grep -v '^\$' $__tmp__ > ${__tmp__}n 413 [[ -f $__out__ ]] && grep -v '^\$' $__out__ > ${__tmp__}o 414 cmp -s ${__tmp__}n ${__tmp__}o || { 415 [[ -f $__out__ ]] && mv $__out__ $__out__.old 416 mv $__tmp__ $__out__ 417 } 418 fi 419fi 420exit $__code__ 421