1#! /bin/sh 2# Wrapper around gettext for programs using the msgid convention. 3# Copyright (C) 1998-2015 Free Software Foundation, Inc. 4 5# Written by Paul Eggert <eggert@twinsun.com>. 6# Revised by Zack Weinberg <zackw@stanford.edu> for no-POTFILES operation. 7 8# This file is part of GCC. 9 10# GCC is free software; you can redistribute it and/or modify 11# it under the terms of the GNU General Public License as published by 12# the Free Software Foundation; either version 3, or (at your option) 13# any later version. 14 15# GCC is distributed in the hope that it will be useful, 16# but WITHOUT ANY WARRANTY; without even the implied warranty of 17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18# GNU General Public License for more details. 19 20# You should have received a copy of the GNU General Public License 21# along with GCC; see the file COPYING3. If not see 22# <http://www.gnu.org/licenses/>. 23 24# Always operate in the C locale. 25LANG=C 26LANGUAGE=C 27LC_ALL=C 28export LANG LANGUAGE LC_ALL 29 30# Set AWK if environment has not already set it. 31AWK=${AWK-awk} 32 33# The arguments to this wrapper are: the program to execute, the 34# name of the "package", and the path to the source directory. 35 36if [ $# -ne 3 ] 37then echo "usage: $0 <xgettext> <package> <srcdir>" 38 exit 1 39fi 40 41xgettext=$1 42package=$2 43srcdir=$3 44 45case `$xgettext --version | sed -e 1q | sed -e 's/^\([^0-9]*\)//'` in 46 0.14.[5-9]* | 0.14.[1-9][0-9]* | 0.1[5-9]* | 0.[2-9][0-9]* | [1-9].*) : ;; 47 *) echo "$xgettext is too old. GNU xgettext 0.14.5 is required" 48 exit 1 ;; 49esac 50 51nl=' 52' 53 54set -e 55 56# Create temporary directory for scratch files. 57T=exg$$.d 58mkdir $T 59trap "rm -r $T" 0 60 61pwd=`${PWDCMD-pwd}` 62kopt=$pwd/$T/keyword-options 63kopt2=$pwd/$T/keyword2-options 64emsg=$pwd/$T/emsgids.c 65posr=$pwd/$T/po-sources 66posrcxx=$pwd/$T/po-cxx-sources 67pottmp1=$pwd/$T/tmp1.pot 68pottmp2=$pwd/$T/tmp2.pot 69pottmp3=$pwd/$T/tmp3.pot 70pottmp=$pwd/$T/tmp.pot 71 72# Locate files to scan. We scan the following directories: 73# $srcdir 74# $srcdir/c-family 75# $srcdir/common 76# $srcdir/common/config 77# $srcdir/common/config/* 78# $srcdir/config 79# $srcdir/config/* 80# all subdirectories of $srcdir containing a config-lang.in file, and 81# all subdirectories of those directories. 82# Within those directories, we examine all .c, .cc, .h, and .def files. 83# However, any files listed in $srcdir/po/EXCLUDE are not examined. 84# 85# Then generate keyword options for xgettext, by scanning for declarations 86# of functions whose parameter names end in "msgid". 87# 88# Finally, generate a source file containing all %e and %n strings from 89# driver specs, so those can be translated too. 90# 91# All in one huge awk script. 92 93echo "scanning for keywords, %e and %n strings..." >&2 94 95( cd $srcdir 96 lang_subdirs=`echo */config-lang.in */*/config-lang.in | sed -e 's|/config-lang\.in||g'` 97 { for dir in "" c-family/ common/ common/config/ common/config/*/ \ 98 config/ config/*/ \ 99 `find $lang_subdirs -type d -print | fgrep -v .svn | sort | sed -e 's|$|/|'` 100 do for glob in '*.c' '*.cc' '*.h' '*.def' 101 do eval echo $dir$glob 102 done 103 done; 104 } | tr ' ' "$nl" | grep -v '\*' | 105 $AWK -v excl=po/EXCLUDES -v posr=$posr -v posrcxx=$posrcxx -v kopt=$kopt -v kopt2=$kopt2 -v emsg=$emsg ' 106function keyword_option(line) { 107 paren_index = index(line, "(") 108 name = substr(line, 1, paren_index - 1) 109 sub(/[^0-9A-Z_a-z]*$/, "", name) 110 sub(/[ ]+PARAMS/, "", name) 111 sub(/[ ]+VPARAMS/, "", name) 112 sub(/.*[^0-9A-Z_a-z]/, "", name) 113 114 args = substr(line, paren_index) 115 sub(/msgid[,\)].*/, "", args) 116 for (n = 1; sub(/^[^,]*,/, "", args); n++) { 117 continue 118 } 119 format="" 120 if (args ~ /g$/) 121 format="gcc-internal-format" 122 else if (args ~ /noc$/) 123 format="no-c-format" 124 else if (args ~ /c$/) 125 format="c-format" 126 127 if (n == 1) { keyword = "--keyword=" name } 128 else { 129 keyword = "--keyword=" name ":" n 130 if (name ~ /_n$/) 131 keyword = keyword "," (n + 1) 132 } 133 if (format) { 134 keyword=keyword "\n--flag=" name ":" n ":" format 135 if (name ~ /_n$/) 136 keyword = keyword "\n--flag=" name ":" (n + 1) ":" format 137 } 138 139 if (! keyword_seen[name]) { 140 if (format == "gcc-internal-format") 141 print keyword > kopt2 142 else 143 print keyword > kopt 144 keyword_seen[name] = keyword 145 } else if (keyword_seen[name] != keyword) { 146 printf("%s used incompatibly as both %s and %s\n", 147 name, keyword_seen[name], keyword) 148 exit (1) 149 } 150} 151 152function spec_error_string (line) { 153 if (index(line, "%e") != 0 && index(line, "%n") != 0) return 154 while ((percent_index = index(line, "%e")) != 0 || 155 (percent_index = index(line, "%n")) != 0) { 156 line = substr(line, percent_index + 2) 157 158 bracket_index = index(line, "}") 159 newline_index = index(line, "\\n") 160 161 quote_index = index(line, "\"") 162 if (bracket_index == 0 && newline_index == 0) return 163 164 if (bracket_index != 0) { 165 if (quote_index != 0 && bracket_index > quote_index) return 166 msgid = substr(line, 1, bracket_index - 1) 167 line = substr(line, bracket_index + 1) 168 } 169 else if (newline_index != 0) { 170 if (quote_index != 0 && quote_index > newline_index) return 171 msgid = substr(line, 1, newline_index - 1) 172 line = substr(line, newline_index + 1) 173 } 174 175 if (index(msgid, "%") != 0) continue 176 177 if ((newline_index = index(msgid, "\\n")) != 0) 178 msgid = substr(msgid, 1, newline_index - 1) 179 printf("#line %d \"%s\"\n", lineno, file) > emsg 180 printf("_(\"%s\")\n", msgid) > emsg 181 } 182} 183 184BEGIN { 185 while ((getline < excl) > 0) { 186 if ($0 ~ /^#/ || $0 ~ /^[ ]*$/) 187 continue 188 excludes[$1] = 1 189 } 190} 191 192{ if (!($0 in excludes)) { 193 if ($0 ~ /.cc$/) { 194 print > posrcxx 195 } else { 196 print > posr 197 } 198 files[NR] = $0 199 } 200} 201 202END { 203 for (f in files) { 204 file = files[f] 205 lineno = 1 206 while (getline < file) { 207 if (/^(#[ ]*define[ ]*)?[A-Za-z_].*\(.*msgid[,\)]/) { 208 keyword_option($0) 209 } else if (/^(#[ ]*define[ ]*)?[A-Za-z_].*(\(|\(.*,)$/) { 210 name_line = $0 211 while (getline < file) { 212 lineno++ 213 if (/msgid[,\)]/){ 214 keyword_option(name_line $0) 215 break 216 } else if (/,$/) { 217 name_line = name_line $0 218 continue 219 } else break 220 } 221 } else if (/%e/ || /%n/) { 222 spec_error_string($0) 223 } 224 lineno++ 225 } 226 } 227 print emsg > posr 228}' 229) || exit 230 231echo "scanning option files..." >&2 232 233( cd $srcdir; find . -name '*.opt' -print | 234 $AWK '{ 235 file = $1 236 lineno = 1 237 field = 0 238 while (getline < file) { 239 if (/^[ \t]*(;|$)/ || !/^[^ \t]/) { 240 field = 0 241 } else { 242 if ((field == 1) && /MissingArgError/) { 243 line = $0 244 sub(".*MissingArgError\\(", "", line) 245 if (line ~ "^{") { 246 sub("^{", "", line) 247 sub("}\\).*", "", line) 248 } else 249 sub("\\).*", "", line) 250 printf("#line %d \"%s\"\n", lineno, file) 251 printf("_(\"%s\")\n", line) 252 } 253 if ((field == 1) && /UnknownError/) { 254 line = $0 255 sub(".*UnknownError\\(", "", line) 256 if (line ~ "^{") { 257 sub("^{", "", line) 258 sub("}\\).*", "", line) 259 } else 260 sub("\\).*", "", line) 261 printf("#line %d \"%s\"\n", lineno, file) 262 printf("_(\"%s\")\n", line) 263 } 264 if ((field == 1) && /Warn\(/) { 265 line = $0 266 sub(".*Warn\\(", "", line) 267 if (line ~ "^{") { 268 sub("^{", "", line) 269 sub("}\\).*", "", line) 270 } else 271 sub("\\).*", "", line) 272 printf("#line %d \"%s\"\n", lineno, file) 273 printf("_(\"%s\")\n", line) 274 } 275 if (field == 2) { 276 line = $0 277 printf("#line %d \"%s\"\n", lineno, file) 278 printf("_(\"%s\")\n", line) 279 } 280 field++; 281 } 282 lineno++; 283 } 284 }') >> $emsg 285 286# Run the xgettext commands, with temporary added as a file to scan. 287echo "running xgettext..." >&2 288$xgettext --default-domain=$package --directory=$srcdir \ 289 --add-comments `cat $kopt` --files-from=$posr \ 290 --copyright-holder="Free Software Foundation, Inc." \ 291 --msgid-bugs-address="http://gcc.gnu.org/bugs.html" \ 292 --language=c -o $pottmp1 293if test -s $posrcxx; then 294 $xgettext --default-domain=$package --directory=$srcdir \ 295 --add-comments `cat $kopt` --files-from=$posrcxx \ 296 --copyright-holder="Free Software Foundation, Inc." \ 297 --msgid-bugs-address="http://gcc.gnu.org/bugs.html" \ 298 --language=c++ -o $pottmp2 299else 300 echo > $pottmp2 301fi 302$xgettext --default-domain=$package --directory=$srcdir \ 303 --add-comments --keyword= `cat $kopt2` --files-from=$posr \ 304 --copyright-holder="Free Software Foundation, Inc." \ 305 --msgid-bugs-address="http://gcc.gnu.org/bugs.html" \ 306 --language=GCC-source -o $pottmp3 307$xgettext --default-domain=$package \ 308 --add-comments $pottmp1 $pottmp2 $pottmp3 \ 309 --copyright-holder="Free Software Foundation, Inc." \ 310 --msgid-bugs-address="http://gcc.gnu.org/bugs.html" \ 311 --language=PO -o $pottmp 312# Remove local paths from .pot file. 313sed "s:$srcdir/::g;s:$pwd/::g;" <$pottmp >po/$package.pot 314