######################################################################## # # # This software is part of the ast package # # Copyright (c) 2000-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # # (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # # # # Information and Software Systems Research # # AT&T Research # # Florham Park NJ # # # # Glenn Fowler # # # ######################################################################## : C language message catalog compiler # NOTE: all variable names match __*__ to avoid clash with msgcpp def vars setvar __command__ = 'msgcc' integer __similar__=30 match $(shell {getopts '[-][123:xyz]' opt --xyz; echo 0$opt}) { with 0123 setvar ARGV0 = ""-a $__command__"" setvar USAGE = "$' [-? @(#)$Id: msgcc (AT&T Labs Research) 2002-09-15 $ ] '$USAGE_LICENSE$' [+NAME?msgcc - C language message catalog compiler] [+DESCRIPTION?\bmsgcc\b is a C language message catalog compiler. It accepts \bcc\b(1) style options and arguments. A \bmsgcpp\b(1) \b.mso\b file is generated for each input \b.c\b file. If the \b-c\b option is not specified then a \bgencat\b(1) format \b.msg\b file is generated from the input \b.mso\b and \b.msg\b files. If \b-c\b is not specified then a \b.msg\b suffix is appended to the \b-o\b \afile\a if it doesn\'t already have a suffix. The default output is \ba.out.msg\b if \b-c\b and \b-o\b are not specified.] [+?If \b-M-new\b is not specified then messages are merged with those in the pre-existing \b-o\b file.] [M?Set a \bmsgcc\b specific \aoption\a. \aoption\a may be:]:[-option]{ [+mkmsgs?The \b-o\b file is assumed to be in \bmkmsgs\b(1) format.] [+new?Create a new \b-o\b file.] [+preserve?Messages in the \b-o\b file that are not in new \b.msg\b file arguments are preserved. The default is to either reuse the message numbers with new message text that is similar to the old or to delete the message text, leaving an unused message number.] [+set=\anumber\a?Set the message set number to \anumber\a. The default is \b1\b.] [+similar=\anumber\a?The message text similarity measure thresshold. The similarity measure between \aold\a and \anew\a message text is 100*(2*gzip(\aold\a+\anew\a)/(gzip(\aold\a)+gzip(\anew\a))-1), where gzip(\ax\a) is the size of text \ax\a when compressed by \bgzip\b(1). The default threshhold is '$__similar__$'. A threshhold of \b0\b turns off message replacement, but unused old messages are still deleted. Use \b-M-preserve\b to preserve all old messages.] [+verbose?Trace similar message replacements on the standard error.] } file ... [+SEE ALSO?\bcc\b(1), \bcpp\b(1), \bgencat\b(1), \bmsggen\b(1), \bmsgcpp\b(1), \bmsgcvt\b(1)] "' with * setvar ARGV0 = """" setvar USAGE = ""M:[-option] [ cc-options ] file ..."" } proc usage { setvar OPTIND = '0' getopts $ARGV0 $USAGE OPT '-?' exit 2 } proc keys { $1 --??keys -- 2>&1 | grep '^".*"$' } typeset -A __index__ typeset __keep__ __text__ __drop__ __oz__ __nz__ __z__ __hit__ __hit_i__ typeset __compile__ __debug__ __mkmsgs__ __preprocess__ typeset __merge__=1 __preserve__ __verbose__ integer __i__=0 __args__=0 __code__=0 __files__=0 __max__=0 __num__=0 __skip__=0 integer __set__=1 __sources__=0 __cmds__=0 __ndrop__=0 __new__=0 __old__=0 setvar __out__ = 'a.out.msg' setvar __OUT__ = '' match " $ifsjoin(ARGV) " { with *" --"*|*" -?"* while getopts $ARGV0 "$USAGE" OPT { match $OPT { with * break } } } while : { match $Argc { with 0 break } setvar __arg__ = "$1" match $__arg__ { with -c setvar __compile__ = '1' with -[DIU]*setvar __argv__[__args__]=$__arg__ (( __args__++ )) with -E setvar __preprocess__ = '1' with -M-debug setvar __debug__ = '1' with -M-mkmsgs setvar __mkmsgs__ = '1' with -M-new setvar __merge__ = '' with -M-perserve setvar __preserve__ = '1' with -M-set=* setvar __set__ = $(msggen -s ${__arg__#*=}.1) with -M-similar=* setvar __similar__ = ${__arg__#*=} with -M-verbose setvar __verbose__ = '1' with -o match $Argc { with 1 print -u2 $"$__command__: output argument expected" exit 1 } shift setvar __out__ = "${1%.*}.msg" setvar __OUT__ = "$1" with [-+]*|*.[aAlLsS]* with *.[cCiI]*|*.[oO]* match $__arg__ { with *.[oO]* with * setvar __srcv__[__files__]=$__arg__ (( __sources__++ )) } setvar __arg__ = ${__arg__##*/} setvar __arg__ = "${__arg__%.*}.mso" setvar __objv__[__files__]=$__arg__ (( __files__++ )) with *.ms[go] setvar __objv__[__files__]=$__arg__ (( __files__++ )) with * setvar __cmdv__[__cmds__]=$__arg__ (( __cmds__++ )) } shift } setvar __cmdv__[__cmds__]=${__out__%.msg} (( __cmds__++ )) # generate the .mso files if [[ $__OUT__ && $__compile__ ]] { setvar __objv__[0]=$__OUT__ } if (( __sources__ )) { for (( __i__=0; __i__<=__files__; __i__++ )) do if [[ ${__srcv__[__i__]} ]] then if (( __sources__ > 1 )) then print "${__srcv__[__i__]}:" fi if [[ $__preprocess__ ]] then msgcpp "${__argv__[@]}" "${__srcv__[__i__]}" else msgcpp "${__argv__[@]}" "${__srcv__[__i__]}" > "${__objv__[__i__]}" fi fi done } # combine the .mso and .msg files if [[ ! $__compile__ && ! $__preprocess__ ]] { if [[ $__merge__ && -r $__out__ ]] { setvar __tmp__ = "$__out__.tmp" trap '__code__=$?; rm -f ${__tmp__}*; exit $__code__' 0 1 2 while read -r __line__ { if (( $__skip__ )) { if [[ $__line__ == '%}'* ]] { setvar __skip__ = '0' } continue } if [[ $__mkmsgs__ && $__line__ == '%{'* ]] { setvar __skip__ = '1' continue } if [[ $__mkmsgs__ ]] { if [[ $__line__ == '%#'*';;'* ]] { setvar __line__ = ${__line__#'%#'} setvar __num__ = ${__line__%';;'*} read -r __line__ } elif [[ $__line__ == %* ]] { continue } else { print -u2 $"$__command__: unrecognized line=$__line__" setvar __code__ = '1' } } else { match $__line__ { with +([0-9])' '* setvar __num__ = ${__line__%%' '*} setvar __line__ = ${__line__#*'"'} setvar __line__ = ${__line__%'"'} with * continue } } setvar __index__["$__line__"]=$__num__ setvar __text__[$__num__]=$__line__ if (( __max__ < __num__ )) { (( __max__=__num__ )) } } < $__out__ (( __new__=__max__+1 )) } else { setvar __tmp__ = "$__out__" (( __new__=1 )) } if (( __code__ )) { exit $__code__ } exec 1>$__tmp__ 9>&1 print -r -- '$'" ${__out__%.msg} message catalog" print -r -- '$translation'" $__command__ $(date +%Y-%m-%d)" print -r -- '$set'" $__set__" print -r -- '$quote "' sort -u ${__objv__[@]} | do { while read -r __line__ { setvar __op__ = ${__line__%% *} setvar __line__ = ${__line__#* } match $__op__ { with cmd setvar __a1__ = ${__line__%% *} match $__a1__ { with dot_cmd setvar __a1__ = '.' } keys $__a1__ with def setvar __a1__ = ${__line__%% *} setvar __a2__ = ${__line__#* } eval $__a1__='$'__a2__ with str print -r -- $__line__ with var setvar __a1__ = ${__line__%% *} setvar __a2__ = ${__line__#* } match $__a1__ { with [[:digit:]]* eval __v__='$'$__a2__ setvar __v__ = "'"'${__v__:__a1__+1}" with * eval __v__='$'$__a1__ } if [[ $__v__ == '"'*'"' ]] { print -r -- $__v__ } with [[:digit:]]* [[ $__preserve__ ]] && print -r -- $__line__ with '$' print -r -u9 $__op__ include $__line__ } } for (( __i__=0; __i__ < __cmds__; __i__++ )) do keys ${__cmdv__[__i__]} done } | do { setvar __num__ = '1' while read -r __line__ { match $__line__ { with '$'[\ \ ]* print -r -- $__line__ continue with '$'*|*"@(#)"*|*"<"*([[:word:] .-])"@"*([[:word:] .-])">"*([ ])'"'|"http://"* continue with *[[:alpha:]][[:alpha:]]* setvar __line__ = ${__line__#*'"'} setvar __line__ = ${__line__%'"'} if [[ $__line__ ]] { if [[ ${__index__["$__line__"]} ]] { if [[ ! $__preserve__ ]] { setvar __num__ = ${__index__["$__line__"]} setvar __keep__[$__num__]=1 } } else { while [[ ${__text__[$__num__]} ]] { (( __num__++ )) } if (( __max__ < __num__ )) { (( __max__=__num__ )) } if [[ ! $__preserve__ ]] { setvar __keep__[$__num__]=1 } setvar __text__[$__num__]=$__line__ setvar __index__["$__line__"]=$__num__ (( __num__++ )) } } } } if (( __max__ < __num__ )) { (( __max__=__num__ )) } if [[ $__debug__ ]] { for (( __num__=1; __num__<=__max__; __num__++ )) do if [[ ${__text__[$__num__]} ]] then if (( __num__ > __new__ )) then if [[ ! ${__keep__[$__num__]} ]] then print -r -u2 -- $__num__ HUH '"'"${__text__[$__num__]}"'"' else print -r -u2 -- $__num__ NEW '"'"${__text__[$__num__]}"'"' fi elif [[ ${__keep__[$__num__]} ]] then print -r -u2 -- $__num__ OLD '"'"${__text__[$__num__]}"'"' else print -r -u2 -- $__num__ XXX '"'"${__text__[$__num__]}"'"' fi fi done exit 0 } # check for replacements if [[ ! $__preserve__ ]] { for (( __num__=1; __num__<__new__; __num__++ )) do if [[ ${__text__[$__num__]} && ! ${__keep__[$__num__]} ]] then (( __ndrop__++ )) __drop__[__ndrop__]=$__num__ fi done [[ $__verbose__ ]] && print -u2 $__command__: old:1-$((__new__-1)) new:$__new__-$__max__ drop $__ndrop__ add $((__max__-__new__+1)) if (( __ndrop__ )) { for (( __i__=1; __i__<=__ndrop__; __i__++ )) do (( __old__=${__drop__[$__i__]} )) __oz__[__i__]=$(print -r -- "\"${__text__[$__old__]}\"" | gzip | wc -c) done for (( __num__=__new__; __num__<=__max__; __num__++ )) do [[ ${__text__[$__num__]} ]] || continue __nz__=$(print -r -- "\"${__text__[$__num__]}\"" | gzip | wc -c) __hit__=0 (( __bz__=__similar__ )) for (( __i__=1; __i__<=__ndrop__; __i__++ )) do if (( __old__=${__drop__[$__i__]} )) then __z__=$(print -r -- "\"${__text__[$__old__]}\"""\"${__text__[$__num__]}\"" | gzip | wc -c) (( __z__ = (__z__ * 200 / (${__oz__[__i__]} + $__nz__)) - 100 )) if (( __z__ < __bz__ )) then (( __bz__=__z__ )) (( __hit__=__old__ )) (( __hit_i__=__i__ )) fi fi done if (( __hit__ )) then [[ $__verbose__ ]] && print -u2 $__command__: $__hit__ $__num__ $__bz__ __text__[$__hit__]=${__text__[$__num__]} __keep__[$__hit__]=1 __drop__[$__hit_i__]=0 __text__[$__num__]= __keep__[$__num__]= fi done } } # final output for (( __num__=1; __num__<=__max__; __num__++ )) do if [[ ${__text__[$__num__]} && ( $__preserve__ || ${__keep__[$__num__]} ) ]] then print -r -- $__num__ "\"${__text__[$__num__]}\"" fi done } if [[ $__tmp__ != $__out__ ]] { grep -v '^\$' $__tmp__ > ${__tmp__}n [[ -f $__out__ ]] && grep -v '^\$' $__out__ > ${__tmp__}o cmp -s ${__tmp__}n ${__tmp__}o || do { [[ -f $__out__ ]] && mv $__out__ $__out__.old mv $__tmp__ $__out__ } } } exit $__code__