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