1######################################################################## 2# # 3# This software is part of the ast package # 4# Copyright (c) 2000-2007 AT&T Knowledge Ventures # 5# and is licensed under the # 6# Common Public License, Version 1.0 # 7# by AT&T Knowledge Ventures # 8# # 9# A copy of the License is available at # 10# http://www.opensource.org/licenses/cpl1.0.txt # 11# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # 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) 2002-09-15 $ 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 thresshold. 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 threshhold is '$__similar__$'. A 60 threshhold 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__cmdv__[__cmds__]=${__out__%.msg} 174(( __cmds__++ )) 175 176# generate the .mso files 177 178if [[ $__OUT__ && $__compile__ ]] 179then __objv__[0]=$__OUT__ 180fi 181 182if (( __sources__ )) 183then for (( __i__=0; __i__<=__files__; __i__++ )) 184 do if [[ ${__srcv__[__i__]} ]] 185 then if (( __sources__ > 1 )) 186 then print "${__srcv__[__i__]}:" 187 fi 188 if [[ $__preprocess__ ]] 189 then msgcpp "${__argv__[@]}" "${__srcv__[__i__]}" 190 else msgcpp "${__argv__[@]}" "${__srcv__[__i__]}" > "${__objv__[__i__]}" 191 fi 192 fi 193 done 194fi 195 196# combine the .mso and .msg files 197 198if [[ ! $__compile__ && ! $__preprocess__ ]] 199then if [[ $__merge__ && -r $__out__ ]] 200 then __tmp__=$__out__.tmp 201 trap '__code__=$?; rm -f ${__tmp__}*; exit $__code__' 0 1 2 202 while read -r __line__ 203 do if (( $__skip__ )) 204 then if [[ $__line__ == '%}'* ]] 205 then __skip__=0 206 fi 207 continue 208 fi 209 if [[ $__mkmsgs__ && $__line__ == '%{'* ]] 210 then __skip__=1 211 continue 212 fi 213 if [[ $__mkmsgs__ ]] 214 then if [[ $__line__ == '%#'*';;'* ]] 215 then __line__=${__line__#'%#'} 216 __num__=${__line__%';;'*} 217 read -r __line__ 218 elif [[ $__line__ == %* ]] 219 then continue 220 else print -u2 $"$__command__: unrecognized line=$__line__" 221 __code__=1 222 fi 223 else case $__line__ in 224 +([0-9])' '*) 225 __num__=${__line__%%' '*} 226 __line__=${__line__#*'"'} 227 __line__=${__line__%'"'} 228 ;; 229 *) continue 230 ;; 231 esac 232 fi 233 __index__["$__line__"]=$__num__ 234 __text__[$__num__]=$__line__ 235 if (( __max__ < __num__ )) 236 then (( __max__=__num__ )) 237 fi 238 done < $__out__ 239 (( __new__=__max__+1 )) 240 else __tmp__=$__out__ 241 (( __new__=1 )) 242 fi 243 if (( __code__ )) 244 then exit $__code__ 245 fi 246 exec 1>$__tmp__ 9>&1 247 print -r -- '$'" ${__out__%.msg} message catalog" 248 print -r -- '$translation'" $__command__ $(date +%Y-%m-%d)" 249 print -r -- '$set'" $__set__" 250 print -r -- '$quote "' 251 sort -u "${__objv__[@]}" | { 252 while read -r __line__ 253 do __op__=${__line__%% *} 254 __line__=${__line__#* } 255 case $__op__ in 256 cmd) __a1__=${__line__%% *} 257 case $__a1__ in 258 dot_cmd) __a1__=. ;; 259 esac 260 keys $__a1__ 261 ;; 262 def) __a1__=${__line__%% *} 263 __a2__=${__line__#* } 264 eval $__a1__='$'__a2__ 265 ;; 266 str) print -r -- "$__line__" 267 ;; 268 var) __a1__=${__line__%% *} 269 __a2__=${__line__#* } 270 case $__a1__ in 271 [[:digit:]]*) 272 eval __v__='$'$__a2__ 273 __v__='"'${__v__:__a1__+1} 274 ;; 275 *) eval __v__='$'$__a1__ 276 ;; 277 esac 278 if [[ $__v__ == '"'*'"' ]] 279 then print -r -- "$__v__" 280 fi 281 ;; 282 [[:digit:]]*) 283 [[ $__preserve__ ]] && print -r -- "$__line__" 284 ;; 285 '$') print -r -u9 $__op__ include $__line__ 286 ;; 287 esac 288 done 289 for (( __i__=0; __i__ < __cmds__; __i__++ )) 290 do keys ${__cmdv__[__i__]} 291 done 292 } | { 293 __num__=1 294 while read -r __line__ 295 do case $__line__ in 296 '$'[\ \ ]*) 297 print -r -- "$__line__" 298 continue 299 ;; 300 '$'*|*"@(#)"*|*"<"*([[:word:] .-])"@"*([[:word:] .-])">"*([ ])'"'|"http://"*) 301 continue 302 ;; 303 *[[:alpha:]][[:alpha:]]*) 304 __line__=${__line__#*'"'} 305 __line__=${__line__%'"'} 306 if [[ $__line__ ]] 307 then if [[ ${__index__["$__line__"]} ]] 308 then if [[ ! $__preserve__ ]] 309 then __num__=${__index__["$__line__"]} 310 __keep__[$__num__]=1 311 fi 312 else while [[ ${__text__[$__num__]} ]] 313 do (( __num__++ )) 314 done 315 if (( __max__ < __num__ )) 316 then (( __max__=__num__ )) 317 fi 318 if [[ ! $__preserve__ ]] 319 then __keep__[$__num__]=1 320 fi 321 __text__[$__num__]=$__line__ 322 __index__["$__line__"]=$__num__ 323 (( __num__++ )) 324 fi 325 fi 326 ;; 327 esac 328 done 329 if (( __max__ < __num__ )) 330 then (( __max__=__num__ )) 331 fi 332 if [[ $__debug__ ]] 333 then for (( __num__=1; __num__<=__max__; __num__++ )) 334 do if [[ ${__text__[$__num__]} ]] 335 then if (( __num__ > __new__ )) 336 then if [[ ! ${__keep__[$__num__]} ]] 337 then print -r -u2 -- $__num__ HUH '"'"${__text__[$__num__]}"'"' 338 else print -r -u2 -- $__num__ NEW '"'"${__text__[$__num__]}"'"' 339 fi 340 elif [[ ${__keep__[$__num__]} ]] 341 then print -r -u2 -- $__num__ OLD '"'"${__text__[$__num__]}"'"' 342 else print -r -u2 -- $__num__ XXX '"'"${__text__[$__num__]}"'"' 343 fi 344 fi 345 done 346 exit 0 347 fi 348 # check for replacements 349 if [[ ! $__preserve__ ]] 350 then for (( __num__=1; __num__<__new__; __num__++ )) 351 do if [[ ${__text__[$__num__]} && ! ${__keep__[$__num__]} ]] 352 then (( __ndrop__++ )) 353 __drop__[__ndrop__]=$__num__ 354 fi 355 done 356 [[ $__verbose__ ]] && print -u2 $__command__: old:1-$((__new__-1)) new:$__new__-$__max__ drop $__ndrop__ add $((__max__-__new__+1)) 357 if (( __ndrop__ )) 358 then for (( __i__=1; __i__<=__ndrop__; __i__++ )) 359 do (( __old__=${__drop__[$__i__]} )) 360 __oz__[__i__]=$(print -r -- "\"${__text__[$__old__]}\"" | gzip | wc -c) 361 done 362 for (( __num__=__new__; __num__<=__max__; __num__++ )) 363 do [[ ${__text__[$__num__]} ]] || continue 364 __nz__=$(print -r -- "\"${__text__[$__num__]}\"" | gzip | wc -c) 365 __hit__=0 366 (( __bz__=__similar__ )) 367 for (( __i__=1; __i__<=__ndrop__; __i__++ )) 368 do if (( __old__=${__drop__[$__i__]} )) 369 then __z__=$(print -r -- "\"${__text__[$__old__]}\"""\"${__text__[$__num__]}\"" | gzip | wc -c) 370 (( __z__ = (__z__ * 200 / (${__oz__[__i__]} + $__nz__)) - 100 )) 371 if (( __z__ < __bz__ )) 372 then (( __bz__=__z__ )) 373 (( __hit__=__old__ )) 374 (( __hit_i__=__i__ )) 375 fi 376 fi 377 done 378 if (( __hit__ )) 379 then [[ $__verbose__ ]] && print -u2 $__command__: $__hit__ $__num__ $__bz__ 380 __text__[$__hit__]=${__text__[$__num__]} 381 __keep__[$__hit__]=1 382 __drop__[$__hit_i__]=0 383 __text__[$__num__]= 384 __keep__[$__num__]= 385 fi 386 done 387 fi 388 fi 389 # final output 390 for (( __num__=1; __num__<=__max__; __num__++ )) 391 do if [[ ${__text__[$__num__]} && ( $__preserve__ || ${__keep__[$__num__]} ) ]] 392 then print -r -- $__num__ "\"${__text__[$__num__]}\"" 393 fi 394 done 395 } 396 if [[ $__tmp__ != $__out__ ]] 397 then grep -v '^\$' $__tmp__ > ${__tmp__}n 398 [[ -f $__out__ ]] && grep -v '^\$' $__out__ > ${__tmp__}o 399 cmp -s ${__tmp__}n ${__tmp__}o || { 400 [[ -f $__out__ ]] && mv $__out__ $__out__.old 401 mv $__tmp__ $__out__ 402 } 403 fi 404fi 405exit $__code__ 406