summaryrefslogtreecommitdiff
path: root/development/translation
Unidiff
Diffstat (limited to 'development/translation') (more/less context) (ignore whitespace changes)
-rw-r--r--development/translation/opie-lupdate/fetchtr.cpp55
-rw-r--r--development/translation/opie-lupdate/main.cpp11
-rw-r--r--development/translation/opie-lupdate/merge.cpp6
-rw-r--r--development/translation/opie-lupdate/numberh.cpp28
-rw-r--r--development/translation/opie-lupdate/sametexth.cpp6
-rw-r--r--development/translation/shared/metatranslator.cpp34
-rw-r--r--development/translation/shared/metatranslator.h16
-rw-r--r--development/translation/shared/opie.h2
-rw-r--r--development/translation/shared/proparser.cpp111
-rw-r--r--development/translation/shared/proparser.h8
10 files changed, 228 insertions, 49 deletions
diff --git a/development/translation/opie-lupdate/fetchtr.cpp b/development/translation/opie-lupdate/fetchtr.cpp
index d1f5881..a137628 100644
--- a/development/translation/opie-lupdate/fetchtr.cpp
+++ b/development/translation/opie-lupdate/fetchtr.cpp
@@ -1,787 +1,822 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qt Linguist. 4** This file is part of Qt Linguist.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12** licenses may use this file in accordance with the Qt Commercial License
13** Agreement provided with the Software.
14**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 17**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 18** See http://www.trolltech.com/gpl/ for GPL licensing information.
19** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20** information about Qt Commercial License Agreements.
15** 21**
16** Contact info@trolltech.com if any conditions of this licensing are 22** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 23** not clear to you.
18** 24**
19**********************************************************************/ 25**********************************************************************/
20 26
21#include <metatranslator.h> 27#include <metatranslator.h>
22 28
23#include <qfile.h> 29#include <qfile.h>
24#include <qregexp.h> 30#include <qregexp.h>
25#include <qstring.h> 31#include <qstring.h>
26#include <qtextstream.h> 32#include <qtextstream.h>
27#include <qvaluestack.h> 33#include <qvaluestack.h>
28#include <qxml.h> 34#include <qxml.h>
29 35
30#include <ctype.h> 36#include <ctype.h>
31#include <errno.h> 37#include <errno.h>
32#include <stdio.h> 38#include <stdio.h>
33#include <string.h> 39#include <string.h>
34 40
35/* qmake ignore Q_OBJECT */ 41/* qmake ignore Q_OBJECT */
36 42
37static const char MagicComment[] = "TRANSLATOR "; 43static const char MagicComment[] = "TRANSLATOR ";
38 44
39static QMap<QCString, int> needs_Q_OBJECT; 45static QMap<QCString, int> needs_Q_OBJECT;
40static QMap<QCString, int> lacks_Q_OBJECT; 46static QMap<QCString, int> lacks_Q_OBJECT;
41 47
42/* 48/*
43 The first part of this source file is the C++ tokenizer. We skip 49 The first part of this source file is the C++ tokenizer. We skip
44 most of C++; the only tokens that interest us are defined here. 50 most of C++; the only tokens that interest us are defined here.
45 Thus, the code fragment 51 Thus, the code fragment
46 52
47 int main() 53 int main()
48 { 54 {
49 printf( "Hello, world!\n" ); 55 printf( "Hello, world!\n" );
50 return 0; 56 return 0;
51 } 57 }
52 58
53 is broken down into the following tokens (Tok_ omitted): 59 is broken down into the following tokens (Tok_ omitted):
54 60
55 Ident Ident LeftParen RightParen 61 Ident Ident LeftParen RightParen
56 LeftBrace 62 LeftBrace
57 Ident LeftParen String RightParen Semicolon 63 Ident LeftParen String RightParen Semicolon
58 return Semicolon 64 return Semicolon
59 RightBrace. 65 RightBrace.
60 66
61 The 0 doesn't produce any token. 67 The 0 doesn't produce any token.
62*/ 68*/
63 69
64enum { Tok_Eof, Tok_class, Tok_namespace, Tok_return, Tok_tr, 70enum { Tok_Eof, Tok_class, Tok_namespace, Tok_return, Tok_tr,
65 Tok_trUtf8, Tok_translate, Tok_Q_OBJECT, Tok_Ident, 71 Tok_trUtf8, Tok_translate, Tok_Q_OBJECT, Tok_Ident,
66 Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, 72 Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon,
67 Tok_Gulbrandsen, Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, 73 Tok_Gulbrandsen, Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen,
68 Tok_RightParen, Tok_Comma, Tok_Semicolon }; 74 Tok_RightParen, Tok_Comma, Tok_Semicolon };
69 75
70/* 76/*
71 The tokenizer maintains the following global variables. The names 77 The tokenizer maintains the following global variables. The names
72 should be self-explanatory. 78 should be self-explanatory.
73*/ 79*/
74static QCString yyFileName; 80static QCString yyFileName;
75static int yyCh; 81static int yyCh;
76static char yyIdent[128]; 82static char yyIdent[128];
77static size_t yyIdentLen; 83static size_t yyIdentLen;
78static char yyComment[65536]; 84static char yyComment[65536];
79static size_t yyCommentLen; 85static size_t yyCommentLen;
80static char yyString[16384]; 86static char yyString[16384];
81static size_t yyStringLen; 87static size_t yyStringLen;
82static QValueStack<int> yySavedBraceDepth; 88static QValueStack<int> yySavedBraceDepth;
89static QValueStack<int> yySavedParenDepth;
83static int yyBraceDepth; 90static int yyBraceDepth;
84static int yyParenDepth; 91static int yyParenDepth;
85static int yyLineNo; 92static int yyLineNo;
86static int yyCurLineNo; 93static int yyCurLineNo;
94static int yyBraceLineNo;
95static int yyParenLineNo;
87 96
88// the file to read from (if reading from a file) 97// the file to read from (if reading from a file)
89static FILE *yyInFile; 98static FILE *yyInFile;
90 99
91// the string to read from and current position in the string (otherwise) 100// the string to read from and current position in the string (otherwise)
92static QString yyInStr; 101static QString yyInStr;
93static int yyInPos; 102static int yyInPos;
94 103
95static int (*getChar)(); 104static int (*getChar)();
96 105
97static int getCharFromFile() 106static int getCharFromFile()
98{ 107{
99 int c = getc( yyInFile ); 108 int c = getc( yyInFile );
100 if ( c == '\n' ) 109 if ( c == '\n' )
101 yyCurLineNo++; 110 yyCurLineNo++;
102 return c; 111 return c;
103} 112}
104 113
105static int getCharFromString() 114static int getCharFromString()
106{ 115{
107 if ( yyInPos == (int) yyInStr.length() ) { 116 if ( yyInPos == (int) yyInStr.length() ) {
108 return EOF; 117 return EOF;
109 } else { 118 } else {
110 return yyInStr[yyInPos++].latin1(); 119 return yyInStr[yyInPos++].latin1();
111 } 120 }
112} 121}
113 122
114static void startTokenizer( const char *fileName, int (*getCharFunc)() ) 123static void startTokenizer( const char *fileName, int (*getCharFunc)() )
115{ 124{
116 yyInPos = 0; 125 yyInPos = 0;
117 getChar = getCharFunc; 126 getChar = getCharFunc;
118 127
119 yyFileName = fileName; 128 yyFileName = fileName;
120 yyCh = getChar(); 129 yyCh = getChar();
121 yySavedBraceDepth.clear(); 130 yySavedBraceDepth.clear();
131 yySavedParenDepth.clear();
122 yyBraceDepth = 0; 132 yyBraceDepth = 0;
123 yyParenDepth = 0; 133 yyParenDepth = 0;
124 yyCurLineNo = 1; 134 yyCurLineNo = 1;
135 yyBraceLineNo = 1;
136 yyParenLineNo = 1;
125} 137}
126 138
127static int getToken() 139static int getToken()
128{ 140{
129 const char tab[] = "abfnrtv"; 141 const char tab[] = "abfnrtv";
130 const char backTab[] = "\a\b\f\n\r\t\v"; 142 const char backTab[] = "\a\b\f\n\r\t\v";
131 uint n; 143 uint n;
132 144
133 yyIdentLen = 0; 145 yyIdentLen = 0;
134 yyCommentLen = 0; 146 yyCommentLen = 0;
135 yyStringLen = 0; 147 yyStringLen = 0;
136 148
137 while ( yyCh != EOF ) { 149 while ( yyCh != EOF ) {
138 yyLineNo = yyCurLineNo; 150 yyLineNo = yyCurLineNo;
139 151
140 if ( isalpha(yyCh) || yyCh == '_' ) { 152 if ( isalpha(yyCh) || yyCh == '_' ) {
141 do { 153 do {
142 if ( yyIdentLen < sizeof(yyIdent) - 1 ) 154 if ( yyIdentLen < sizeof(yyIdent) - 1 )
143 yyIdent[yyIdentLen++] = (char) yyCh; 155 yyIdent[yyIdentLen++] = (char) yyCh;
144 yyCh = getChar(); 156 yyCh = getChar();
145 } while ( isalnum(yyCh) || yyCh == '_' ); 157 } while ( isalnum(yyCh) || yyCh == '_' );
146 yyIdent[yyIdentLen] = '\0'; 158 yyIdent[yyIdentLen] = '\0';
147 159
148 switch ( yyIdent[0] ) { 160 switch ( yyIdent[0] ) {
149 case 'Q': 161 case 'Q':
150 if ( strcmp(yyIdent + 1, "_OBJECT") == 0 ) { 162 if ( strcmp(yyIdent + 1, "_OBJECT") == 0 ) {
151 return Tok_Q_OBJECT; 163 return Tok_Q_OBJECT;
152 } else if ( strcmp(yyIdent + 1, "T_TR_NOOP") == 0 ) { 164 } else if ( strcmp(yyIdent + 1, "T_TR_NOOP") == 0 ) {
153 return Tok_tr; 165 return Tok_tr;
154 } else if ( strcmp(yyIdent + 1, "T_TRANSLATE_NOOP") == 0 ) { 166 } else if ( strcmp(yyIdent + 1, "T_TRANSLATE_NOOP") == 0 ) {
155 return Tok_translate; 167 return Tok_translate;
156 } 168 }
157 break; 169 break;
158 case 'T': 170 case 'T':
159 // TR() for when all else fails 171 // TR() for when all else fails
160 if ( qstricmp(yyIdent + 1, "R") == 0 ) 172 if ( qstricmp(yyIdent + 1, "R") == 0 )
161 return Tok_tr; 173 return Tok_tr;
162 break; 174 break;
163 case 'c': 175 case 'c':
164 if ( strcmp(yyIdent + 1, "lass") == 0 ) 176 if ( strcmp(yyIdent + 1, "lass") == 0 )
165 return Tok_class; 177 return Tok_class;
166 break; 178 break;
179 case 'f':
180 /*
181 QTranslator::findMessage() has the same parameters as
182 QApplication::translate().
183 */
184 if ( strcmp(yyIdent + 1, "indMessage") == 0 )
185 return Tok_translate;
186 break;
187 case 'i':
188 /* FOR KDE APPS */
189 if ( strcmp( yyIdent + 1, "8n") == 0 )
190 return Tok_translate;
191 break;
167 case 'n': 192 case 'n':
168 if ( strcmp(yyIdent + 1, "amespace") == 0 ) 193 if ( strcmp(yyIdent + 1, "amespace") == 0 )
169 return Tok_namespace; 194 return Tok_namespace;
170 break; 195 break;
171 case 'r': 196 case 'r':
172 if ( strcmp(yyIdent + 1, "eturn") == 0 ) 197 if ( strcmp(yyIdent + 1, "eturn") == 0 )
173 return Tok_return; 198 return Tok_return;
174 break; 199 break;
175 case 's': 200 case 's':
176 if ( strcmp(yyIdent + 1, "truct") == 0 ) 201 if ( strcmp(yyIdent + 1, "truct") == 0 )
177 return Tok_class; 202 return Tok_class;
178 break; 203 break;
179 case 'i':
180 if( strcmp(yyIdent + 1, "18n") == 0 )
181 return Tok_tr;
182 case 't': 204 case 't':
183 if ( strcmp(yyIdent + 1, "r") == 0 ) { 205 if ( strcmp(yyIdent + 1, "r") == 0 ) {
184 return Tok_tr; 206 return Tok_tr;
185 } else if ( qstrcmp(yyIdent + 1, "rUtf8") == 0 ) { 207 } else if ( qstrcmp(yyIdent + 1, "rUtf8") == 0 ) {
186 return Tok_trUtf8; 208 return Tok_trUtf8;
187 } else if ( qstrcmp(yyIdent + 1, "ranslate") == 0 ) { 209 } else if ( qstrcmp(yyIdent + 1, "ranslate") == 0 ) {
188 return Tok_translate; 210 return Tok_translate;
189 } 211 }
190 } 212 }
191 return Tok_Ident; 213 return Tok_Ident;
192 } else { 214 } else {
193 switch ( yyCh ) { 215 switch ( yyCh ) {
194 case '#': 216 case '#':
195 /* 217 /*
196 Early versions of lupdate complained about 218 Early versions of lupdate complained about
197 unbalanced braces in the following code: 219 unbalanced braces in the following code:
198 220
199 #ifdef ALPHA 221 #ifdef ALPHA
200 while ( beta ) { 222 while ( beta ) {
201 #else 223 #else
202 while ( gamma ) { 224 while ( gamma ) {
203 #endif 225 #endif
204 delta; 226 delta;
205 } 227 }
206 228
207 The code contains, indeed, two opening braces for 229 The code contains, indeed, two opening braces for
208 one closing brace; yet there's no reason to panic. 230 one closing brace; yet there's no reason to panic.
209 231
210 The solution is to remember yyBraceDepth as it was 232 The solution is to remember yyBraceDepth as it was
211 when #if, #ifdef or #ifndef was met, and to set 233 when #if, #ifdef or #ifndef was met, and to set
212 yyBraceDepth to that value when meeting #elif or 234 yyBraceDepth to that value when meeting #elif or
213 #else. 235 #else.
214 */ 236 */
215 do { 237 do {
216 yyCh = getChar(); 238 yyCh = getChar();
217 } while ( isspace(yyCh) && yyCh != '\n' ); 239 } while ( isspace(yyCh) && yyCh != '\n' );
218 240
219 switch ( yyCh ) { 241 switch ( yyCh ) {
220 case 'i': 242 case 'i':
221 yyCh = getChar(); 243 yyCh = getChar();
222 if ( yyCh == 'f' ) { 244 if ( yyCh == 'f' ) {
223 // if, ifdef, ifndef 245 // if, ifdef, ifndef
224 yySavedBraceDepth.push( yyBraceDepth ); 246 yySavedBraceDepth.push( yyBraceDepth );
247 yySavedParenDepth.push( yyParenDepth );
225 } 248 }
226 break; 249 break;
227 case 'e': 250 case 'e':
228 yyCh = getChar(); 251 yyCh = getChar();
229 if ( yyCh == 'l' ) { 252 if ( yyCh == 'l' ) {
230 // elif, else 253 // elif, else
231 if ( !yySavedBraceDepth.isEmpty() ) 254 if ( !yySavedBraceDepth.isEmpty() ) {
232 yyBraceDepth = yySavedBraceDepth.top(); 255 yyBraceDepth = yySavedBraceDepth.top();
256 yyParenDepth = yySavedParenDepth.top();
257 }
233 } else if ( yyCh == 'n' ) { 258 } else if ( yyCh == 'n' ) {
234 // endif 259 // endif
235 if ( !yySavedBraceDepth.isEmpty() ) 260 if ( !yySavedBraceDepth.isEmpty() ) {
236 yySavedBraceDepth.pop(); 261 yySavedBraceDepth.pop();
262 yySavedParenDepth.pop();
263 }
237 } 264 }
238 } 265 }
239 while ( isalnum(yyCh) || yyCh == '_' ) 266 while ( isalnum(yyCh) || yyCh == '_' )
240 yyCh = getChar(); 267 yyCh = getChar();
241 break; 268 break;
242 case '/': 269 case '/':
243 yyCh = getChar(); 270 yyCh = getChar();
244 if ( yyCh == '/' ) { 271 if ( yyCh == '/' ) {
245 do { 272 do {
246 yyCh = getChar(); 273 yyCh = getChar();
247 } while ( yyCh != EOF && yyCh != '\n' ); 274 } while ( yyCh != EOF && yyCh != '\n' );
248 } else if ( yyCh == '*' ) { 275 } else if ( yyCh == '*' ) {
249 bool metAster = FALSE; 276 bool metAster = FALSE;
250 bool metAsterSlash = FALSE; 277 bool metAsterSlash = FALSE;
251 278
252 while ( !metAsterSlash ) { 279 while ( !metAsterSlash ) {
253 yyCh = getChar(); 280 yyCh = getChar();
254 if ( yyCh == EOF ) { 281 if ( yyCh == EOF ) {
255 fprintf( stderr, 282 fprintf( stderr,
256 "%s: Unterminated C++ comment starting at" 283 "%s: Unterminated C++ comment starting at"
257 " line %d\n", 284 " line %d\n",
258 (const char *) yyFileName, yyLineNo ); 285 (const char *) yyFileName, yyLineNo );
259 yyComment[yyCommentLen] = '\0'; 286 yyComment[yyCommentLen] = '\0';
260 return Tok_Comment; 287 return Tok_Comment;
261 } 288 }
262 if ( yyCommentLen < sizeof(yyComment) - 1 ) 289 if ( yyCommentLen < sizeof(yyComment) - 1 )
263 yyComment[yyCommentLen++] = (char) yyCh; 290 yyComment[yyCommentLen++] = (char) yyCh;
264 291
265 if ( yyCh == '*' ) 292 if ( yyCh == '*' )
266 metAster = TRUE; 293 metAster = TRUE;
267 else if ( metAster && yyCh == '/' ) 294 else if ( metAster && yyCh == '/' )
268 metAsterSlash = TRUE; 295 metAsterSlash = TRUE;
269 else 296 else
270 metAster = FALSE; 297 metAster = FALSE;
271 } 298 }
272 yyCh = getChar(); 299 yyCh = getChar();
273 yyCommentLen -= 2; 300 yyCommentLen -= 2;
274 yyComment[yyCommentLen] = '\0'; 301 yyComment[yyCommentLen] = '\0';
275 return Tok_Comment; 302 return Tok_Comment;
276 } 303 }
277 break; 304 break;
278 case '"': 305 case '"':
279 yyCh = getChar(); 306 yyCh = getChar();
280 307
281 while ( yyCh != EOF && yyCh != '\n' && yyCh != '"' ) { 308 while ( yyCh != EOF && yyCh != '\n' && yyCh != '"' ) {
282 if ( yyCh == '\\' ) { 309 if ( yyCh == '\\' ) {
283 yyCh = getChar(); 310 yyCh = getChar();
284 311
285 if ( yyCh == '\n' ) { 312 if ( yyCh == '\n' ) {
286 yyCh = getChar(); 313 yyCh = getChar();
287 } else if ( yyCh == 'x' ) { 314 } else if ( yyCh == 'x' ) {
288 QCString hex = "0"; 315 QCString hex = "0";
289 316
290 yyCh = getChar(); 317 yyCh = getChar();
291 while ( isxdigit(yyCh) ) { 318 while ( isxdigit(yyCh) ) {
292 hex += (char) yyCh; 319 hex += (char) yyCh;
293 yyCh = getChar(); 320 yyCh = getChar();
294 } 321 }
295 sscanf( hex, "%x", &n ); 322 sscanf( hex, "%x", &n );
296 if ( yyStringLen < sizeof(yyString) - 1 ) 323 if ( yyStringLen < sizeof(yyString) - 1 )
297 yyString[yyStringLen++] = (char) n; 324 yyString[yyStringLen++] = (char) n;
298 } else if ( yyCh >= '0' && yyCh < '8' ) { 325 } else if ( yyCh >= '0' && yyCh < '8' ) {
299 QCString oct = ""; 326 QCString oct = "";
300 327
301 do { 328 do {
302 oct += (char) yyCh; 329 oct += (char) yyCh;
303 yyCh = getChar(); 330 yyCh = getChar();
304 } while ( yyCh >= '0' && yyCh < '8' ); 331 } while ( yyCh >= '0' && yyCh < '8' );
305 sscanf( oct, "%o", &n ); 332 sscanf( oct, "%o", &n );
306 if ( yyStringLen < sizeof(yyString) - 1 ) 333 if ( yyStringLen < sizeof(yyString) - 1 )
307 yyString[yyStringLen++] = (char) n; 334 yyString[yyStringLen++] = (char) n;
308 } else { 335 } else {
309 const char *p = strchr( tab, yyCh ); 336 const char *p = strchr( tab, yyCh );
310 if ( yyStringLen < sizeof(yyString) - 1 ) 337 if ( yyStringLen < sizeof(yyString) - 1 )
311 yyString[yyStringLen++] = ( p == 0 ) ? 338 yyString[yyStringLen++] = ( p == 0 ) ?
312 (char) yyCh : backTab[p - tab]; 339 (char) yyCh : backTab[p - tab];
313 yyCh = getChar(); 340 yyCh = getChar();
314 } 341 }
315 } else { 342 } else {
316 if ( yyStringLen < sizeof(yyString) - 1 ) 343 if ( yyStringLen < sizeof(yyString) - 1 )
317 yyString[yyStringLen++] = (char) yyCh; 344 yyString[yyStringLen++] = (char) yyCh;
318 yyCh = getChar(); 345 yyCh = getChar();
319 } 346 }
320 } 347 }
321 yyString[yyStringLen] = '\0'; 348 yyString[yyStringLen] = '\0';
322 349
323 if ( yyCh != '"' ) 350 if ( yyCh != '"' )
324 qWarning( "%s:%d: Unterminated C++ string", 351 qWarning( "%s:%d: Unterminated C++ string",
325 (const char *) yyFileName, yyLineNo ); 352 (const char *) yyFileName, yyLineNo );
326 353
327 if ( yyCh == EOF ) { 354 if ( yyCh == EOF ) {
328 return Tok_Eof; 355 return Tok_Eof;
329 } else { 356 } else {
330 yyCh = getChar(); 357 yyCh = getChar();
331 return Tok_String; 358 return Tok_String;
332 } 359 }
333 break; 360 break;
334 case '-': 361 case '-':
335 yyCh = getChar(); 362 yyCh = getChar();
336 if ( yyCh == '>' ) { 363 if ( yyCh == '>' ) {
337 yyCh = getChar(); 364 yyCh = getChar();
338 return Tok_Arrow; 365 return Tok_Arrow;
339 } 366 }
340 break; 367 break;
341 case ':': 368 case ':':
342 yyCh = getChar(); 369 yyCh = getChar();
343 if ( yyCh == ':' ) { 370 if ( yyCh == ':' ) {
344 yyCh = getChar(); 371 yyCh = getChar();
345 return Tok_Gulbrandsen; 372 return Tok_Gulbrandsen;
346 } 373 }
347 return Tok_Colon; 374 return Tok_Colon;
348 case '\'': 375 case '\'':
349 yyCh = getChar(); 376 yyCh = getChar();
350 if ( yyCh == '\\' ) 377 if ( yyCh == '\\' )
351 yyCh = getChar(); 378 yyCh = getChar();
352 379
353 do { 380 do {
354 yyCh = getChar(); 381 yyCh = getChar();
355 } while ( yyCh != EOF && yyCh != '\'' ); 382 } while ( yyCh != EOF && yyCh != '\'' );
356 yyCh = getChar(); 383 yyCh = getChar();
357 break; 384 break;
358 case '{': 385 case '{':
386 if (yyBraceDepth == 0)
387 yyBraceLineNo = yyCurLineNo;
359 yyBraceDepth++; 388 yyBraceDepth++;
360 yyCh = getChar(); 389 yyCh = getChar();
361 return Tok_LeftBrace; 390 return Tok_LeftBrace;
362 case '}': 391 case '}':
392 if (yyBraceDepth == 0)
393 yyBraceLineNo = yyCurLineNo;
363 yyBraceDepth--; 394 yyBraceDepth--;
364 yyCh = getChar(); 395 yyCh = getChar();
365 return Tok_RightBrace; 396 return Tok_RightBrace;
366 case '(': 397 case '(':
398 if (yyParenDepth == 0)
399 yyParenLineNo = yyCurLineNo;
367 yyParenDepth++; 400 yyParenDepth++;
368 yyCh = getChar(); 401 yyCh = getChar();
369 return Tok_LeftParen; 402 return Tok_LeftParen;
370 case ')': 403 case ')':
404 if (yyParenDepth == 0)
405 yyParenLineNo = yyCurLineNo;
371 yyParenDepth--; 406 yyParenDepth--;
372 yyCh = getChar(); 407 yyCh = getChar();
373 return Tok_RightParen; 408 return Tok_RightParen;
374 case ',': 409 case ',':
375 yyCh = getChar(); 410 yyCh = getChar();
376 return Tok_Comma; 411 return Tok_Comma;
377 case ';': 412 case ';':
378 yyCh = getChar(); 413 yyCh = getChar();
379 return Tok_Semicolon; 414 return Tok_Semicolon;
380 default: 415 default:
381 yyCh = getChar(); 416 yyCh = getChar();
382 } 417 }
383 } 418 }
384 } 419 }
385 return Tok_Eof; 420 return Tok_Eof;
386} 421}
387 422
388/* 423/*
389 The second part of this source file is the parser. It accomplishes 424 The second part of this source file is the parser. It accomplishes
390 a very easy task: It finds all strings inside a tr() or translate() 425 a very easy task: It finds all strings inside a tr() or translate()
391 call, and possibly finds out the context of the call. It supports 426 call, and possibly finds out the context of the call. It supports
392 three cases: (1) the context is specified, as in 427 three cases: (1) the context is specified, as in
393 FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello"); 428 FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello");
394 (2) the call appears within an inlined function; (3) the call 429 (2) the call appears within an inlined function; (3) the call
395 appears within a function defined outside the class definition. 430 appears within a function defined outside the class definition.
396*/ 431*/
397 432
398static int yyTok; 433static int yyTok;
399 434
400static bool match( int t ) 435static bool match( int t )
401{ 436{
402 bool matches = ( yyTok == t ); 437 bool matches = ( yyTok == t );
403 if ( matches ) 438 if ( matches )
404 yyTok = getToken(); 439 yyTok = getToken();
405 return matches; 440 return matches;
406} 441}
407 442
408static bool matchString( QCString *s ) 443static bool matchString( QCString *s )
409{ 444{
410 bool matches = ( yyTok == Tok_String ); 445 bool matches = ( yyTok == Tok_String );
411 *s = ""; 446 *s = "";
412 while ( yyTok == Tok_String ) { 447 while ( yyTok == Tok_String ) {
413 *s += yyString; 448 *s += yyString;
414 yyTok = getToken(); 449 yyTok = getToken();
415 } 450 }
416 return matches; 451 return matches;
417} 452}
418 453
419static bool matchEncoding( bool *utf8 ) 454static bool matchEncoding( bool *utf8 )
420{ 455{
421 if ( yyTok == Tok_Ident ) { 456 if ( yyTok == Tok_Ident ) {
422 if ( strcmp(yyIdent, "QApplication") == 0 ) { 457 if ( strcmp(yyIdent, "QApplication") == 0 ) {
423 yyTok = getToken(); 458 yyTok = getToken();
424 if ( yyTok == Tok_Gulbrandsen ) 459 if ( yyTok == Tok_Gulbrandsen )
425 yyTok = getToken(); 460 yyTok = getToken();
426 } 461 }
427 *utf8 = QString( yyIdent ).endsWith( QString("UTF8") ); 462 *utf8 = QString( yyIdent ).endsWith( QString("UTF8") );
428 yyTok = getToken(); 463 yyTok = getToken();
429 return TRUE; 464 return TRUE;
430 } else { 465 } else {
431 return FALSE; 466 return FALSE;
432 } 467 }
433} 468}
434 469
435static void parse( MetaTranslator *tor, const char *initialContext, 470static void parse( MetaTranslator *tor, const char *initialContext,
436 const char *defaultContext ) 471 const char *defaultContext )
437{ 472{
438 QMap<QCString, QCString> qualifiedContexts; 473 QMap<QCString, QCString> qualifiedContexts;
439 QStringList namespaces; 474 QStringList namespaces;
440 QCString context; 475 QCString context;
441 QCString text; 476 QCString text;
442 QCString com; 477 QCString com;
443 QCString functionContext = initialContext; 478 QCString functionContext = initialContext;
444 QCString prefix; 479 QCString prefix;
445 bool utf8 = FALSE; 480 bool utf8 = FALSE;
446 bool missing_Q_OBJECT = FALSE; 481 bool missing_Q_OBJECT = FALSE;
447 482
448 yyTok = getToken(); 483 yyTok = getToken();
449 while ( yyTok != Tok_Eof ) { 484 while ( yyTok != Tok_Eof ) {
450 switch ( yyTok ) { 485 switch ( yyTok ) {
451 case Tok_class: 486 case Tok_class:
452 /* 487 /*
453 Partial support for inlined functions. 488 Partial support for inlined functions.
454 */ 489 */
455 yyTok = getToken(); 490 yyTok = getToken();
456 if ( yyBraceDepth == (int) namespaces.count() && 491 if ( yyBraceDepth == (int) namespaces.count() &&
457 yyParenDepth == 0 ) { 492 yyParenDepth == 0 ) {
458 do { 493 do {
459 /* 494 /*
460 This code should execute only once, but we play 495 This code should execute only once, but we play
461 safe with impure definitions such as 496 safe with impure definitions such as
462 'class Q_EXPORT QMessageBox', in which case 497 'class Q_EXPORT QMessageBox', in which case
463 'QMessageBox' is the class name, not 'Q_EXPORT'. 498 'QMessageBox' is the class name, not 'Q_EXPORT'.
464 */ 499 */
465 functionContext = yyIdent; 500 functionContext = yyIdent;
466 yyTok = getToken(); 501 yyTok = getToken();
467 } while ( yyTok == Tok_Ident ); 502 } while ( yyTok == Tok_Ident );
468 503
469 while ( yyTok == Tok_Gulbrandsen ) { 504 while ( yyTok == Tok_Gulbrandsen ) {
470 yyTok = getToken(); 505 yyTok = getToken();
471 functionContext += "::"; 506 functionContext += "::";
472 functionContext += yyIdent; 507 functionContext += yyIdent;
473 yyTok = getToken(); 508 yyTok = getToken();
474 } 509 }
475 510
476 if ( yyTok == Tok_Colon ) { 511 if ( yyTok == Tok_Colon ) {
477 missing_Q_OBJECT = TRUE; 512 missing_Q_OBJECT = TRUE;
478 } else { 513 } else {
479 functionContext = defaultContext; 514 functionContext = defaultContext;
480 } 515 }
481 } 516 }
482 break; 517 break;
483 case Tok_namespace: 518 case Tok_namespace:
484 yyTok = getToken(); 519 yyTok = getToken();
485 if ( yyTok == Tok_Ident ) { 520 if ( yyTok == Tok_Ident ) {
486 QCString ns = yyIdent; 521 QCString ns = yyIdent;
487 yyTok = getToken(); 522 yyTok = getToken();
488 if ( yyTok == Tok_LeftBrace && 523 if ( yyTok == Tok_LeftBrace &&
489 yyBraceDepth == (int) namespaces.count() + 1 ) 524 yyBraceDepth == (int) namespaces.count() + 1 )
490 namespaces.append( QString(ns) ); 525 namespaces.append( QString(ns) );
491 } 526 }
492 break; 527 break;
493 case Tok_tr: 528 case Tok_tr:
494 case Tok_trUtf8: 529 case Tok_trUtf8:
495 utf8 = ( yyTok == Tok_trUtf8 ); 530 utf8 = ( yyTok == Tok_trUtf8 );
496 yyTok = getToken(); 531 yyTok = getToken();
497 if ( match(Tok_LeftParen) && matchString(&text) ) { 532 if ( match(Tok_LeftParen) && matchString(&text) ) {
498 com = ""; 533 com = "";
499 if ( match(Tok_RightParen) || (match(Tok_Comma) && 534 if ( match(Tok_RightParen) || (match(Tok_Comma) &&
500 matchString(&com) && match(Tok_RightParen)) ) { 535 matchString(&com) && match(Tok_RightParen)) ) {
501 if ( prefix.isNull() ) { 536 if ( prefix.isNull() ) {
502 context = functionContext; 537 context = functionContext;
503 if ( !namespaces.isEmpty() ) 538 if ( !namespaces.isEmpty() )
504 context.prepend( (namespaces.join(QString("::")) + 539 context.prepend( (namespaces.join(QString("::")) +
505 QString("::")).latin1() ); 540 QString("::")).latin1() );
506 } else { 541 } else {
507 context = prefix; 542 context = prefix;
508 } 543 }
509 prefix = (const char *) 0; 544 prefix = (const char *) 0;
510 545
511 if ( qualifiedContexts.contains(context) ) 546 if ( qualifiedContexts.contains(context) )
512 context = qualifiedContexts[context]; 547 context = qualifiedContexts[context];
513 tor->insert( MetaTranslatorMessage(context, text, com, 548 tor->insert( MetaTranslatorMessage(context, text, com,
514 QString::null, utf8) ); 549 QString::null, utf8) );
515 550
516 if ( lacks_Q_OBJECT.contains(context) ) { 551 if ( lacks_Q_OBJECT.contains(context) ) {
517 qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro", 552 qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro",
518 (const char *) yyFileName, yyLineNo, 553 (const char *) yyFileName, yyLineNo,
519 (const char *) context ); 554 (const char *) context );
520 lacks_Q_OBJECT.remove( context ); 555 lacks_Q_OBJECT.remove( context );
521 } else { 556 } else {
522 needs_Q_OBJECT.insert( context, 0 ); 557 needs_Q_OBJECT.insert( context, 0 );
523 } 558 }
524 } 559 }
525 } 560 }
526 break; 561 break;
527 case Tok_translate: 562 case Tok_translate:
528 utf8 = FALSE; 563 utf8 = FALSE;
529 yyTok = getToken(); 564 yyTok = getToken();
530 if ( match(Tok_LeftParen) && 565 if ( match(Tok_LeftParen) &&
531 matchString(&context) && 566 matchString(&context) &&
532 match(Tok_Comma) && 567 match(Tok_Comma) &&
533 matchString(&text) ) { 568 matchString(&text) ) {
534 com = ""; 569 com = "";
535 if ( match(Tok_RightParen) || 570 if ( match(Tok_RightParen) ||
536 (match(Tok_Comma) && 571 (match(Tok_Comma) &&
537 matchString(&com) && 572 matchString(&com) &&
538 (match(Tok_RightParen) || 573 (match(Tok_RightParen) ||
539 match(Tok_Comma) && 574 match(Tok_Comma) &&
540 matchEncoding(&utf8) && 575 matchEncoding(&utf8) &&
541 match(Tok_RightParen))) ) 576 match(Tok_RightParen))) )
542 tor->insert( MetaTranslatorMessage(context, text, com, 577 tor->insert( MetaTranslatorMessage(context, text, com,
543 QString::null, utf8) ); 578 QString::null, utf8) );
544 } 579 }
545 break; 580 break;
546 case Tok_Q_OBJECT: 581 case Tok_Q_OBJECT:
547 missing_Q_OBJECT = FALSE; 582 missing_Q_OBJECT = FALSE;
548 yyTok = getToken(); 583 yyTok = getToken();
549 break; 584 break;
550 case Tok_Ident: 585 case Tok_Ident:
551 if ( !prefix.isNull() ) 586 if ( !prefix.isNull() )
552 prefix += "::"; 587 prefix += "::";
553 prefix += yyIdent; 588 prefix += yyIdent;
554 yyTok = getToken(); 589 yyTok = getToken();
555 if ( yyTok != Tok_Gulbrandsen ) 590 if ( yyTok != Tok_Gulbrandsen )
556 prefix = (const char *) 0; 591 prefix = (const char *) 0;
557 break; 592 break;
558 case Tok_Comment: 593 case Tok_Comment:
559 com = yyComment; 594 com = yyComment;
560 com = com.simplifyWhiteSpace(); 595 com = com.simplifyWhiteSpace();
561 if ( com.left(sizeof(MagicComment) - 1) == MagicComment ) { 596 if ( com.left(sizeof(MagicComment) - 1) == MagicComment ) {
562 com.remove( 0, sizeof(MagicComment) - 1 ); 597 com.remove( 0, sizeof(MagicComment) - 1 );
563 int k = com.find( ' ' ); 598 int k = com.find( ' ' );
564 if ( k == -1 ) { 599 if ( k == -1 ) {
565 context = com; 600 context = com;
566 } else { 601 } else {
567 context = com.left( k ); 602 context = com.left( k );
568 com.remove( 0, k + 1 ); 603 com.remove( 0, k + 1 );
569 tor->insert( MetaTranslatorMessage(context, "", com, 604 tor->insert( MetaTranslatorMessage(context, "", com,
570 QString::null, FALSE) ); 605 QString::null, FALSE) );
571 } 606 }
572 607
573 /* 608 /*
574 Provide a backdoor for people using "using 609 Provide a backdoor for people using "using
575 namespace". See the manual for details. 610 namespace". See the manual for details.
576 */ 611 */
577 k = 0; 612 k = 0;
578 while ( (k = context.find("::", k)) != -1 ) { 613 while ( (k = context.find("::", k)) != -1 ) {
579 qualifiedContexts.insert( context.mid(k + 2), context ); 614 qualifiedContexts.insert( context.mid(k + 2), context );
580 k++; 615 k++;
581 } 616 }
582 } 617 }
583 yyTok = getToken(); 618 yyTok = getToken();
584 break; 619 break;
585 case Tok_Arrow: 620 case Tok_Arrow:
586 yyTok = getToken(); 621 yyTok = getToken();
587 if ( yyTok == Tok_tr || yyTok == Tok_trUtf8 ) 622 if ( yyTok == Tok_tr || yyTok == Tok_trUtf8 )
588 qWarning( "%s:%d: Cannot invoke tr() like this", 623 qWarning( "%s:%d: Cannot invoke tr() like this",
589 (const char *) yyFileName, yyLineNo ); 624 (const char *) yyFileName, yyLineNo );
590 break; 625 break;
591 case Tok_Gulbrandsen: 626 case Tok_Gulbrandsen:
592 // at top level? 627 // at top level?
593 if ( yyBraceDepth == (int) namespaces.count() && yyParenDepth == 0 ) 628 if ( yyBraceDepth == (int) namespaces.count() && yyParenDepth == 0 )
594 functionContext = prefix; 629 functionContext = prefix;
595 yyTok = getToken(); 630 yyTok = getToken();
596 break; 631 break;
597 case Tok_RightBrace: 632 case Tok_RightBrace:
598 case Tok_Semicolon: 633 case Tok_Semicolon:
599 if ( yyBraceDepth >= 0 && 634 if ( yyBraceDepth >= 0 &&
600 yyBraceDepth + 1 == (int) namespaces.count() ) 635 yyBraceDepth + 1 == (int) namespaces.count() )
601 namespaces.remove( namespaces.fromLast() ); 636 namespaces.remove( namespaces.fromLast() );
602 if ( yyBraceDepth == (int) namespaces.count() ) { 637 if ( yyBraceDepth == (int) namespaces.count() ) {
603 if ( missing_Q_OBJECT ) { 638 if ( missing_Q_OBJECT ) {
604 if ( needs_Q_OBJECT.contains(functionContext) ) { 639 if ( needs_Q_OBJECT.contains(functionContext) ) {
605 qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro", 640 qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro",
606 (const char *) yyFileName, yyLineNo, 641 (const char *) yyFileName, yyLineNo,
607 (const char *) functionContext ); 642 (const char *) functionContext );
608 } else { 643 } else {
609 lacks_Q_OBJECT.insert( functionContext, 0 ); 644 lacks_Q_OBJECT.insert( functionContext, 0 );
610 } 645 }
611 } 646 }
612 functionContext = defaultContext; 647 functionContext = defaultContext;
613 missing_Q_OBJECT = FALSE; 648 missing_Q_OBJECT = FALSE;
614 } 649 }
615 yyTok = getToken(); 650 yyTok = getToken();
616 break; 651 break;
617 default: 652 default:
618 yyTok = getToken(); 653 yyTok = getToken();
619 } 654 }
620 } 655 }
621 656
622 if ( yyBraceDepth != 0 ) 657 if ( yyBraceDepth != 0 )
623 fprintf( stderr, 658 fprintf( stderr,
624 "%s: Unbalanced braces in C++ code (or abuse of the C++" 659 "%s:%d: Unbalanced braces in C++ code (or abuse of the C++"
625 " preprocessor)\n", 660 " preprocessor)\n",
626 (const char *) yyFileName ); 661 (const char *)yyFileName, yyBraceLineNo );
627 if ( yyParenDepth != 0 ) 662 else if ( yyParenDepth != 0 )
628 fprintf( stderr, 663 fprintf( stderr,
629 "%s: Unbalanced parentheses in C++ code (or abuse of the C++" 664 "%s:%d: Unbalanced parentheses in C++ code (or abuse of the C++"
630 " preprocessor)\n", 665 " preprocessor)\n",
631 (const char *) yyFileName ); 666 (const char *)yyFileName, yyParenLineNo );
632} 667}
633 668
634void fetchtr_cpp( const char *fileName, MetaTranslator *tor, 669void fetchtr_cpp( const char *fileName, MetaTranslator *tor,
635 const char *defaultContext, bool mustExist ) 670 const char *defaultContext, bool mustExist )
636{ 671{
637 yyInFile = fopen( fileName, "r" ); 672 yyInFile = fopen( fileName, "r" );
638 if ( yyInFile == 0 ) { 673 if ( yyInFile == 0 ) {
639 if ( mustExist ) 674 if ( mustExist )
640 fprintf( stderr, 675 fprintf( stderr,
641 "lupdate error: Cannot open C++ source file '%s': %s\n", 676 "lupdate error: Cannot open C++ source file '%s': %s\n",
642 fileName, strerror(errno) ); 677 fileName, strerror(errno) );
643 return; 678 return;
644 } 679 }
645 680
646 startTokenizer( fileName, getCharFromFile ); 681 startTokenizer( fileName, getCharFromFile );
647 parse( tor, 0, defaultContext ); 682 parse( tor, 0, defaultContext );
648 fclose( yyInFile ); 683 fclose( yyInFile );
649} 684}
650 685
651/* 686/*
652 In addition to C++, we support Qt Designer UI files. 687 In addition to C++, we support Qt Designer UI files.
653*/ 688*/
654 689
655/* 690/*
656 Fetches tr() calls in C++ code in UI files (inside "<function>" 691 Fetches tr() calls in C++ code in UI files (inside "<function>"
657 tag). This mechanism is obsolete. 692 tag). This mechanism is obsolete.
658*/ 693*/
659void fetchtr_inlined_cpp( const char *fileName, const QString& in, 694void fetchtr_inlined_cpp( const char *fileName, const QString& in,
660 MetaTranslator *tor, const char *context ) 695 MetaTranslator *tor, const char *context )
661{ 696{
662 yyInStr = in; 697 yyInStr = in;
663 startTokenizer( fileName, getCharFromString ); 698 startTokenizer( fileName, getCharFromString );
664 parse( tor, context, 0 ); 699 parse( tor, context, 0 );
665 yyInStr = QString::null; 700 yyInStr = QString::null;
666} 701}
667 702
668class UiHandler : public QXmlDefaultHandler 703class UiHandler : public QXmlDefaultHandler
669{ 704{
670public: 705public:
671 UiHandler( MetaTranslator *translator, const char *fileName ) 706 UiHandler( MetaTranslator *translator, const char *fileName )
672 : tor( translator ), fname( fileName ), comment( "" ) { } 707 : tor( translator ), fname( fileName ), comment( "" ) { }
673 708
674 virtual bool startElement( const QString& namespaceURI, 709 virtual bool startElement( const QString& namespaceURI,
675 const QString& localName, const QString& qName, 710 const QString& localName, const QString& qName,
676 const QXmlAttributes& atts ); 711 const QXmlAttributes& atts );
677 virtual bool endElement( const QString& namespaceURI, 712 virtual bool endElement( const QString& namespaceURI,
678 const QString& localName, const QString& qName ); 713 const QString& localName, const QString& qName );
679 virtual bool characters( const QString& ch ); 714 virtual bool characters( const QString& ch );
680 virtual bool fatalError( const QXmlParseException& exception ); 715 virtual bool fatalError( const QXmlParseException& exception );
681 716
682private: 717private:
683 void flush(); 718 void flush();
684 719
685 MetaTranslator *tor; 720 MetaTranslator *tor;
686 QCString fname; 721 QCString fname;
687 QString context; 722 QString context;
688 QString source; 723 QString source;
689 QString comment; 724 QString comment;
690 725
691 QString accum; 726 QString accum;
692}; 727};
693 728
694bool UiHandler::startElement( const QString& /* namespaceURI */, 729bool UiHandler::startElement( const QString& /* namespaceURI */,
695 const QString& /* localName */, 730 const QString& /* localName */,
696 const QString& qName, 731 const QString& qName,
697 const QXmlAttributes& atts ) 732 const QXmlAttributes& atts )
698{ 733{
699 if ( qName == QString("item") ) { 734 if ( qName == QString("item") ) {
700 flush(); 735 flush();
701 if ( !atts.value(QString("text")).isEmpty() ) 736 if ( !atts.value(QString("text")).isEmpty() )
702 source = atts.value( QString("text") ); 737 source = atts.value( QString("text") );
703 } else if ( qName == QString("string") ) { 738 } else if ( qName == QString("string") ) {
704 flush(); 739 flush();
705 } 740 }
706 accum.truncate( 0 ); 741 accum.truncate( 0 );
707 return TRUE; 742 return TRUE;
708} 743}
709 744
710bool UiHandler::endElement( const QString& /* namespaceURI */, 745bool UiHandler::endElement( const QString& /* namespaceURI */,
711 const QString& /* localName */, 746 const QString& /* localName */,
712 const QString& qName ) 747 const QString& qName )
713{ 748{
714 accum.replace( QRegExp(QString("\r\n")), "\n" ); 749 accum.replace( QRegExp(QString("\r\n")), "\n" );
715 750
716 if ( qName == QString("class") ) { 751 if ( qName == QString("class") ) {
717 if ( context.isEmpty() ) 752 if ( context.isEmpty() )
718 context = accum; 753 context = accum;
719 } else if ( qName == QString("string") ) { 754 } else if ( qName == QString("string") ) {
720 source = accum; 755 source = accum;
721 } else if ( qName == QString("comment") ) { 756 } else if ( qName == QString("comment") ) {
722 comment = accum; 757 comment = accum;
723 flush(); 758 flush();
724 } else if ( qName == QString("function") ) { 759 } else if ( qName == QString("function") ) {
725 fetchtr_inlined_cpp( (const char *) fname, accum, tor, 760 fetchtr_inlined_cpp( (const char *) fname, accum, tor,
726 context.latin1() ); 761 context.latin1() );
727 } else { 762 } else {
728 flush(); 763 flush();
729 } 764 }
730 return TRUE; 765 return TRUE;
731} 766}
732 767
733bool UiHandler::characters( const QString& ch ) 768bool UiHandler::characters( const QString& ch )
734{ 769{
735 accum += ch; 770 accum += ch;
736 return TRUE; 771 return TRUE;
737} 772}
738 773
739bool UiHandler::fatalError( const QXmlParseException& exception ) 774bool UiHandler::fatalError( const QXmlParseException& exception )
740{ 775{
741 QString msg; 776 QString msg;
742 msg.sprintf( "Parse error at line %d, column %d (%s).", 777 msg.sprintf( "Parse error at line %d, column %d (%s).",
743 exception.lineNumber(), exception.columnNumber(), 778 exception.lineNumber(), exception.columnNumber(),
744 exception.message().latin1() ); 779 exception.message().latin1() );
745 fprintf( stderr, "XML error: %s\n", msg.latin1() ); 780 fprintf( stderr, "XML error: %s\n", msg.latin1() );
746 return FALSE; 781 return FALSE;
747} 782}
748 783
749void UiHandler::flush() 784void UiHandler::flush()
750{ 785{
751 if ( !context.isEmpty() && !source.isEmpty() ) 786 if ( !context.isEmpty() && !source.isEmpty() )
752 tor->insert( MetaTranslatorMessage(context.utf8(), source.utf8(), 787 tor->insert( MetaTranslatorMessage(context.utf8(), source.utf8(),
753 comment.utf8(), QString::null, 788 comment.utf8(), QString::null,
754 TRUE) ); 789 TRUE) );
755 source.truncate( 0 ); 790 source.truncate( 0 );
756 comment.truncate( 0 ); 791 comment.truncate( 0 );
757} 792}
758 793
759void fetchtr_ui( const char *fileName, MetaTranslator *tor, 794void fetchtr_ui( const char *fileName, MetaTranslator *tor,
760 const char * /* defaultContext */, bool mustExist ) 795 const char * /* defaultContext */, bool mustExist )
761{ 796{
762 QFile f( fileName ); 797 QFile f( fileName );
763 if ( !f.open(IO_ReadOnly) ) { 798 if ( !f.open(IO_ReadOnly) ) {
764 if ( mustExist ) 799 if ( mustExist )
765 fprintf( stderr, "lupdate error: cannot open UI file '%s': %s\n", 800 fprintf( stderr, "lupdate error: cannot open UI file '%s': %s\n",
766 fileName, strerror(errno) ); 801 fileName, strerror(errno) );
767 return; 802 return;
768 } 803 }
769 804
770 QTextStream t( &f ); 805 QTextStream t( &f );
771 QXmlInputSource in( t ); 806 QXmlInputSource in( t );
772 QXmlSimpleReader reader; 807 QXmlSimpleReader reader;
773 reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE ); 808 reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE );
774 reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE ); 809 reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE );
775 reader.setFeature( "http://trolltech.com/xml/features/report-whitespace" 810 reader.setFeature( "http://trolltech.com/xml/features/report-whitespace"
776 "-only-CharData", FALSE ); 811 "-only-CharData", FALSE );
777 QXmlDefaultHandler *hand = new UiHandler( tor, fileName ); 812 QXmlDefaultHandler *hand = new UiHandler( tor, fileName );
778 reader.setContentHandler( hand ); 813 reader.setContentHandler( hand );
779 reader.setErrorHandler( hand ); 814 reader.setErrorHandler( hand );
780 815
781 if ( !reader.parse(in) ) 816 if ( !reader.parse(in) )
782 fprintf( stderr, "%s: Parse error in UI file\n", fileName ); 817 fprintf( stderr, "%s: Parse error in UI file\n", fileName );
783 reader.setContentHandler( 0 ); 818 reader.setContentHandler( 0 );
784 reader.setErrorHandler( 0 ); 819 reader.setErrorHandler( 0 );
785 delete hand; 820 delete hand;
786 f.close(); 821 f.close();
787} 822}
diff --git a/development/translation/opie-lupdate/main.cpp b/development/translation/opie-lupdate/main.cpp
index ce65e7a..bf16fd7 100644
--- a/development/translation/opie-lupdate/main.cpp
+++ b/development/translation/opie-lupdate/main.cpp
@@ -1,215 +1,224 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** Copyright (C) 2003 zecke 3** Copyright (C) 2003 zecke
4** 4**
5** This file is part of Qt Linguist. 5** This file is part of Qt Linguist.
6** 6**
7** This file may be distributed and/or modified under the terms of the 7** This file may be distributed and/or modified under the terms of the
8** GNU General Public License version 2 as published by the Free Software 8** GNU General Public License version 2 as published by the Free Software
9** Foundation and appearing in the file LICENSE.GPL included in the 9** Foundation and appearing in the file LICENSE.GPL included in the
10** packaging of this file. 10** packaging of this file.
11** 11**
12** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 12** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
13** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 13** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14** 14**
15** See http://www.trolltech.com/gpl/ for GPL licensing information. 15** See http://www.trolltech.com/gpl/ for GPL licensing information.
16** 16**
17** Contact info@trolltech.com if any conditions of this licensing are 17** Contact info@trolltech.com if any conditions of this licensing are
18** not clear to you. 18** not clear to you.
19** 19**
20**********************************************************************/ 20**********************************************************************/
21 21
22#include <metatranslator.h> 22#include <metatranslator.h>
23#include <proparser.h> 23#include <proparser.h>
24#include <opie.h> 24#include <opie.h>
25 25
26#include <qfile.h> 26#include <qfile.h>
27#include <qfileinfo.h> 27#include <qfileinfo.h>
28#include <qstring.h> 28#include <qstring.h>
29#include <qstringlist.h> 29#include <qstringlist.h>
30#include <qtextstream.h> 30#include <qtextstream.h>
31 31
32#include <errno.h> 32#include <errno.h>
33#include <string.h> 33#include <string.h>
34 34
35// defined in fetchtr.cpp 35// defined in fetchtr.cpp
36extern void fetchtr_cpp( const char *fileName, MetaTranslator *tor, 36extern void fetchtr_cpp( const char *fileName, MetaTranslator *tor,
37 const char *defaultContext, bool mustExist ); 37 const char *defaultContext, bool mustExist );
38extern void fetchtr_ui( const char *fileName, MetaTranslator *tor, 38extern void fetchtr_ui( const char *fileName, MetaTranslator *tor,
39 const char *defaultContext, bool mustExist ); 39 const char *defaultContext, bool mustExist );
40 40
41// defined in merge.cpp 41// defined in merge.cpp
42extern void merge( MetaTranslator *tor, const MetaTranslator *virginTor, 42extern void merge( MetaTranslator *tor, const MetaTranslator *virginTor,
43 bool verbose ); 43 bool verbose );
44 44
45typedef QValueList<MetaTranslatorMessage> TML; 45typedef QValueList<MetaTranslatorMessage> TML;
46 46
47static const char* LUPDATE_VERSION = "0.1"; 47static const char* LUPDATE_VERSION = "0.1";
48 48
49static void printUsage() 49static void printUsage()
50{ 50{
51 fprintf( stderr, "Usage:\n" 51 fprintf( stderr, "Usage:\n"
52 " opie-lupdate [options] project-file\n" 52 " opie-lupdate [options] project-file\n"
53 " opie-lupdate [options] source-files -ts ts-files\n" 53 " opie-lupdate [options] source-files -ts ts-files\n"
54 "Options:\n" 54 "Options:\n"
55 " -opie The OPIE base dir if not supplied $OPIEDIR will be taken\n" 55 " -opie The OPIE base dir if not supplied $OPIEDIR will be taken\n"
56 " -help Display this information and exit\n" 56 " -help Display this information and exit\n"
57 " -noobsolete\n" 57 " -noobsolete\n"
58 " Drop all obsolete strings\n" 58 " Drop all obsolete strings\n"
59 " -verbose\n" 59 " -verbose\n"
60 " Explain what is being done\n" 60 " Explain what is being done\n"
61 " -version\n" 61 " -version\n"
62 " Display the version of lupdate and exit\n" ); 62 " Display the version of lupdate and exit\n" );
63} 63}
64 64
65/*static QString opie_escape( const QString& str ) {
66 QString ret = str.stripWhiteSpace();
67 qWarning(ret);
68 if ( ret.startsWith("$$(OPIEDIR)") )
69 ret = ret.replace("$$(OPIEDIR)", OPIE::self()->opieDir() );
70 qWarning(ret);
71 return ret;
72 }*/
73
65static void updateTsFiles( const MetaTranslator& fetchedTor, 74static void updateTsFiles( const MetaTranslator& fetchedTor,
66 const QString& opiedir, 75 const QString& opiedir,
67 const QStringList& languages, 76 const QStringList& languages,
68 const QString& basename, 77 const QString& basename,
69 const QString& codec, 78 const QString& codec,
70 bool noObsolete, bool verbose ) 79 bool noObsolete, bool verbose )
71{ 80{
72 QStringList::ConstIterator it = languages.begin(); 81 QStringList::ConstIterator it = languages.begin();
73 for ( ; it != languages.end(); ++it ) { 82 for ( ; it != languages.end(); ++it ) {
74 QString fileName = opiedir + "/i18n/" + (*it) + "/" + basename; 83 QString fileName = opiedir + "/i18n/" + (*it) + "/" + basename;
75 MetaTranslator tor; 84 MetaTranslator tor;
76 tor.load( fileName ); 85 tor.load( fileName );
77 if ( !codec.isEmpty() ) 86 if ( !codec.isEmpty() )
78 tor.setCodec( codec ); 87 tor.setCodec( codec );
79 if ( verbose ) 88 if ( verbose )
80 fprintf( stderr, "Updating '%s'...\n", fileName.latin1() ); 89 fprintf( stderr, "Updating '%s'...\n", fileName.latin1() );
81 merge( &tor, &fetchedTor, verbose ); 90 merge( &tor, &fetchedTor, verbose );
82 if ( noObsolete ) 91 if ( noObsolete )
83 tor.stripObsoleteMessages(); 92 tor.stripObsoleteMessages();
84 tor.stripEmptyContexts(); 93 tor.stripEmptyContexts();
85 if ( !tor.save(fileName) ) 94 if ( !tor.save(fileName) )
86 fprintf( stderr, "lupdate error: Cannot save '%s': %s\n", 95 fprintf( stderr, "lupdate error: Cannot save '%s': %s\n",
87 fileName.latin1(), strerror(errno) ); 96 fileName.latin1(), strerror(errno) );
88 } 97 }
89} 98}
90 99
91int main( int argc, char **argv ) 100int main( int argc, char **argv )
92{ 101{
93 QString defaultContext = "@default"; 102 QString defaultContext = "@default";
94 MetaTranslator fetchedTor; 103 MetaTranslator fetchedTor;
95 QCString codec; 104 QCString codec;
96 QStringList tsFileNames; 105 QStringList tsFileNames;
97 QString opiedir; 106 QString opiedir;
98 QString translationBase; 107 QString translationBase;
99 QString target; 108 QString target;
100 109
101 bool verbose = FALSE; 110 bool verbose = FALSE;
102 bool noObsolete = FALSE; 111 bool noObsolete = FALSE;
103 bool metSomething = FALSE; 112 bool metSomething = FALSE;
104 bool isLib = FALSE; 113 bool isLib = FALSE;
105 int numFiles = 0; 114 int numFiles = 0;
106 115
107 int i; 116 int i;
108 117
109 QStringList languageList = OPIE::self()->languageList(opiedir); 118 QStringList languageList = OPIE::self()->languageList(opiedir);
110 119
111 for ( i = 1; i < argc; i++ ) { 120 for ( i = 1; i < argc; i++ ) {
112 if ( qstrcmp(argv[i], "-help") == 0 ) { 121 if ( qstrcmp(argv[i], "-help") == 0 ) {
113 printUsage(); 122 printUsage();
114 return 0; 123 return 0;
115 } else if ( qstrcmp(argv[i], "-noobsolete") == 0 ) { 124 } else if ( qstrcmp(argv[i], "-noobsolete") == 0 ) {
116 noObsolete = TRUE; 125 noObsolete = TRUE;
117 continue; 126 continue;
118 } else if ( qstrcmp(argv[i], "-verbose") == 0 ) { 127 } else if ( qstrcmp(argv[i], "-verbose") == 0 ) {
119 verbose = TRUE; 128 verbose = TRUE;
120 continue; 129 continue;
121 } else if ( qstrcmp(argv[i], "-version") == 0 ) { 130 } else if ( qstrcmp(argv[i], "-version") == 0 ) {
122 fprintf( stderr, "lupdate version %s\n", LUPDATE_VERSION ); 131 fprintf( stderr, "lupdate version %s\n", LUPDATE_VERSION );
123 return 0; 132 return 0;
124 } else if ( qstrcmp(argv[i], "-opie") == 0 ) { 133 } else if ( qstrcmp(argv[i], "-opie") == 0 ) {
125 if( i+1 < argc ) { 134 if( i+1 < argc ) {
126 opiedir = argv[i+1]; 135 opiedir = argv[i+1];
127 languageList = OPIE::self()->languageList(opiedir); 136 languageList = OPIE::self()->languageList(opiedir);
128 } 137 }
129 i++; // UGLY but we want to skip the next argument 138 i++; // UGLY but we want to skip the next argument
130 continue; 139 continue;
131 } 140 }
132 141
133 numFiles++; 142 numFiles++;
134 143
135 QString fullText; 144 QString fullText;
136 145
137 QFile f( argv[i] ); 146 QFile f( argv[i] );
138 if ( !f.open(IO_ReadOnly) ) { 147 if ( !f.open(IO_ReadOnly) ) {
139 fprintf( stderr, "lupdate error: Cannot open file '%s': %s\n", 148 fprintf( stderr, "lupdate error: Cannot open file '%s': %s\n",
140 argv[i], strerror(errno) ); 149 argv[i], strerror(errno) );
141 return 1; 150 return 1;
142 } 151 }
143 152
144 QTextStream t( &f ); 153 QTextStream t( &f );
145 fullText = t.read(); 154 fullText = t.read();
146 f.close(); 155 f.close();
147 156
148 fetchedTor = MetaTranslator(); 157 fetchedTor = MetaTranslator();
149 codec.truncate( 0 ); 158 codec.truncate( 0 );
150 tsFileNames.clear(); 159 tsFileNames.clear();
151 isLib = FALSE; 160 isLib = FALSE;
152 161
153 QMap<QString, QString> tagMap = proFileTagMap( fullText ); 162 QMap<QString, QString> tagMap = proFileTagMap( fullText, OPIE::self()->opieDir() );
154 QMap<QString, QString>::Iterator it; 163 QMap<QString, QString>::Iterator it;
155 164
156 for ( it = tagMap.begin(); it != tagMap.end(); ++it ) { 165 for ( it = tagMap.begin(); it != tagMap.end(); ++it ) {
157 QStringList toks = QStringList::split( ' ', it.data() ); 166 QStringList toks = QStringList::split( ' ', it.data() );
158 QStringList::Iterator t; 167 QStringList::Iterator t;
159 168
160 for ( t = toks.begin(); t != toks.end(); ++t ) { 169 for ( t = toks.begin(); t != toks.end(); ++t ) {
161 if ( it.key() == "HEADERS" || it.key() == "SOURCES" ) { 170 if ( it.key() == "HEADERS" || it.key() == "SOURCES" ) {
162 fetchtr_cpp( *t, &fetchedTor, defaultContext, TRUE ); 171 fetchtr_cpp( *t, &fetchedTor, defaultContext, TRUE );
163 metSomething = TRUE; 172 metSomething = TRUE;
164 } else if ( it.key() == "INTERFACES" || 173 } else if ( it.key() == "INTERFACES" ||
165 it.key() == "FORMS" ) { 174 it.key() == "FORMS" ) {
166 fetchtr_ui( *t, &fetchedTor, defaultContext, TRUE ); 175 fetchtr_ui( *t, &fetchedTor, defaultContext, TRUE );
167 fetchtr_cpp( *t + ".h", &fetchedTor, defaultContext, 176 fetchtr_cpp( *t + ".h", &fetchedTor, defaultContext,
168 FALSE ); 177 FALSE );
169 metSomething = TRUE; 178 metSomething = TRUE;
170 } else if ( it.key() == "TRANSLATIONS" ) { 179 } else if ( it.key() == "TRANSLATIONS" ) {
171 // we do not care for that attribute anymore 180 // we do not care for that attribute anymore
172 //tsFileNames.append( *t ); 181 //tsFileNames.append( *t );
173 metSomething = TRUE; 182 metSomething = TRUE;
174 } else if ( it.key() == "CODEC" ) { 183 } else if ( it.key() == "CODEC" ) {
175 codec = (*t).latin1(); 184 codec = (*t).latin1();
176 } else if ( it.key() == "TARGET" ) { 185 } else if ( it.key() == "TARGET" ) {
177 target = *t; 186 target = *t;
178 metSomething = TRUE; 187 metSomething = TRUE;
179 } else if ( it.key() == "TEMPLATE" ) { 188 } else if ( it.key() == "TEMPLATE" ) {
180 if ( (*t).stripWhiteSpace().lower() == "lib" ) 189 if ( (*t).stripWhiteSpace().lower() == "lib" )
181 isLib = true; 190 isLib = true;
182 } 191 }
183 } 192 }
184 } 193 }
185 /** 194 /**
186 * We know the $OPIEDIR or have opiedir 195 * We know the $OPIEDIR or have opiedir
187 * we've a list of languages (de,en,gb,foo,bar) 196 * we've a list of languages (de,en,gb,foo,bar)
188 * we've got the TARGET and we no it's the lib 197 * we've got the TARGET and we no it's the lib
189 * so let's do that 198 * so let's do that
190 * $OPIEDIR/language[i]/ifLibAppendLib$TARGET.ts 199 * $OPIEDIR/language[i]/ifLibAppendLib$TARGET.ts
191 */ 200 */
192 qWarning("TARGET %s IsLib:%d", target.latin1(), isLib ); 201 qWarning("TARGET %s IsLib:%d", target.latin1(), isLib );
193 qWarning("LANGS %s", languageList.join(";").latin1() ); 202 qWarning("LANGS %s", languageList.join(";").latin1() );
194 qWarning("OPIEDIR %s", OPIE::self()->opieDir(opiedir).latin1() ); 203 qWarning("OPIEDIR %s", OPIE::self()->opieDir(opiedir).latin1() );
195 if (isLib ) 204 if (isLib )
196 target.prepend("lib"); 205 target.prepend("lib");
197 target += ".ts"; 206 target += ".ts";
198 updateTsFiles( fetchedTor, OPIE::self()->opieDir(opiedir), 207 updateTsFiles( fetchedTor, OPIE::self()->opieDir(opiedir),
199 languageList, target, codec, noObsolete, verbose ); 208 languageList, target, codec, noObsolete, verbose );
200 209
201 if ( !metSomething ) { 210 if ( !metSomething ) {
202 fprintf( stderr, 211 fprintf( stderr,
203 "lupdate warning: File '%s' does not look like a" 212 "lupdate warning: File '%s' does not look like a"
204 " project file\n", 213 " project file\n",
205 argv[i] ); 214 argv[i] );
206 } 215 }
207 216
208 } 217 }
209 218
210 if ( numFiles == 0 ) { 219 if ( numFiles == 0 ) {
211 printUsage(); 220 printUsage();
212 return 1; 221 return 1;
213 } 222 }
214 return 0; 223 return 0;
215} 224}
diff --git a/development/translation/opie-lupdate/merge.cpp b/development/translation/opie-lupdate/merge.cpp
index a96104e..3001d4b 100644
--- a/development/translation/opie-lupdate/merge.cpp
+++ b/development/translation/opie-lupdate/merge.cpp
@@ -1,115 +1,121 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qt Linguist. 4** This file is part of Qt Linguist.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12** licenses may use this file in accordance with the Qt Commercial License
13** Agreement provided with the Software.
14**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 17**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 18** See http://www.trolltech.com/gpl/ for GPL licensing information.
19** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20** information about Qt Commercial License Agreements.
15** 21**
16** Contact info@trolltech.com if any conditions of this licensing are 22** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 23** not clear to you.
18** 24**
19**********************************************************************/ 25**********************************************************************/
20 26
21#include <metatranslator.h> 27#include <metatranslator.h>
22 28
23// defined in numberh.cpp 29// defined in numberh.cpp
24extern void applyNumberHeuristic( MetaTranslator *tor, bool verbose ); 30extern void applyNumberHeuristic( MetaTranslator *tor, bool verbose );
25// defined in sametexth.cpp 31// defined in sametexth.cpp
26extern void applySameTextHeuristic( MetaTranslator *tor, bool verbose ); 32extern void applySameTextHeuristic( MetaTranslator *tor, bool verbose );
27 33
28typedef QValueList<MetaTranslatorMessage> TML; 34typedef QValueList<MetaTranslatorMessage> TML;
29 35
30/* 36/*
31 Merges two MetaTranslator objects into the first one. The first one 37 Merges two MetaTranslator objects into the first one. The first one
32 is a set of source texts and translations for a previous version of 38 is a set of source texts and translations for a previous version of
33 the internationalized program; the second one is a set of fresh 39 the internationalized program; the second one is a set of fresh
34 source texts newly extracted from the source code, without any 40 source texts newly extracted from the source code, without any
35 translation yet. 41 translation yet.
36*/ 42*/
37 43
38void merge( MetaTranslator *tor, const MetaTranslator *virginTor, bool verbose ) 44void merge( MetaTranslator *tor, const MetaTranslator *virginTor, bool verbose )
39{ 45{
40 int known = 0; 46 int known = 0;
41 int neww = 0; 47 int neww = 0;
42 int obsoleted = 0; 48 int obsoleted = 0;
43 TML all = tor->messages(); 49 TML all = tor->messages();
44 TML::Iterator it; 50 TML::Iterator it;
45 51
46 /* 52 /*
47 The types of all the messages from the vernacular translator 53 The types of all the messages from the vernacular translator
48 are updated according to the virgin translator. 54 are updated according to the virgin translator.
49 */ 55 */
50 for ( it = all.begin(); it != all.end(); ++it ) { 56 for ( it = all.begin(); it != all.end(); ++it ) {
51 MetaTranslatorMessage::Type newType; 57 MetaTranslatorMessage::Type newType;
52 MetaTranslatorMessage m = *it; 58 MetaTranslatorMessage m = *it;
53 59
54 // skip context comment 60 // skip context comment
55 if ( !QCString((*it).sourceText()).isEmpty() ) { 61 if ( !QCString((*it).sourceText()).isEmpty() ) {
56 if ( !virginTor->contains((*it).context(), (*it).sourceText(), 62 if ( !virginTor->contains((*it).context(), (*it).sourceText(),
57 (*it).comment()) ) { 63 (*it).comment()) ) {
58 newType = MetaTranslatorMessage::Obsolete; 64 newType = MetaTranslatorMessage::Obsolete;
59 if ( m.type() != MetaTranslatorMessage::Obsolete ) 65 if ( m.type() != MetaTranslatorMessage::Obsolete )
60 obsoleted++; 66 obsoleted++;
61 } else { 67 } else {
62 switch ( m.type() ) { 68 switch ( m.type() ) {
63 case MetaTranslatorMessage::Finished: 69 case MetaTranslatorMessage::Finished:
64 newType = MetaTranslatorMessage::Finished; 70 newType = MetaTranslatorMessage::Finished;
65 known++; 71 known++;
66 break; 72 break;
67 case MetaTranslatorMessage::Unfinished: 73 case MetaTranslatorMessage::Unfinished:
68 newType = MetaTranslatorMessage::Unfinished; 74 newType = MetaTranslatorMessage::Unfinished;
69 known++; 75 known++;
70 break; 76 break;
71 case MetaTranslatorMessage::Obsolete: 77 case MetaTranslatorMessage::Obsolete:
72 newType = MetaTranslatorMessage::Unfinished; 78 newType = MetaTranslatorMessage::Unfinished;
73 neww++; 79 neww++;
74 } 80 }
75 } 81 }
76 82
77 if ( newType != m.type() ) { 83 if ( newType != m.type() ) {
78 m.setType( newType ); 84 m.setType( newType );
79 tor->insert( m ); 85 tor->insert( m );
80 } 86 }
81 } 87 }
82 } 88 }
83 89
84 /* 90 /*
85 Messages found only in the virgin translator are added to the 91 Messages found only in the virgin translator are added to the
86 vernacular translator. Among these are all the context comments. 92 vernacular translator. Among these are all the context comments.
87 */ 93 */
88 all = virginTor->messages(); 94 all = virginTor->messages();
89 95
90 for ( it = all.begin(); it != all.end(); ++it ) { 96 for ( it = all.begin(); it != all.end(); ++it ) {
91 if ( !tor->contains((*it).context(), (*it).sourceText(), 97 if ( !tor->contains((*it).context(), (*it).sourceText(),
92 (*it).comment()) ) { 98 (*it).comment()) ) {
93 tor->insert( *it ); 99 tor->insert( *it );
94 if ( !QCString((*it).sourceText()).isEmpty() ) 100 if ( !QCString((*it).sourceText()).isEmpty() )
95 neww++; 101 neww++;
96 } 102 }
97 } 103 }
98 104
99 /* 105 /*
100 The same-text heuristic handles cases where a message has an 106 The same-text heuristic handles cases where a message has an
101 obsolete counterpart with a different context or comment. 107 obsolete counterpart with a different context or comment.
102 */ 108 */
103 applySameTextHeuristic( tor, verbose ); 109 applySameTextHeuristic( tor, verbose );
104 110
105 /* 111 /*
106 The number heuristic handles cases where a message has an 112 The number heuristic handles cases where a message has an
107 obsolete counterpart with mostly numbers differing in the 113 obsolete counterpart with mostly numbers differing in the
108 source text. 114 source text.
109 */ 115 */
110 applyNumberHeuristic( tor, verbose ); 116 applyNumberHeuristic( tor, verbose );
111 117
112 if ( verbose ) 118 if ( verbose )
113 fprintf( stderr, " %d known, %d new and %d obsoleted messages\n", known, 119 fprintf( stderr, " %d known, %d new and %d obsoleted messages\n", known,
114 neww, obsoleted ); 120 neww, obsoleted );
115} 121}
diff --git a/development/translation/opie-lupdate/numberh.cpp b/development/translation/opie-lupdate/numberh.cpp
index f7b7bf8..2f12c3d 100644
--- a/development/translation/opie-lupdate/numberh.cpp
+++ b/development/translation/opie-lupdate/numberh.cpp
@@ -1,235 +1,241 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qt Linguist. 4** This file is part of Qt Linguist.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12** licenses may use this file in accordance with the Qt Commercial License
13** Agreement provided with the Software.
14**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 17**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 18** See http://www.trolltech.com/gpl/ for GPL licensing information.
19** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20** information about Qt Commercial License Agreements.
15** 21**
16** Contact info@trolltech.com if any conditions of this licensing are 22** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 23** not clear to you.
18** 24**
19**********************************************************************/ 25**********************************************************************/
20 26
21#include <metatranslator.h> 27#include <metatranslator.h>
22 28
23#include <qmemarray.h> 29#include <qmemarray.h>
24#include <qcstring.h> 30#include <qcstring.h>
25#include <qmap.h> 31#include <qmap.h>
26#include <qstringlist.h> 32#include <qstringlist.h>
27 33
28#include <ctype.h> 34#include <ctype.h>
29 35
30typedef QMap<QCString, MetaTranslatorMessage> TMM; 36typedef QMap<QCString, MetaTranslatorMessage> TMM;
31typedef QValueList<MetaTranslatorMessage> TML; 37typedef QValueList<MetaTranslatorMessage> TML;
32 38
33static bool isDigitFriendly( int c ) 39static bool isDigitFriendly( int c )
34{ 40{
35 return ispunct( c ) || isspace( c ); 41 return ispunct((uchar)c) || isspace((uchar)c);
36} 42}
37 43
38static int numberLength( const char *s ) 44static int numberLength( const char *s )
39{ 45{
40 int i = 0; 46 int i = 0;
41 47
42 if ( isdigit(s[0]) ) { 48 if ( isdigit((uchar)s[0]) ) {
43 do { 49 do {
44 i++; 50 i++;
45 } while ( isdigit(s[i]) || 51 } while (isdigit((uchar)s[i]) ||
46 (isDigitFriendly(s[i]) && 52 (isDigitFriendly(s[i]) &&
47 (isdigit(s[i + 1]) || 53 (isdigit((uchar)s[i + 1]) ||
48 (isDigitFriendly(s[i + 1]) && isdigit(s[i + 2])))) ); 54 (isDigitFriendly(s[i + 1]) && isdigit((uchar)s[i + 2])))));
49 } 55 }
50 return i; 56 return i;
51} 57}
52 58
53/* 59/*
54 Returns a version of 'key' where all numbers have been replaced by zeroes. If 60 Returns a version of 'key' where all numbers have been replaced by zeroes. If
55 there were none, returns "". 61 there were none, returns "".
56*/ 62*/
57static QCString zeroKey( const char *key ) 63static QCString zeroKey( const char *key )
58{ 64{
59 QCString zeroed( strlen(key) + 1 ); 65 QCString zeroed( strlen(key) + 1 );
60 char *z = zeroed.data(); 66 char *z = zeroed.data();
61 int i = 0, j = 0; 67 int i = 0, j = 0;
62 int len; 68 int len;
63 bool metSomething = FALSE; 69 bool metSomething = FALSE;
64 70
65 while ( key[i] != '\0' ) { 71 while ( key[i] != '\0' ) {
66 len = numberLength( key + i ); 72 len = numberLength( key + i );
67 if ( len > 0 ) { 73 if ( len > 0 ) {
68 i += len; 74 i += len;
69 z[j++] = '0'; 75 z[j++] = '0';
70 metSomething = TRUE; 76 metSomething = TRUE;
71 } else { 77 } else {
72 z[j++] = key[i++]; 78 z[j++] = key[i++];
73 } 79 }
74 } 80 }
75 z[j] = '\0'; 81 z[j] = '\0';
76 82
77 if ( metSomething ) 83 if ( metSomething )
78 return zeroed; 84 return zeroed;
79 else 85 else
80 return ""; 86 return "";
81} 87}
82 88
83static QString translationAttempt( const QString& oldTranslation, 89static QString translationAttempt( const QString& oldTranslation,
84 const char *oldSource, 90 const char *oldSource,
85 const char *newSource ) 91 const char *newSource )
86{ 92{
87 int p = zeroKey( oldSource ).contains( '0' ); 93 int p = zeroKey( oldSource ).contains( '0' );
88 int oldSourceLen = qstrlen( oldSource ); 94 int oldSourceLen = qstrlen( oldSource );
89 QString attempt; 95 QString attempt;
90 QStringList oldNumbers; 96 QStringList oldNumbers;
91 QStringList newNumbers; 97 QStringList newNumbers;
92 QMemArray<bool> met( p ); 98 QMemArray<bool> met( p );
93 QMemArray<int> matchedYet( p ); 99 QMemArray<int> matchedYet( p );
94 int i, j; 100 int i, j;
95 int k = 0, ell, best; 101 int k = 0, ell, best;
96 int m, n; 102 int m, n;
97 int pass; 103 int pass;
98 104
99 /* 105 /*
100 This algorithm is hard to follow, so we'll consider an example 106 This algorithm is hard to follow, so we'll consider an example
101 all along: oldTranslation is "XeT 3.0", oldSource is "TeX 3.0" 107 all along: oldTranslation is "XeT 3.0", oldSource is "TeX 3.0"
102 and newSource is "XeT 3.1". 108 and newSource is "XeT 3.1".
103 109
104 First, we set up two tables: oldNumbers and newNumbers. In our 110 First, we set up two tables: oldNumbers and newNumbers. In our
105 example, oldNumber[0] is "3.0" and newNumber[0] is "3.1". 111 example, oldNumber[0] is "3.0" and newNumber[0] is "3.1".
106 */ 112 */
107 for ( i = 0, j = 0; i < oldSourceLen; i++, j++ ) { 113 for ( i = 0, j = 0; i < oldSourceLen; i++, j++ ) {
108 m = numberLength( oldSource + i ); 114 m = numberLength( oldSource + i );
109 n = numberLength( newSource + j ); 115 n = numberLength( newSource + j );
110 if ( m > 0 ) { 116 if ( m > 0 ) {
111 oldNumbers.append( QCString(oldSource + i, m + 1) ); 117 oldNumbers.append( QCString(oldSource + i, m + 1) );
112 newNumbers.append( QCString(newSource + j, n + 1) ); 118 newNumbers.append( QCString(newSource + j, n + 1) );
113 i += m; 119 i += m;
114 j += n; 120 j += n;
115 met[k] = FALSE; 121 met[k] = FALSE;
116 matchedYet[k] = 0; 122 matchedYet[k] = 0;
117 k++; 123 k++;
118 } 124 }
119 } 125 }
120 126
121 /* 127 /*
122 We now go over the old translation, "XeT 3.0", one letter at a 128 We now go over the old translation, "XeT 3.0", one letter at a
123 time, looking for numbers found in oldNumbers. Whenever such a 129 time, looking for numbers found in oldNumbers. Whenever such a
124 number is met, it is replaced with its newNumber equivalent. In 130 number is met, it is replaced with its newNumber equivalent. In
125 our example, the "3.0" of "XeT 3.0" becomes "3.1". 131 our example, the "3.0" of "XeT 3.0" becomes "3.1".
126 */ 132 */
127 for ( i = 0; i < (int) oldTranslation.length(); i++ ) { 133 for ( i = 0; i < (int) oldTranslation.length(); i++ ) {
128 attempt += oldTranslation[i]; 134 attempt += oldTranslation[i];
129 for ( k = 0; k < p; k++ ) { 135 for ( k = 0; k < p; k++ ) {
130 if ( oldTranslation[i] == oldNumbers[k][matchedYet[k]] ) 136 if ( oldTranslation[i] == oldNumbers[k][matchedYet[k]] )
131 matchedYet[k]++; 137 matchedYet[k]++;
132 else 138 else
133 matchedYet[k] = 0; 139 matchedYet[k] = 0;
134 } 140 }
135 141
136 /* 142 /*
137 Let's find out if the last character ended a match. We make 143 Let's find out if the last character ended a match. We make
138 two passes over the data. In the first pass, we try to 144 two passes over the data. In the first pass, we try to
139 match only numbers that weren't matched yet; if that fails, 145 match only numbers that weren't matched yet; if that fails,
140 the second pass does the trick. This is useful in some 146 the second pass does the trick. This is useful in some
141 suspicious cases, flagged below. 147 suspicious cases, flagged below.
142 */ 148 */
143 for ( pass = 0; pass < 2; pass++ ) { 149 for ( pass = 0; pass < 2; pass++ ) {
144 best = p; // an impossible value 150 best = p; // an impossible value
145 for ( k = 0; k < p; k++ ) { 151 for ( k = 0; k < p; k++ ) {
146 if ( (!met[k] || pass > 0) && 152 if ( (!met[k] || pass > 0) &&
147 matchedYet[k] == (int) oldNumbers[k].length() && 153 matchedYet[k] == (int) oldNumbers[k].length() &&
148 numberLength(oldTranslation.latin1() + (i + 1) - 154 numberLength(oldTranslation.latin1() + (i + 1) -
149 matchedYet[k]) == matchedYet[k] ) { 155 matchedYet[k]) == matchedYet[k] ) {
150 // the longer the better 156 // the longer the better
151 if ( best == p || matchedYet[k] > matchedYet[best] ) 157 if ( best == p || matchedYet[k] > matchedYet[best] )
152 best = k; 158 best = k;
153 } 159 }
154 } 160 }
155 if ( best != p ) { 161 if ( best != p ) {
156 attempt.truncate( attempt.length() - matchedYet[best] ); 162 attempt.truncate( attempt.length() - matchedYet[best] );
157 attempt += newNumbers[best]; 163 attempt += newNumbers[best];
158 met[best] = TRUE; 164 met[best] = TRUE;
159 for ( k = 0; k < p; k++ ) 165 for ( k = 0; k < p; k++ )
160 matchedYet[k] = 0; 166 matchedYet[k] = 0;
161 break; 167 break;
162 } 168 }
163 } 169 }
164 } 170 }
165 171
166 /* 172 /*
167 We flag two kinds of suspicious cases. They are identified as 173 We flag two kinds of suspicious cases. They are identified as
168 such with comments such as "{2000?}" at the end. 174 such with comments such as "{2000?}" at the end.
169 175
170 Example of the first kind: old source text "TeX 3.0" translated 176 Example of the first kind: old source text "TeX 3.0" translated
171 as "XeT 2.0" is flagged "TeX 2.0 {3.0?}", no matter what the 177 as "XeT 2.0" is flagged "TeX 2.0 {3.0?}", no matter what the
172 new text is. 178 new text is.
173 */ 179 */
174 for ( k = 0; k < p; k++ ) { 180 for ( k = 0; k < p; k++ ) {
175 if ( !met[k] ) 181 if ( !met[k] )
176 attempt += QString( " {" ) + newNumbers[k] + QString( "?}" ); 182 attempt += QString( " {" ) + newNumbers[k] + QString( "?}" );
177 } 183 }
178 184
179 /* 185 /*
180 Example of the second kind: "1 of 1" translated as "1 af 1", 186 Example of the second kind: "1 of 1" translated as "1 af 1",
181 with new source text "1 of 2", generates "1 af 2 {1 or 2?}" 187 with new source text "1 of 2", generates "1 af 2 {1 or 2?}"
182 because it's not clear which of "1 af 2" and "2 af 1" is right. 188 because it's not clear which of "1 af 2" and "2 af 1" is right.
183 */ 189 */
184 for ( k = 0; k < p; k++ ) { 190 for ( k = 0; k < p; k++ ) {
185 for ( ell = 0; ell < p; ell++ ) { 191 for ( ell = 0; ell < p; ell++ ) {
186 if ( k != ell && oldNumbers[k] == oldNumbers[ell] && 192 if ( k != ell && oldNumbers[k] == oldNumbers[ell] &&
187 newNumbers[k] < newNumbers[ell] ) 193 newNumbers[k] < newNumbers[ell] )
188 attempt += QString( " {" ) + newNumbers[k] + QString( " or " ) + 194 attempt += QString( " {" ) + newNumbers[k] + QString( " or " ) +
189 newNumbers[ell] + QString( "?}" ); 195 newNumbers[ell] + QString( "?}" );
190 } 196 }
191 } 197 }
192 return attempt; 198 return attempt;
193} 199}
194 200
195/* 201/*
196 Augments a MetaTranslator with translations easily derived from 202 Augments a MetaTranslator with translations easily derived from
197 similar existing (probably obsolete) translations. 203 similar existing (probably obsolete) translations.
198 204
199 For example, if "TeX 3.0" is translated as "XeT 3.0" and "TeX 3.1" 205 For example, if "TeX 3.0" is translated as "XeT 3.0" and "TeX 3.1"
200 has no translation, "XeT 3.1" is added to the translator and is 206 has no translation, "XeT 3.1" is added to the translator and is
201 marked Unfinished. 207 marked Unfinished.
202*/ 208*/
203void applyNumberHeuristic( MetaTranslator *tor, bool verbose ) 209void applyNumberHeuristic( MetaTranslator *tor, bool verbose )
204{ 210{
205 TMM translated, untranslated; 211 TMM translated, untranslated;
206 TMM::Iterator t, u; 212 TMM::Iterator t, u;
207 TML all = tor->messages(); 213 TML all = tor->messages();
208 TML::Iterator it; 214 TML::Iterator it;
209 int inserted = 0; 215 int inserted = 0;
210 216
211 for ( it = all.begin(); it != all.end(); ++it ) { 217 for ( it = all.begin(); it != all.end(); ++it ) {
212 if ( (*it).type() == MetaTranslatorMessage::Unfinished ) { 218 if ( (*it).type() == MetaTranslatorMessage::Unfinished ) {
213 if ( (*it).translation().isEmpty() ) 219 if ( (*it).translation().isEmpty() )
214 untranslated.insert( zeroKey((*it).sourceText()), *it ); 220 untranslated.insert(QCString((*it).context()) + "\n" + (*it).sourceText() + "\n"
221 + (*it).comment(), *it);
215 } else if ( !(*it).translation().isEmpty() ) { 222 } else if ( !(*it).translation().isEmpty() ) {
216 translated.insert( zeroKey((*it).sourceText()), *it ); 223 translated.insert( zeroKey((*it).sourceText()), *it );
217 } 224 }
218 } 225 }
219 226
220 for ( u = untranslated.begin(); u != untranslated.end(); ++u ) { 227 for ( u = untranslated.begin(); u != untranslated.end(); ++u ) {
221 t = translated.find( u.key() ); 228 t = translated.find( zeroKey((*u).sourceText()) );
222 if ( t != translated.end() && !t.key().isEmpty() && 229 if ( t != translated.end() && !t.key().isEmpty() &&
223 qstrcmp((*t).sourceText(), (*u).sourceText()) != 0 ) { 230 qstrcmp((*t).sourceText(), (*u).sourceText()) != 0 ) {
224 MetaTranslatorMessage m( *u ); 231 MetaTranslatorMessage m( *u );
225 m.setTranslation( translationAttempt((*t).translation(), 232 m.setTranslation(translationAttempt((*t).translation(), (*t).sourceText(),
226 (*t).sourceText(), 233 (*u).sourceText()));
227 (*u).sourceText()) );
228 tor->insert( m ); 234 tor->insert( m );
229 inserted++; 235 inserted++;
230 } 236 }
231 } 237 }
232 if ( verbose && inserted != 0 ) 238 if ( verbose && inserted != 0 )
233 fprintf( stderr, " number heuristic provided %d translation%s\n", 239 fprintf( stderr, " number heuristic provided %d translation%s\n",
234 inserted, inserted == 1 ? "" : "s" ); 240 inserted, inserted == 1 ? "" : "s" );
235} 241}
diff --git a/development/translation/opie-lupdate/sametexth.cpp b/development/translation/opie-lupdate/sametexth.cpp
index 574cfd5..80909b3 100644
--- a/development/translation/opie-lupdate/sametexth.cpp
+++ b/development/translation/opie-lupdate/sametexth.cpp
@@ -1,84 +1,90 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qt Linguist. 4** This file is part of Qt Linguist.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12** licenses may use this file in accordance with the Qt Commercial License
13** Agreement provided with the Software.
14**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 17**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 18** See http://www.trolltech.com/gpl/ for GPL licensing information.
19** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20** information about Qt Commercial License Agreements.
15** 21**
16** Contact info@trolltech.com if any conditions of this licensing are 22** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 23** not clear to you.
18** 24**
19**********************************************************************/ 25**********************************************************************/
20 26
21#include <metatranslator.h> 27#include <metatranslator.h>
22 28
23#include <qcstring.h> 29#include <qcstring.h>
24#include <qmap.h> 30#include <qmap.h>
25 31
26typedef QMap<QCString, MetaTranslatorMessage> TMM; 32typedef QMap<QCString, MetaTranslatorMessage> TMM;
27typedef QValueList<MetaTranslatorMessage> TML; 33typedef QValueList<MetaTranslatorMessage> TML;
28 34
29/* 35/*
30 Augments a MetaTranslator with trivially derived translations. 36 Augments a MetaTranslator with trivially derived translations.
31 37
32 For example, if "Enabled:" is consistendly translated as "Eingeschaltet:" no 38 For example, if "Enabled:" is consistendly translated as "Eingeschaltet:" no
33 matter the context or the comment, "Eingeschaltet:" is added as the 39 matter the context or the comment, "Eingeschaltet:" is added as the
34 translation of any untranslated "Enabled:" text and is marked Unfinished. 40 translation of any untranslated "Enabled:" text and is marked Unfinished.
35*/ 41*/
36 42
37void applySameTextHeuristic( MetaTranslator *tor, bool verbose ) 43void applySameTextHeuristic( MetaTranslator *tor, bool verbose )
38{ 44{
39 TMM translated; 45 TMM translated;
40 TMM avoid; 46 TMM avoid;
41 TMM::Iterator t; 47 TMM::Iterator t;
42 TML untranslated; 48 TML untranslated;
43 TML::Iterator u; 49 TML::Iterator u;
44 TML all = tor->messages(); 50 TML all = tor->messages();
45 TML::Iterator it; 51 TML::Iterator it;
46 int inserted = 0; 52 int inserted = 0;
47 53
48 for ( it = all.begin(); it != all.end(); ++it ) { 54 for ( it = all.begin(); it != all.end(); ++it ) {
49 if ( (*it).type() == MetaTranslatorMessage::Unfinished ) { 55 if ( (*it).type() == MetaTranslatorMessage::Unfinished ) {
50 if ( (*it).translation().isEmpty() ) 56 if ( (*it).translation().isEmpty() )
51 untranslated.append( *it ); 57 untranslated.append( *it );
52 } else { 58 } else {
53 QCString key = (*it).sourceText(); 59 QCString key = (*it).sourceText();
54 t = translated.find( key ); 60 t = translated.find( key );
55 if ( t != translated.end() ) { 61 if ( t != translated.end() ) {
56 /* 62 /*
57 The same source text is translated at least two 63 The same source text is translated at least two
58 different ways. Do nothing then. 64 different ways. Do nothing then.
59 */ 65 */
60 if ( (*t).translation() != (*it).translation() ) { 66 if ( (*t).translation() != (*it).translation() ) {
61 translated.remove( key ); 67 translated.remove( key );
62 avoid.insert( key, *it ); 68 avoid.insert( key, *it );
63 } 69 }
64 } else if ( !avoid.contains(key) && 70 } else if ( !avoid.contains(key) &&
65 !(*it).translation().isEmpty() ) { 71 !(*it).translation().isEmpty() ) {
66 translated.insert( key, *it ); 72 translated.insert( key, *it );
67 } 73 }
68 } 74 }
69 } 75 }
70 76
71 for ( u = untranslated.begin(); u != untranslated.end(); ++u ) { 77 for ( u = untranslated.begin(); u != untranslated.end(); ++u ) {
72 QCString key = (*u).sourceText(); 78 QCString key = (*u).sourceText();
73 t = translated.find( key ); 79 t = translated.find( key );
74 if ( t != translated.end() ) { 80 if ( t != translated.end() ) {
75 MetaTranslatorMessage m( *u ); 81 MetaTranslatorMessage m( *u );
76 m.setTranslation( (*t).translation() ); 82 m.setTranslation( (*t).translation() );
77 tor->insert( m ); 83 tor->insert( m );
78 inserted++; 84 inserted++;
79 } 85 }
80 } 86 }
81 if ( verbose && inserted != 0 ) 87 if ( verbose && inserted != 0 )
82 fprintf( stderr, " same-text heuristic provided %d translation%s\n", 88 fprintf( stderr, " same-text heuristic provided %d translation%s\n",
83 inserted, inserted == 1 ? "" : "s" ); 89 inserted, inserted == 1 ? "" : "s" );
84} 90}
diff --git a/development/translation/shared/metatranslator.cpp b/development/translation/shared/metatranslator.cpp
index a01e1eb..51270c5 100644
--- a/development/translation/shared/metatranslator.cpp
+++ b/development/translation/shared/metatranslator.cpp
@@ -1,586 +1,596 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qt Linguist. 4** This file is part of Qt Linguist.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12** licenses may use this file in accordance with the Qt Commercial License
13** Agreement provided with the Software.
14**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 17**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 18** See http://www.trolltech.com/gpl/ for GPL licensing information.
19** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20** information about Qt Commercial License Agreements.
15** 21**
16** Contact info@trolltech.com if any conditions of this licensing are 22** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 23** not clear to you.
18** 24**
19**********************************************************************/ 25**********************************************************************/
20 26
21#include "metatranslator.h" 27#include "metatranslator.h"
22 28
23#include <qapplication.h> 29#include <qapplication.h>
24#include <qcstring.h> 30#include <qcstring.h>
25#include <qfile.h> 31#include <qfile.h>
26#include <qmessagebox.h> 32#include <qmessagebox.h>
27#include <qtextcodec.h> 33#include <qtextcodec.h>
28#include <qtextstream.h> 34#include <qtextstream.h>
29#include <qxml.h> 35#include <qxml.h>
30 36
31static bool encodingIsUtf8( const QXmlAttributes& atts ) 37static bool encodingIsUtf8( const QXmlAttributes& atts )
32{ 38{
33 for ( int i = 0; i < atts.length(); i++ ) { 39 for ( int i = 0; i < atts.length(); i++ ) {
34 // utf8="true" is a pre-3.0 syntax 40 // utf8="true" is a pre-3.0 syntax
35 if ( atts.qName(i) == QString("utf8") ) { 41 if ( atts.qName(i) == QString("utf8") ) {
36 return ( atts.value(i) == QString("true") ); 42 return ( atts.value(i) == QString("true") );
37 } else if ( atts.qName(i) == QString("encoding") ) { 43 } else if ( atts.qName(i) == QString("encoding") ) {
38 return ( atts.value(i) == QString("UTF-8") ); 44 return ( atts.value(i) == QString("UTF-8") );
39 } 45 }
40 } 46 }
41 return FALSE; 47 return FALSE;
42} 48}
43 49
44class TsHandler : public QXmlDefaultHandler 50class TsHandler : public QXmlDefaultHandler
45{ 51{
46public: 52public:
47 TsHandler( MetaTranslator *translator ) 53 TsHandler( MetaTranslator *translator )
48 : tor( translator ), type( MetaTranslatorMessage::Finished ), 54 : tor( translator ), type( MetaTranslatorMessage::Finished ),
49 inMessage( FALSE ), ferrorCount( 0 ), contextIsUtf8( FALSE ), 55 inMessage( FALSE ), ferrorCount( 0 ), contextIsUtf8( FALSE ),
50 messageIsUtf8( FALSE ) { } 56 messageIsUtf8( FALSE ) { }
51 57
52 virtual bool startElement( const QString& namespaceURI, 58 virtual bool startElement( const QString& namespaceURI,
53 const QString& localName, const QString& qName, 59 const QString& localName, const QString& qName,
54 const QXmlAttributes& atts ); 60 const QXmlAttributes& atts );
55 virtual bool endElement( const QString& namespaceURI, 61 virtual bool endElement( const QString& namespaceURI,
56 const QString& localName, const QString& qName ); 62 const QString& localName, const QString& qName );
57 virtual bool characters( const QString& ch ); 63 virtual bool characters( const QString& ch );
58 virtual bool fatalError( const QXmlParseException& exception ); 64 virtual bool fatalError( const QXmlParseException& exception );
59 65
60private: 66private:
61 MetaTranslator *tor; 67 MetaTranslator *tor;
62 MetaTranslatorMessage::Type type; 68 MetaTranslatorMessage::Type type;
63 bool inMessage; 69 bool inMessage;
64 QString context; 70 QString context;
65 QString source; 71 QString source;
66 QString comment; 72 QString comment;
67 QString translation; 73 QString translation;
68 74
69 QString accum; 75 QString accum;
70 int ferrorCount; 76 int ferrorCount;
71 bool contextIsUtf8; 77 bool contextIsUtf8;
72 bool messageIsUtf8; 78 bool messageIsUtf8;
73}; 79};
74 80
75bool TsHandler::startElement( const QString& /* namespaceURI */, 81bool TsHandler::startElement( const QString& /* namespaceURI */,
76 const QString& /* localName */, 82 const QString& /* localName */,
77 const QString& qName, 83 const QString& qName,
78 const QXmlAttributes& atts ) 84 const QXmlAttributes& atts )
79{ 85{
80 if ( qName == QString("byte") ) { 86 if ( qName == QString("byte") ) {
81 for ( int i = 0; i < atts.length(); i++ ) { 87 for ( int i = 0; i < atts.length(); i++ ) {
82 if ( atts.qName(i) == QString("value") ) { 88 if ( atts.qName(i) == QString("value") ) {
83 QString value = atts.value( i ); 89 QString value = atts.value( i );
84 int base = 10; 90 int base = 10;
85 if ( value.startsWith("x") ) { 91 if ( value.startsWith("x") ) {
86 base = 16; 92 base = 16;
87 value = value.mid( 1 ); 93 value = value.mid( 1 );
88 } 94 }
89 int n = value.toUInt( 0, base ); 95 int n = value.toUInt( 0, base );
90 if ( n != 0 ) 96 if ( n != 0 )
91 accum += QChar( n ); 97 accum += QChar( n );
92 } 98 }
93 } 99 }
94 } else { 100 } else {
95 if ( qName == QString("context") ) { 101 if ( qName == QString("context") ) {
96 context.truncate( 0 ); 102 context.truncate( 0 );
97 source.truncate( 0 ); 103 source.truncate( 0 );
98 comment.truncate( 0 ); 104 comment.truncate( 0 );
99 translation.truncate( 0 ); 105 translation.truncate( 0 );
100 contextIsUtf8 = encodingIsUtf8( atts ); 106 contextIsUtf8 = encodingIsUtf8( atts );
101 } else if ( qName == QString("message") ) { 107 } else if ( qName == QString("message") ) {
102 inMessage = TRUE; 108 inMessage = TRUE;
103 type = MetaTranslatorMessage::Finished; 109 type = MetaTranslatorMessage::Finished;
104 source.truncate( 0 ); 110 source.truncate( 0 );
105 comment.truncate( 0 ); 111 comment.truncate( 0 );
106 translation.truncate( 0 ); 112 translation.truncate( 0 );
107 messageIsUtf8 = encodingIsUtf8( atts ); 113 messageIsUtf8 = encodingIsUtf8( atts );
108 } else if ( qName == QString("translation") ) { 114 } else if ( qName == QString("translation") ) {
109 for ( int i = 0; i < atts.length(); i++ ) { 115 for ( int i = 0; i < atts.length(); i++ ) {
110 if ( atts.qName(i) == QString("type") ) { 116 if ( atts.qName(i) == QString("type") ) {
111 if ( atts.value(i) == QString("unfinished") ) 117 if ( atts.value(i) == QString("unfinished") )
112 type = MetaTranslatorMessage::Unfinished; 118 type = MetaTranslatorMessage::Unfinished;
113 else if ( atts.value(i) == QString("obsolete") ) 119 else if ( atts.value(i) == QString("obsolete") )
114 type = MetaTranslatorMessage::Obsolete; 120 type = MetaTranslatorMessage::Obsolete;
115 else 121 else
116 type = MetaTranslatorMessage::Finished; 122 type = MetaTranslatorMessage::Finished;
117 } 123 }
118 } 124 }
119 } 125 }
120 accum.truncate( 0 ); 126 accum.truncate( 0 );
121 } 127 }
122 return TRUE; 128 return TRUE;
123} 129}
124 130
125bool TsHandler::endElement( const QString& /* namespaceURI */, 131bool TsHandler::endElement( const QString& /* namespaceURI */,
126 const QString& /* localName */, 132 const QString& /* localName */,
127 const QString& qName ) 133 const QString& qName )
128{ 134{
129 if ( qName == QString("codec") || qName == QString("defaultcodec") ) { 135 if ( qName == QString("codec") || qName == QString("defaultcodec") ) {
130 // "codec" is a pre-3.0 syntax 136 // "codec" is a pre-3.0 syntax
131 tor->setCodec( accum ); 137 tor->setCodec( accum );
132 } else if ( qName == QString("name") ) { 138 } else if ( qName == QString("name") ) {
133 context = accum; 139 context = accum;
134 } else if ( qName == QString("source") ) { 140 } else if ( qName == QString("source") ) {
135 source = accum; 141 source = accum;
136 } else if ( qName == QString("comment") ) { 142 } else if ( qName == QString("comment") ) {
137 if ( inMessage ) { 143 if ( inMessage ) {
138 comment = accum; 144 comment = accum;
139 } else { 145 } else {
140 if ( contextIsUtf8 ) 146 if ( contextIsUtf8 )
141 tor->insert( MetaTranslatorMessage(context.utf8(), "", 147 tor->insert( MetaTranslatorMessage(context.utf8(),
148 ContextComment,
142 accum.utf8(), QString::null, TRUE, 149 accum.utf8(), QString::null, TRUE,
143 MetaTranslatorMessage::Unfinished) ); 150 MetaTranslatorMessage::Unfinished) );
144 else 151 else
145 tor->insert( MetaTranslatorMessage(context.ascii(), "", 152 tor->insert( MetaTranslatorMessage(context.ascii(),
153 ContextComment,
146 accum.ascii(), QString::null, FALSE, 154 accum.ascii(), QString::null, FALSE,
147 MetaTranslatorMessage::Unfinished) ); 155 MetaTranslatorMessage::Unfinished) );
148 } 156 }
149 } else if ( qName == QString("translation") ) { 157 } else if ( qName == QString("translation") ) {
150 translation = accum; 158 translation = accum;
151 } else if ( qName == QString("message") ) { 159 } else if ( qName == QString("message") ) {
152 if ( messageIsUtf8 ) 160 if ( messageIsUtf8 )
153 tor->insert( MetaTranslatorMessage(context.utf8(), source.utf8(), 161 tor->insert( MetaTranslatorMessage(context.utf8(), source.utf8(),
154 comment.utf8(), translation, 162 comment.utf8(), translation,
155 TRUE, type) ); 163 TRUE, type) );
156 else 164 else
157 tor->insert( MetaTranslatorMessage(context.ascii(), source.ascii(), 165 tor->insert( MetaTranslatorMessage(context.ascii(), source.ascii(),
158 comment.ascii(), translation, 166 comment.ascii(), translation,
159 FALSE, type) ); 167 FALSE, type) );
160 inMessage = FALSE; 168 inMessage = FALSE;
161 } 169 }
162 return TRUE; 170 return TRUE;
163} 171}
164 172
165bool TsHandler::characters( const QString& ch ) 173bool TsHandler::characters( const QString& ch )
166{ 174{
167 QString t = ch; 175 QString t = ch;
168 t.replace( "\r", "" ); 176 t.replace( "\r", "" );
169 accum += t; 177 accum += t;
170 return TRUE; 178 return TRUE;
171} 179}
172 180
173bool TsHandler::fatalError( const QXmlParseException& exception ) 181bool TsHandler::fatalError( const QXmlParseException& exception )
174{ 182{
175 if ( ferrorCount++ == 0 ) { 183 if ( ferrorCount++ == 0 ) {
176 QString msg; 184 QString msg;
177 msg.sprintf( "Parse error at line %d, column %d (%s).", 185 msg.sprintf( "Parse error at line %d, column %d (%s).",
178 exception.lineNumber(), exception.columnNumber(), 186 exception.lineNumber(), exception.columnNumber(),
179 exception.message().latin1() ); 187 exception.message().latin1() );
180 if ( qApp == 0 ) 188 if ( qApp == 0 )
181 fprintf( stderr, "XML error: %s\n", msg.latin1() ); 189 fprintf( stderr, "XML error: %s\n", msg.latin1() );
182 else 190 else
183 QMessageBox::information( qApp->mainWidget(), 191 QMessageBox::information( qApp->mainWidget(),
184 QObject::tr("Qt Linguist"), msg ); 192 QObject::tr("Qt Linguist"), msg );
185 } 193 }
186 return FALSE; 194 return FALSE;
187} 195}
188 196
189static QString numericEntity( int ch ) 197static QString numericEntity( int ch )
190{ 198{
191 return QString( ch <= 0x20 ? "<byte value=\"x%1\"/>" : "&#x%1;" ) 199 return QString( ch <= 0x20 ? "<byte value=\"x%1\"/>" : "&#x%1;" )
192 .arg( ch, 0, 16 ); 200 .arg( ch, 0, 16 );
193} 201}
194 202
195static QString protect( const QCString& str ) 203static QString protect( const QCString& str )
196{ 204{
197 QString result; 205 QString result;
198 int len = (int) str.length(); 206 int len = (int) str.length();
199 for ( int k = 0; k < len; k++ ) { 207 for ( int k = 0; k < len; k++ ) {
200 switch( str[k] ) { 208 switch( str[k] ) {
201 case '\"': 209 case '\"':
202 result += QString( "&quot;" ); 210 result += QString( "&quot;" );
203 break; 211 break;
204 case '&': 212 case '&':
205 result += QString( "&amp;" ); 213 result += QString( "&amp;" );
206 break; 214 break;
207 case '>': 215 case '>':
208 result += QString( "&gt;" ); 216 result += QString( "&gt;" );
209 break; 217 break;
210 case '<': 218 case '<':
211 result += QString( "&lt;" ); 219 result += QString( "&lt;" );
212 break; 220 break;
213 case '\'': 221 case '\'':
214 result += QString( "&apos;" ); 222 result += QString( "&apos;" );
215 break; 223 break;
216 default: 224 default:
217 if ( (uchar) str[k] < 0x20 && str[k] != '\n' ) 225 if ( (uchar) str[k] < 0x20 && str[k] != '\n' )
218 result += numericEntity( (uchar) str[k] ); 226 result += numericEntity( (uchar) str[k] );
219 else 227 else
220 result += str[k]; 228 result += str[k];
221 } 229 }
222 } 230 }
223 return result; 231 return result;
224} 232}
225 233
226static QString evilBytes( const QCString& str, bool utf8 ) 234static QString evilBytes( const QCString& str, bool utf8 )
227{ 235{
228 if ( utf8 ) { 236 if ( utf8 ) {
229 return protect( str ); 237 return protect( str );
230 } else { 238 } else {
231 QString result; 239 QString result;
232 QCString t = protect( str ).latin1(); 240 QCString t = protect( str ).latin1();
233 int len = (int) t.length(); 241 int len = (int) t.length();
234 for ( int k = 0; k < len; k++ ) { 242 for ( int k = 0; k < len; k++ ) {
235 if ( (uchar) t[k] >= 0x7f ) 243 if ( (uchar) t[k] >= 0x7f )
236 result += numericEntity( (uchar) t[k] ); 244 result += numericEntity( (uchar) t[k] );
237 else 245 else
238 result += QChar( t[k] ); 246 result += QChar( t[k] );
239 } 247 }
240 return result; 248 return result;
241 } 249 }
242} 250}
243 251
244MetaTranslatorMessage::MetaTranslatorMessage() 252MetaTranslatorMessage::MetaTranslatorMessage()
245 : utfeight( FALSE ), ty( Unfinished ) 253 : utfeight( FALSE ), ty( Unfinished )
246{ 254{
247} 255}
248 256
249MetaTranslatorMessage::MetaTranslatorMessage( const char *context, 257MetaTranslatorMessage::MetaTranslatorMessage( const char *context,
250 const char *sourceText, 258 const char *sourceText,
251 const char *comment, 259 const char *comment,
252 const QString& translation, 260 const QString& translation,
253 bool utf8, Type type ) 261 bool utf8, Type type )
254 : QTranslatorMessage( context, sourceText, comment, translation ), 262 : QTranslatorMessage( context, sourceText, comment, translation ),
255 utfeight( FALSE ), ty( type ) 263 utfeight( FALSE ), ty( type )
256{ 264{
257 /* 265 /*
258 Don't use UTF-8 if it makes no difference. UTF-8 should be 266 Don't use UTF-8 if it makes no difference. UTF-8 should be
259 reserved for the real problematic case: non-ASCII (possibly 267 reserved for the real problematic case: non-ASCII (possibly
260 non-Latin-1) characters in .ui files. 268 non-Latin-1) characters in .ui files.
261 */ 269 */
262 if ( utf8 ) { 270 if ( utf8 ) {
263 if ( sourceText != 0 ) { 271 if ( sourceText != 0 ) {
264 int i = 0; 272 int i = 0;
265 while ( sourceText[i] != '\0' ) { 273 while ( sourceText[i] != '\0' ) {
266 if ( (uchar) sourceText[i] >= 0x80 ) { 274 if ( (uchar) sourceText[i] >= 0x80 ) {
267 utfeight = TRUE; 275 utfeight = TRUE;
268 break; 276 break;
269 } 277 }
270 i++; 278 i++;
271 } 279 }
272 } 280 }
273 if ( !utfeight && comment != 0 ) { 281 if ( !utfeight && comment != 0 ) {
274 int i = 0; 282 int i = 0;
275 while ( comment[i] != '\0' ) { 283 while ( comment[i] != '\0' ) {
276 if ( (uchar) comment[i] >= 0x80 ) { 284 if ( (uchar) comment[i] >= 0x80 ) {
277 utfeight = TRUE; 285 utfeight = TRUE;
278 break; 286 break;
279 } 287 }
280 i++; 288 i++;
281 } 289 }
282 } 290 }
283 } 291 }
284} 292}
285 293
286MetaTranslatorMessage::MetaTranslatorMessage( const MetaTranslatorMessage& m ) 294MetaTranslatorMessage::MetaTranslatorMessage( const MetaTranslatorMessage& m )
287 : QTranslatorMessage( m ), utfeight( m.utfeight ), ty( m.ty ) 295 : QTranslatorMessage( m ), utfeight( m.utfeight ), ty( m.ty )
288{ 296{
289} 297}
290 298
291MetaTranslatorMessage& MetaTranslatorMessage::operator=( 299MetaTranslatorMessage& MetaTranslatorMessage::operator=(
292 const MetaTranslatorMessage& m ) 300 const MetaTranslatorMessage& m )
293{ 301{
294 QTranslatorMessage::operator=( m ); 302 QTranslatorMessage::operator=( m );
295 utfeight = m.utfeight; 303 utfeight = m.utfeight;
296 ty = m.ty; 304 ty = m.ty;
297 return *this; 305 return *this;
298} 306}
299 307
300bool MetaTranslatorMessage::operator==( const MetaTranslatorMessage& m ) const 308bool MetaTranslatorMessage::operator==( const MetaTranslatorMessage& m ) const
301{ 309{
302 return qstrcmp( context(), m.context() ) == 0 && 310 return qstrcmp( context(), m.context() ) == 0 &&
303 qstrcmp( sourceText(), m.sourceText() ) == 0 && 311 qstrcmp( sourceText(), m.sourceText() ) == 0 &&
304 qstrcmp( comment(), m.comment() ) == 0; 312 qstrcmp( comment(), m.comment() ) == 0;
305} 313}
306 314
307bool MetaTranslatorMessage::operator<( const MetaTranslatorMessage& m ) const 315bool MetaTranslatorMessage::operator<( const MetaTranslatorMessage& m ) const
308{ 316{
309 int delta = qstrcmp( context(), m.context() ); 317 int delta = qstrcmp( context(), m.context() );
310 if ( delta == 0 ) 318 if ( delta == 0 )
311 delta = qstrcmp( sourceText(), m.sourceText() ); 319 delta = qstrcmp( sourceText(), m.sourceText() );
312 if ( delta == 0 ) 320 if ( delta == 0 )
313 delta = qstrcmp( comment(), m.comment() ); 321 delta = qstrcmp( comment(), m.comment() );
314 return delta < 0; 322 return delta < 0;
315} 323}
316 324
317MetaTranslator::MetaTranslator() 325MetaTranslator::MetaTranslator()
318 : codecName( "ISO-8859-1" ), codec( 0 )
319{ 326{
327 clear();
320} 328}
321 329
322MetaTranslator::MetaTranslator( const MetaTranslator& tor ) 330MetaTranslator::MetaTranslator( const MetaTranslator& tor )
323 : mm( tor.mm ), codecName( tor.codecName ), codec( tor.codec ) 331 : mm( tor.mm ), codecName( tor.codecName ), codec( tor.codec )
324{ 332{
325
326} 333}
327 334
328MetaTranslator& MetaTranslator::operator=( const MetaTranslator& tor ) 335MetaTranslator& MetaTranslator::operator=( const MetaTranslator& tor )
329{ 336{
330 mm = tor.mm; 337 mm = tor.mm;
331 codecName = tor.codecName; 338 codecName = tor.codecName;
332 codec = tor.codec; 339 codec = tor.codec;
333 return *this; 340 return *this;
334} 341}
335 342
336bool MetaTranslator::load( const QString& filename ) 343void MetaTranslator::clear()
337{ 344{
338 mm.clear(); 345 mm.clear();
346 codecName = "ISO-8859-1";
347 codec = 0;
348}
339 349
350bool MetaTranslator::load( const QString& filename )
351{
340 QFile f( filename ); 352 QFile f( filename );
341 if ( !f.open(IO_ReadOnly) ) 353 if ( !f.open(IO_ReadOnly) )
342 return FALSE; 354 return FALSE;
343 355
344 QTextStream t( &f ); 356 QTextStream t( &f );
345 QXmlInputSource in( t ); 357 QXmlInputSource in( t );
346 QXmlSimpleReader reader; 358 QXmlSimpleReader reader;
347 // don't click on these!
348 reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE ); 359 reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE );
349 reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE ); 360 reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE );
350 reader.setFeature( "http://trolltech.com/xml/features/report-whitespace" 361 reader.setFeature( "http://trolltech.com/xml/features/report-whitespace"
351 "-only-CharData", FALSE ); 362 "-only-CharData", FALSE );
352 QXmlDefaultHandler *hand = new TsHandler( this ); 363 QXmlDefaultHandler *hand = new TsHandler( this );
353 reader.setContentHandler( hand ); 364 reader.setContentHandler( hand );
354 reader.setErrorHandler( hand ); 365 reader.setErrorHandler( hand );
355 366
356 bool ok = reader.parse( in ); 367 bool ok = reader.parse( in );
357 reader.setContentHandler( 0 ); 368 reader.setContentHandler( 0 );
358 reader.setErrorHandler( 0 ); 369 reader.setErrorHandler( 0 );
359 delete hand; 370 delete hand;
360 f.close(); 371 f.close();
361 if ( !ok )
362 mm.clear();
363 return ok; 372 return ok;
364} 373}
365 374
366bool MetaTranslator::save( const QString& filename ) const 375bool MetaTranslator::save( const QString& filename ) const
367{ 376{
368 QFile f( filename ); 377 QFile f( filename );
369 if ( !f.open(IO_WriteOnly) ) 378 if ( !f.open(IO_WriteOnly) )
370 return FALSE; 379 return FALSE;
371 380
372 QTextStream t( &f ); 381 QTextStream t( &f );
373 t.setCodec( QTextCodec::codecForName("ISO-8859-1") ); 382 t.setCodec( QTextCodec::codecForName("ISO-8859-1") );
374 383
375 t << "<!DOCTYPE TS><TS>\n"; 384 t << "<!DOCTYPE TS><TS>\n";
376 if ( codecName != "ISO-8859-1" ) 385 if ( codecName != "ISO-8859-1" )
377 t << "<defaultcodec>" << codecName << "</defaultcodec>\n"; 386 t << "<defaultcodec>" << codecName << "</defaultcodec>\n";
378 TMM::ConstIterator m = mm.begin(); 387 TMM::ConstIterator m = mm.begin();
379 while ( m != mm.end() ) { 388 while ( m != mm.end() ) {
380 TMMInv inv; 389 TMMInv inv;
381 TMMInv::Iterator i; 390 TMMInv::Iterator i;
382 bool contextIsUtf8 = m.key().utf8(); 391 bool contextIsUtf8 = m.key().utf8();
383 QCString context = m.key().context(); 392 QCString context = m.key().context();
384 QCString comment = ""; 393 QCString comment = "";
385 394
386 do { 395 do {
387 if ( QCString(m.key().sourceText()).isEmpty() ) { 396 if ( QCString(m.key().sourceText()) == ContextComment ) {
388 if ( m.key().type() != MetaTranslatorMessage::Obsolete ) { 397 if ( m.key().type() != MetaTranslatorMessage::Obsolete ) {
389 contextIsUtf8 = m.key().utf8(); 398 contextIsUtf8 = m.key().utf8();
390 comment = QCString( m.key().comment() ); 399 comment = QCString( m.key().comment() );
391 } 400 }
392 } else { 401 } else {
393 inv.insert( *m, m.key() ); 402 inv.insert( *m, m.key() );
394 } 403 }
395 } while ( ++m != mm.end() && QCString(m.key().context()) == context ); 404 } while ( ++m != mm.end() && QCString(m.key().context()) == context );
396 405
397 t << "<context"; 406 t << "<context";
398 if ( contextIsUtf8 ) 407 if ( contextIsUtf8 )
399 t << " encoding=\"UTF-8\""; 408 t << " encoding=\"UTF-8\"";
400 t << ">\n"; 409 t << ">\n";
401 t << " <name>" << evilBytes( context, contextIsUtf8 ) 410 t << " <name>" << evilBytes( context, contextIsUtf8 )
402 << "</name>\n"; 411 << "</name>\n";
403 if ( !comment.isEmpty() ) 412 if ( !comment.isEmpty() )
404 t << " <comment>" << evilBytes( comment, contextIsUtf8 ) 413 t << " <comment>" << evilBytes( comment, contextIsUtf8 )
405 << "</comment>\n"; 414 << "</comment>\n";
406 415
407 for ( i = inv.begin(); i != inv.end(); ++i ) { 416 for ( i = inv.begin(); i != inv.end(); ++i ) {
408 // no need for such noise 417 // no need for such noise
409 if ( (*i).type() == MetaTranslatorMessage::Obsolete && 418 if ( (*i).type() == MetaTranslatorMessage::Obsolete &&
410 (*i).translation().isEmpty() ) 419 (*i).translation().isEmpty() )
411 continue; 420 continue;
412 421
413 t << " <message"; 422 t << " <message";
414 if ( (*i).utf8() ) 423 if ( (*i).utf8() )
415 t << " encoding=\"UTF-8\""; 424 t << " encoding=\"UTF-8\"";
416 t << ">\n" 425 t << ">\n"
417 << " <source>" << evilBytes( (*i).sourceText(), 426 << " <source>" << evilBytes( (*i).sourceText(),
418 (*i).utf8() ) 427 (*i).utf8() )
419 << "</source>\n"; 428 << "</source>\n";
420 if ( !QCString((*i).comment()).isEmpty() ) 429 if ( !QCString((*i).comment()).isEmpty() )
421 t << " <comment>" << evilBytes( (*i).comment(), 430 t << " <comment>" << evilBytes( (*i).comment(),
422 (*i).utf8() ) 431 (*i).utf8() )
423 << "</comment>\n"; 432 << "</comment>\n";
424 t << " <translation"; 433 t << " <translation";
425 if ( (*i).type() == MetaTranslatorMessage::Unfinished ) 434 if ( (*i).type() == MetaTranslatorMessage::Unfinished )
426 t << " type=\"unfinished\""; 435 t << " type=\"unfinished\"";
427 else if ( (*i).type() == MetaTranslatorMessage::Obsolete ) 436 else if ( (*i).type() == MetaTranslatorMessage::Obsolete )
428 t << " type=\"obsolete\""; 437 t << " type=\"obsolete\"";
429 t << ">" << protect( (*i).translation().utf8() ) 438 t << ">" << protect( (*i).translation().utf8() )
430 << "</translation>\n"; 439 << "</translation>\n";
431 t << " </message>\n"; 440 t << " </message>\n";
432 } 441 }
433 t << "</context>\n"; 442 t << "</context>\n";
434 } 443 }
435 t << "</TS>\n"; 444 t << "</TS>\n";
436 f.close(); 445 f.close();
437 return TRUE; 446 return TRUE;
438} 447}
439 448
440bool MetaTranslator::release( const QString& filename, bool verbose ) const 449bool MetaTranslator::release( const QString& filename, bool verbose,
450 QTranslator::SaveMode mode ) const
441{ 451{
442 QTranslator tor( 0 ); 452 QTranslator tor( 0 );
443 int finished = 0; 453 int finished = 0;
444 int unfinished = 0; 454 int unfinished = 0;
445 int untranslated = 0; 455 int untranslated = 0;
446 TMM::ConstIterator m; 456 TMM::ConstIterator m;
447 457
448 for ( m = mm.begin(); m != mm.end(); ++m ) { 458 for ( m = mm.begin(); m != mm.end(); ++m ) {
449 if ( m.key().type() != MetaTranslatorMessage::Obsolete ) { 459 if ( m.key().type() != MetaTranslatorMessage::Obsolete ) {
450 if ( m.key().translation().isEmpty() ) { 460 if ( m.key().translation().isEmpty() ) {
451 untranslated++; 461 untranslated++;
452 } else { 462 } else {
453 if ( m.key().type() == MetaTranslatorMessage::Unfinished ) 463 if ( m.key().type() == MetaTranslatorMessage::Unfinished )
454 unfinished++; 464 unfinished++;
455 else 465 else
456 finished++; 466 finished++;
457 467
458 QCString context = m.key().context(); 468 QCString context = m.key().context();
459 QCString sourceText = m.key().sourceText(); 469 QCString sourceText = m.key().sourceText();
460 QCString comment = m.key().comment(); 470 QCString comment = m.key().comment();
461 QString translation = m.key().translation(); 471 QString translation = m.key().translation();
462 472
463 /* 473 /*
464 Drop the comment in (context, sourceText, comment), 474 Drop the comment in (context, sourceText, comment),
465 unless (context, sourceText, "") already exists, or 475 unless (context, sourceText, "") already exists, or
466 unless we already dropped the comment of (context, 476 unless we already dropped the comment of (context,
467 sourceText, comment0). 477 sourceText, comment0).
468 */ 478 */
469 if ( comment.isEmpty() 479 if ( comment.isEmpty()
470 || contains(context, sourceText, "") 480 || contains(context, sourceText, "")
471 || !tor.findMessage(context, sourceText, "").translation() 481 || !tor.findMessage(context, sourceText, "").translation()
472 .isNull() ) { 482 .isNull() ) {
473 tor.insert( m.key() ); 483 tor.insert( m.key() );
474 } else { 484 } else {
475 tor.insert( QTranslatorMessage(context, sourceText, "", 485 tor.insert( QTranslatorMessage(context, sourceText, "",
476 translation) ); 486 translation) );
477 } 487 }
478 } 488 }
479 } 489 }
480 } 490 }
481 491
482 bool saved = tor.save( filename, QTranslator::Stripped ); 492 bool saved = tor.save( filename, mode );
483 if ( saved && verbose ) 493 if ( saved && verbose )
484 fprintf( stderr, 494 fprintf( stderr,
485 " %d finished, %d unfinished and %d untranslated messages\n", 495 " %d finished, %d unfinished and %d untranslated messages\n",
486 finished, unfinished, untranslated ); 496 finished, unfinished, untranslated );
487 497
488 return saved; 498 return saved;
489} 499}
490 500
491bool MetaTranslator::contains( const char *context, const char *sourceText, 501bool MetaTranslator::contains( const char *context, const char *sourceText,
492 const char *comment ) const 502 const char *comment ) const
493{ 503{
494 return mm.find( MetaTranslatorMessage(context, sourceText, comment) ) != 504 return mm.find( MetaTranslatorMessage(context, sourceText, comment) ) !=
495 mm.end(); 505 mm.end();
496} 506}
497 507
498void MetaTranslator::insert( const MetaTranslatorMessage& m ) 508void MetaTranslator::insert( const MetaTranslatorMessage& m )
499{ 509{
500 int pos = mm.count(); 510 int pos = mm.count();
501 TMM::Iterator n = mm.find( m ); 511 TMM::Iterator n = mm.find( m );
502 if ( n != mm.end() ) 512 if ( n != mm.end() )
503 pos = *n; 513 pos = *n;
504 mm.replace( m, pos ); 514 mm.replace( m, pos );
505} 515}
506 516
507void MetaTranslator::stripObsoleteMessages() 517void MetaTranslator::stripObsoleteMessages()
508{ 518{
509 TMM newmm; 519 TMM newmm;
510 520
511 TMM::Iterator m = mm.begin(); 521 TMM::Iterator m = mm.begin();
512 while ( m != mm.end() ) { 522 while ( m != mm.end() ) {
513 if ( m.key().type() != MetaTranslatorMessage::Obsolete ) 523 if ( m.key().type() != MetaTranslatorMessage::Obsolete )
514 newmm.insert( m.key(), *m ); 524 newmm.insert( m.key(), *m );
515 ++m; 525 ++m;
516 } 526 }
517 mm = newmm; 527 mm = newmm;
518} 528}
519 529
520void MetaTranslator::stripEmptyContexts() 530void MetaTranslator::stripEmptyContexts()
521{ 531{
522 TMM newmm; 532 TMM newmm;
523 533
524 TMM::Iterator m = mm.begin(); 534 TMM::Iterator m = mm.begin();
525 while ( m != mm.end() ) { 535 while ( m != mm.end() ) {
526 if ( QCString(m.key().sourceText()).isEmpty() ) { 536 if ( QCString(m.key().sourceText()) == ContextComment ) {
527 TMM::Iterator n = m; 537 TMM::Iterator n = m;
528 ++n; 538 ++n;
529 // the context comment is followed by other messages 539 // the context comment is followed by other messages
530 if ( n != newmm.end() && 540 if ( n != newmm.end() &&
531 qstrcmp(m.key().context(), n.key().context()) == 0 ) 541 qstrcmp(m.key().context(), n.key().context()) == 0 )
532 newmm.insert( m.key(), *m ); 542 newmm.insert( m.key(), *m );
533 } else { 543 } else {
534 newmm.insert( m.key(), *m ); 544 newmm.insert( m.key(), *m );
535 } 545 }
536 ++m; 546 ++m;
537 } 547 }
538 mm = newmm; 548 mm = newmm;
539} 549}
540 550
541void MetaTranslator::setCodec( const char *name ) 551void MetaTranslator::setCodec( const char *name )
542{ 552{
543 const int latin1 = 4; 553 const int latin1 = 4;
544 554
545 codecName = name; 555 codecName = name;
546 codec = QTextCodec::codecForName( name ); 556 codec = QTextCodec::codecForName( name );
547 if ( codec == 0 || codec->mibEnum() == latin1 ) 557 if ( codec == 0 || codec->mibEnum() == latin1 )
548 codec = 0; 558 codec = 0;
549} 559}
550 560
551QString MetaTranslator::toUnicode( const char *str, bool utf8 ) const 561QString MetaTranslator::toUnicode( const char *str, bool utf8 ) const
552{ 562{
553 if ( utf8 ) 563 if ( utf8 )
554 return QString::fromUtf8( str ); 564 return QString::fromUtf8( str );
555 else if ( codec == 0 ) 565 else if ( codec == 0 )
556 return QString( str ); 566 return QString( str );
557 else 567 else
558 return codec->toUnicode( str ); 568 return codec->toUnicode( str );
559} 569}
560 570
561QValueList<MetaTranslatorMessage> MetaTranslator::messages() const 571QValueList<MetaTranslatorMessage> MetaTranslator::messages() const
562{ 572{
563 int n = mm.count(); 573 int n = mm.count();
564 TMM::ConstIterator *t = new TMM::ConstIterator[n + 1]; 574 TMM::ConstIterator *t = new TMM::ConstIterator[n + 1];
565 TMM::ConstIterator m; 575 TMM::ConstIterator m;
566 for ( m = mm.begin(); m != mm.end(); ++m ) 576 for ( m = mm.begin(); m != mm.end(); ++m )
567 t[*m] = m; 577 t[*m] = m;
568 578
569 QValueList<MetaTranslatorMessage> val; 579 QValueList<MetaTranslatorMessage> val;
570 for ( int i = 0; i < n; i++ ) 580 for ( int i = 0; i < n; i++ )
571 val.append( t[i].key() ); 581 val.append( t[i].key() );
572 582
573 delete[] t; 583 delete[] t;
574 return val; 584 return val;
575} 585}
576 586
577QValueList<MetaTranslatorMessage> MetaTranslator::translatedMessages() const 587QValueList<MetaTranslatorMessage> MetaTranslator::translatedMessages() const
578{ 588{
579 QValueList<MetaTranslatorMessage> val; 589 QValueList<MetaTranslatorMessage> val;
580 TMM::ConstIterator m; 590 TMM::ConstIterator m;
581 for ( m = mm.begin(); m != mm.end(); ++m ) { 591 for ( m = mm.begin(); m != mm.end(); ++m ) {
582 if ( m.key().type() == MetaTranslatorMessage::Finished ) 592 if ( m.key().type() == MetaTranslatorMessage::Finished )
583 val.append( m.key() ); 593 val.append( m.key() );
584 } 594 }
585 return val; 595 return val;
586} 596}
diff --git a/development/translation/shared/metatranslator.h b/development/translation/shared/metatranslator.h
index d35b202..a13f462 100644
--- a/development/translation/shared/metatranslator.h
+++ b/development/translation/shared/metatranslator.h
@@ -1,99 +1,113 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qt Linguist. 4** This file is part of Qt Linguist.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12** licenses may use this file in accordance with the Qt Commercial License
13** Agreement provided with the Software.
14**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 17**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 18** See http://www.trolltech.com/gpl/ for GPL licensing information.
19** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20** information about Qt Commercial License Agreements.
15** 21**
16** Contact info@trolltech.com if any conditions of this licensing are 22** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 23** not clear to you.
18** 24**
19**********************************************************************/ 25**********************************************************************/
20 26
21#ifndef METATRANSLATOR_H 27#ifndef METATRANSLATOR_H
22#define METATRANSLATOR_H 28#define METATRANSLATOR_H
23 29
24#include <qmap.h> 30#include <qmap.h>
25#include <qstring.h> 31#include <qstring.h>
26#include <qtranslator.h> 32#include <qtranslator.h>
27#include <qvaluelist.h> 33#include <qvaluelist.h>
28 34
29class QTextCodec; 35class QTextCodec;
30 36
31class MetaTranslatorMessage : public QTranslatorMessage 37class MetaTranslatorMessage : public QTranslatorMessage
32{ 38{
33public: 39public:
34 enum Type { Unfinished, Finished, Obsolete }; 40 enum Type { Unfinished, Finished, Obsolete };
35 41
36 MetaTranslatorMessage(); 42 MetaTranslatorMessage();
37 MetaTranslatorMessage( const char *context, const char *sourceText, 43 MetaTranslatorMessage( const char *context, const char *sourceText,
38 const char *comment, 44 const char *comment,
39 const QString& translation = QString::null, 45 const QString& translation = QString::null,
40 bool utf8 = FALSE, Type type = Unfinished ); 46 bool utf8 = FALSE, Type type = Unfinished );
41 MetaTranslatorMessage( const MetaTranslatorMessage& m ); 47 MetaTranslatorMessage( const MetaTranslatorMessage& m );
42 48
43 MetaTranslatorMessage& operator=( const MetaTranslatorMessage& m ); 49 MetaTranslatorMessage& operator=( const MetaTranslatorMessage& m );
44 50
45 void setType( Type nt ) { ty = nt; } 51 void setType( Type nt ) { ty = nt; }
46 Type type() const { return ty; } 52 Type type() const { return ty; }
47 bool utf8() const { return utfeight; } 53 bool utf8() const { return utfeight; }
48 54
49 bool operator==( const MetaTranslatorMessage& m ) const; 55 bool operator==( const MetaTranslatorMessage& m ) const;
50 bool operator!=( const MetaTranslatorMessage& m ) const 56 bool operator!=( const MetaTranslatorMessage& m ) const
51 { return !operator==( m ); } 57 { return !operator==( m ); }
52 bool operator<( const MetaTranslatorMessage& m ) const; 58 bool operator<( const MetaTranslatorMessage& m ) const;
53 bool operator<=( const MetaTranslatorMessage& m ) 59 bool operator<=( const MetaTranslatorMessage& m )
54 { return !operator>( m ); } 60 { return !operator>( m ); }
55 bool operator>( const MetaTranslatorMessage& m ) const 61 bool operator>( const MetaTranslatorMessage& m ) const
56 { return this->operator<( m ); } 62 { return this->operator<( m ); }
57 bool operator>=( const MetaTranslatorMessage& m ) const 63 bool operator>=( const MetaTranslatorMessage& m ) const
58 { return !operator<( m ); } 64 { return !operator<( m ); }
59 65
60private: 66private:
61 bool utfeight; 67 bool utfeight;
62 Type ty; 68 Type ty;
63}; 69};
64 70
65class MetaTranslator 71class MetaTranslator
66{ 72{
67public: 73public:
68 MetaTranslator(); 74 MetaTranslator();
69 MetaTranslator( const MetaTranslator& tor ); 75 MetaTranslator( const MetaTranslator& tor );
70 76
71 MetaTranslator& operator=( const MetaTranslator& tor ); 77 MetaTranslator& operator=( const MetaTranslator& tor );
72 78
79 void clear();
73 bool load( const QString& filename ); 80 bool load( const QString& filename );
74 bool save( const QString& filename ) const; 81 bool save( const QString& filename ) const;
75 bool release( const QString& filename, bool verbose = FALSE ) const; 82 bool release( const QString& filename, bool verbose = FALSE,
83 QTranslator::SaveMode mode = QTranslator::Stripped ) const;
76 84
77 bool contains( const char *context, const char *sourceText, 85 bool contains( const char *context, const char *sourceText,
78 const char *comment ) const; 86 const char *comment ) const;
79 void insert( const MetaTranslatorMessage& m ); 87 void insert( const MetaTranslatorMessage& m );
80 88
81 void stripObsoleteMessages(); 89 void stripObsoleteMessages();
82 void stripEmptyContexts(); 90 void stripEmptyContexts();
83 91
84 void setCodec( const char *name ); 92 void setCodec( const char *name );
85 QString toUnicode( const char *str, bool utf8 ) const; 93 QString toUnicode( const char *str, bool utf8 ) const;
86 94
87 QValueList<MetaTranslatorMessage> messages() const; 95 QValueList<MetaTranslatorMessage> messages() const;
88 QValueList<MetaTranslatorMessage> translatedMessages() const; 96 QValueList<MetaTranslatorMessage> translatedMessages() const;
89 97
90private: 98private:
91 typedef QMap<MetaTranslatorMessage, int> TMM; 99 typedef QMap<MetaTranslatorMessage, int> TMM;
92 typedef QMap<int, MetaTranslatorMessage> TMMInv; 100 typedef QMap<int, MetaTranslatorMessage> TMMInv;
93 101
94 TMM mm; 102 TMM mm;
95 QCString codecName; 103 QCString codecName;
96 QTextCodec *codec; 104 QTextCodec *codec;
97}; 105};
98 106
107/*
108 This is a quick hack. The proper way to handle this would be
109 to extend MetaTranslator's interface.
110*/
111#define ContextComment "QT_LINGUIST_INTERNAL_CONTEXT_COMMENT"
112
99#endif 113#endif
diff --git a/development/translation/shared/opie.h b/development/translation/shared/opie.h
index 4646bb0..28b2a61 100644
--- a/development/translation/shared/opie.h
+++ b/development/translation/shared/opie.h
@@ -1,21 +1,21 @@
1#ifndef OPIE_H 1#ifndef OPIE_H
2#define OPIE_H 2#define OPIE_H
3 3
4#include <qstring.h> 4#include <qstring.h>
5#include <qstringlist.h> 5#include <qstringlist.h>
6 6
7class OPIE { 7class OPIE {
8public: 8public:
9 static OPIE* self(); 9 static OPIE* self();
10 /** get the list of languages */ 10 /** get the list of languages */
11 QStringList languageList(const QString& opiedir = QString::null)const; 11 QStringList languageList(const QString& opiedir = QString::null)const;
12 QString opieDir(const QString& opieDir)const; 12 QString opieDir(const QString& opieDir = QString::null)const;
13 13
14private: 14private:
15 OPIE(); 15 OPIE();
16 ~OPIE(); 16 ~OPIE();
17 static OPIE* m_self; 17 static OPIE* m_self;
18 18
19}; 19};
20 20
21#endif 21#endif
diff --git a/development/translation/shared/proparser.cpp b/development/translation/shared/proparser.cpp
index 21d2f86..f616c5a 100644
--- a/development/translation/shared/proparser.cpp
+++ b/development/translation/shared/proparser.cpp
@@ -1,87 +1,174 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qt Linguist. 4** This file is part of Qt Linguist.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12** licenses may use this file in accordance with the Qt Commercial License
13** Agreement provided with the Software.
14**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 17**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 18** See http://www.trolltech.com/gpl/ for GPL licensing information.
19** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20** information about Qt Commercial License Agreements.
15** 21**
16** Contact info@trolltech.com if any conditions of this licensing are 22** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 23** not clear to you.
18** 24**
19**********************************************************************/ 25**********************************************************************/
20 26
21#include "proparser.h" 27#include "proparser.h"
22 28
29#include <qfile.h>
23#include <qregexp.h> 30#include <qregexp.h>
24#include <qstringlist.h> 31#include <qstringlist.h>
32#include <qtextstream.h>
33
34#ifdef Q_OS_UNIX
35#include <unistd.h>
36#endif
37
38#ifdef Q_OS_WIN32
39#define QT_POPEN _popen
40#else
41#define QT_POPEN popen
42#endif
43
44QString loadFile( const QString &fileName )
45{
46 QFile file( fileName );
47 if ( !file.open(IO_ReadOnly) ) {
48 fprintf( stderr, "error: Cannot load '%s': %s\n",
49 file.name().latin1(),
50 file.errorString().latin1() );
51 return QString();
52 }
53
54 QTextStream in( &file );
55 return in.read();
56}
25 57
26QMap<QString, QString> proFileTagMap( const QString& text ) 58QMap<QString, QString> proFileTagMap( const QString& text, const QString& opieDir )
27{ 59{
28 QString t = text; 60 QString t = text;
29 61
30 /* 62 /*
63 Process include() commands.
64 */
65 QRegExp callToInclude("include\\s*\\(\\s*([^()\\s]+)\\s*\\)");
66 int i = 0;
67 while ( (i = callToInclude.search(t, i)) != -1 ) {
68 QString after = loadFile( callToInclude.cap(1) );
69 t.replace( i, callToInclude.matchedLength(), after );
70 i += after.length();
71 }
72
73 /*
31 Strip comments, merge lines ending with backslash, add 74 Strip comments, merge lines ending with backslash, add
32 spaces around '=' and '+=', replace '\n' with ';', and 75 spaces around '=' and '+=', replace '\n' with ';', and
33 simplify white spaces. 76 simplify white spaces.
34 */ 77 */
35 t.replace( QRegExp(QString("#[^\n]$")), QString(" ") ); 78 t.replace( QRegExp(QString("#[^\n]*\n")), QString(" ") );
36 t.replace( QRegExp(QString("\\\\\\s*\n")), QString(" ") ); 79 t.replace( QRegExp(QString("\\\\[^\n\\S]*\n")), QString(" ") );
37 t.replace( "=", QString(" = ") ); 80 t.replace( "=", QString(" = ") );
38 t.replace( "+ =", QString(" += ") ); 81 t.replace( "+ =", QString(" += ") );
39 t.replace( "\n", QString(";") ); 82 t.replace( "\n", QString(";") );
40 t = t.simplifyWhiteSpace(); 83 t = t.simplifyWhiteSpace();
41 84
85 /*
86 Populate tagMap with 'key = value' entries.
87 */
42 QMap<QString, QString> tagMap; 88 QMap<QString, QString> tagMap;
43
44 QStringList lines = QStringList::split( QChar(';'), t ); 89 QStringList lines = QStringList::split( QChar(';'), t );
45 QStringList::Iterator line; 90 QStringList::Iterator line;
46 for ( line = lines.begin(); line != lines.end(); ++line ) { 91 for ( line = lines.begin(); line != lines.end(); ++line ) {
47 QStringList toks = QStringList::split( QChar(' '), *line ); 92 QStringList toks = QStringList::split( QChar(' '), *line );
48 93
49 if ( toks.count() >= 3 && 94 if ( toks.count() >= 3 &&
50 (toks[1] == QString("=") || toks[1] == QString("+=")) ) { 95 (toks[1] == QString("=") || toks[1] == QString("+=")) ) {
51 QString tag = toks.first(); 96 QString tag = toks.first();
52 int k = tag.findRev( QChar(':') ); // as in 'unix:' 97 int k = tag.findRev( QChar(':') ); // as in 'unix:'
53 if ( k != -1 ) 98 if ( k != -1 )
54 tag = tag.mid( k + 1 ); 99 tag = tag.mid( k + 1 );
55 toks.remove( toks.begin() ); 100 toks.remove( toks.begin() );
56 101
57 QString action = toks.first(); 102 QString action = toks.first();
58 toks.remove( toks.begin() ); 103 toks.remove( toks.begin() );
59 104
60 if ( tagMap.contains(tag) ) { 105 if ( tagMap.contains(tag) ) {
61 if ( action == QString("=") ) 106 if ( action == QString("=") )
62 tagMap.replace( tag, toks.join(QChar(' ')) ); 107 tagMap.replace( tag, toks.join(QChar(' ')) );
63 else 108 else
64 tagMap[tag] += QChar( ' ' ) + toks.join( QChar(' ') ); 109 tagMap[tag] += QChar( ' ' ) + toks.join( QChar(' ') );
65 } else { 110 } else {
66 tagMap[tag] = toks.join( QChar(' ') ); 111 tagMap[tag] = toks.join( QChar(' ') );
67 } 112 }
68 } 113 }
69 } 114 }
70 115
71 QRegExp var( "\\$\\$[a-zA-Z0-9_]+" ); 116 /*
117 Expand $$variables within the 'value' part of a 'key = value'
118 pair.
119 */
120 QRegExp var( "\\$\\$[({]?([a-zA-Z0-9_]+)[)}]?" );
72 QMap<QString, QString>::Iterator it; 121 QMap<QString, QString>::Iterator it;
73 for ( it = tagMap.begin(); it != tagMap.end(); ++it ) { 122 for ( it = tagMap.begin(); it != tagMap.end(); ++it ) {
74 int i = 0; 123 int i = 0;
75 124 while ( (i = var.search((*it), i)) != -1 ) {
76 while ( (i = var.search(it.data(), i)) != -1 ) {
77 int len = var.matchedLength(); 125 int len = var.matchedLength();
78 QString invocation = (*it).mid( i + 2, len - 2 ); 126 QString invocation = var.cap(1);
79 QString after; 127 QString after;
80 if ( tagMap.contains(invocation) ) 128
81 after = tagMap[invocation]; 129 if ( invocation == "system" ) {
82 (*it).replace( i, len, after ); 130 // skip system(); it will be handled in the next pass
131 ++i;
132 } else if ( invocation == "OPIEDIR") {
133 (*it).replace( i, len, opieDir );
134 }else {
135 if ( tagMap.contains(invocation) )
136 after = tagMap[invocation];
137 (*it).replace( i, len, after );
138 }
139 }
140 }
141
142 /*
143 Execute system() calls.
144 */
145 QRegExp callToSystem( "\\$\\$system\\s*\\(([^()]*)\\)" );
146 for ( it = tagMap.begin(); it != tagMap.end(); ++it ) {
147 int i = 0;
148 while ( (i = callToSystem.search((*it), i)) != -1 ) {
149 /*
150 This code is stolen from qmake's project.cpp file.
151 Ideally we would use the same parser, so we wouldn't
152 have this code duplication.
153 */
154 QString after;
155 char buff[256];
156 FILE *proc = QT_POPEN( callToSystem.cap(1).latin1(), "r" );
157 while ( proc && !feof(proc) ) {
158 int read_in = fread( buff, 1, 255, proc );
159 if ( !read_in )
160 break;
161 for ( int i = 0; i < read_in; i++ ) {
162 if ( buff[i] == '\n' || buff[i] == '\t' )
163 buff[i] = ' ';
164 }
165 buff[read_in] = '\0';
166 after += buff;
167 }
168 (*it).replace( i, callToSystem.matchedLength(), after );
83 i += after.length(); 169 i += after.length();
84 } 170 }
85 } 171 }
172
86 return tagMap; 173 return tagMap;
87} 174}
diff --git a/development/translation/shared/proparser.h b/development/translation/shared/proparser.h
index 6a61d90..e5678d6 100644
--- a/development/translation/shared/proparser.h
+++ b/development/translation/shared/proparser.h
@@ -1,29 +1,35 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qt Linguist. 4** This file is part of Qt Linguist.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12** licenses may use this file in accordance with the Qt Commercial License
13** Agreement provided with the Software.
14**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 17**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 18** See http://www.trolltech.com/gpl/ for GPL licensing information.
19** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20** information about Qt Commercial License Agreements.
15** 21**
16** Contact info@trolltech.com if any conditions of this licensing are 22** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 23** not clear to you.
18** 24**
19**********************************************************************/ 25**********************************************************************/
20 26
21#ifndef PROPARSER_H 27#ifndef PROPARSER_H
22#define PROPARSER_H 28#define PROPARSER_H
23 29
24#include <qmap.h> 30#include <qmap.h>
25#include <qstring.h> 31#include <qstring.h>
26 32
27QMap<QString, QString> proFileTagMap( const QString& text ); 33QMap<QString, QString> proFileTagMap( const QString& text, const QString& = QString::null );
28 34
29#endif 35#endif