-rw-r--r-- | development/translation/opie-lupdate/fetchtr.cpp | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/development/translation/opie-lupdate/fetchtr.cpp b/development/translation/opie-lupdate/fetchtr.cpp index eb25555..d1f5881 100644 --- a/development/translation/opie-lupdate/fetchtr.cpp +++ b/development/translation/opie-lupdate/fetchtr.cpp | |||
@@ -1,784 +1,787 @@ | |||
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 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | 11 | ** 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. | 12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
13 | ** | 13 | ** |
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | 14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. |
15 | ** | 15 | ** |
16 | ** Contact info@trolltech.com if any conditions of this licensing are | 16 | ** Contact info@trolltech.com if any conditions of this licensing are |
17 | ** not clear to you. | 17 | ** not clear to you. |
18 | ** | 18 | ** |
19 | **********************************************************************/ | 19 | **********************************************************************/ |
20 | 20 | ||
21 | #include <metatranslator.h> | 21 | #include <metatranslator.h> |
22 | 22 | ||
23 | #include <qfile.h> | 23 | #include <qfile.h> |
24 | #include <qregexp.h> | 24 | #include <qregexp.h> |
25 | #include <qstring.h> | 25 | #include <qstring.h> |
26 | #include <qtextstream.h> | 26 | #include <qtextstream.h> |
27 | #include <qvaluestack.h> | 27 | #include <qvaluestack.h> |
28 | #include <qxml.h> | 28 | #include <qxml.h> |
29 | 29 | ||
30 | #include <ctype.h> | 30 | #include <ctype.h> |
31 | #include <errno.h> | 31 | #include <errno.h> |
32 | #include <stdio.h> | 32 | #include <stdio.h> |
33 | #include <string.h> | 33 | #include <string.h> |
34 | 34 | ||
35 | /* qmake ignore Q_OBJECT */ | 35 | /* qmake ignore Q_OBJECT */ |
36 | 36 | ||
37 | static const char MagicComment[] = "TRANSLATOR "; | 37 | static const char MagicComment[] = "TRANSLATOR "; |
38 | 38 | ||
39 | static QMap<QCString, int> needs_Q_OBJECT; | 39 | static QMap<QCString, int> needs_Q_OBJECT; |
40 | static QMap<QCString, int> lacks_Q_OBJECT; | 40 | static QMap<QCString, int> lacks_Q_OBJECT; |
41 | 41 | ||
42 | /* | 42 | /* |
43 | The first part of this source file is the C++ tokenizer. We skip | 43 | 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. | 44 | most of C++; the only tokens that interest us are defined here. |
45 | Thus, the code fragment | 45 | Thus, the code fragment |
46 | 46 | ||
47 | int main() | 47 | int main() |
48 | { | 48 | { |
49 | printf( "Hello, world!\n" ); | 49 | printf( "Hello, world!\n" ); |
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | 52 | ||
53 | is broken down into the following tokens (Tok_ omitted): | 53 | is broken down into the following tokens (Tok_ omitted): |
54 | 54 | ||
55 | Ident Ident LeftParen RightParen | 55 | Ident Ident LeftParen RightParen |
56 | LeftBrace | 56 | LeftBrace |
57 | Ident LeftParen String RightParen Semicolon | 57 | Ident LeftParen String RightParen Semicolon |
58 | return Semicolon | 58 | return Semicolon |
59 | RightBrace. | 59 | RightBrace. |
60 | 60 | ||
61 | The 0 doesn't produce any token. | 61 | The 0 doesn't produce any token. |
62 | */ | 62 | */ |
63 | 63 | ||
64 | enum { Tok_Eof, Tok_class, Tok_namespace, Tok_return, Tok_tr, | 64 | enum { Tok_Eof, Tok_class, Tok_namespace, Tok_return, Tok_tr, |
65 | Tok_trUtf8, Tok_translate, Tok_Q_OBJECT, Tok_Ident, | 65 | Tok_trUtf8, Tok_translate, Tok_Q_OBJECT, Tok_Ident, |
66 | Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, | 66 | Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, |
67 | Tok_Gulbrandsen, Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, | 67 | Tok_Gulbrandsen, Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, |
68 | Tok_RightParen, Tok_Comma, Tok_Semicolon }; | 68 | Tok_RightParen, Tok_Comma, Tok_Semicolon }; |
69 | 69 | ||
70 | /* | 70 | /* |
71 | The tokenizer maintains the following global variables. The names | 71 | The tokenizer maintains the following global variables. The names |
72 | should be self-explanatory. | 72 | should be self-explanatory. |
73 | */ | 73 | */ |
74 | static QCString yyFileName; | 74 | static QCString yyFileName; |
75 | static int yyCh; | 75 | static int yyCh; |
76 | static char yyIdent[128]; | 76 | static char yyIdent[128]; |
77 | static size_t yyIdentLen; | 77 | static size_t yyIdentLen; |
78 | static char yyComment[65536]; | 78 | static char yyComment[65536]; |
79 | static size_t yyCommentLen; | 79 | static size_t yyCommentLen; |
80 | static char yyString[16384]; | 80 | static char yyString[16384]; |
81 | static size_t yyStringLen; | 81 | static size_t yyStringLen; |
82 | static QValueStack<int> yySavedBraceDepth; | 82 | static QValueStack<int> yySavedBraceDepth; |
83 | static int yyBraceDepth; | 83 | static int yyBraceDepth; |
84 | static int yyParenDepth; | 84 | static int yyParenDepth; |
85 | static int yyLineNo; | 85 | static int yyLineNo; |
86 | static int yyCurLineNo; | 86 | static int yyCurLineNo; |
87 | 87 | ||
88 | // the file to read from (if reading from a file) | 88 | // the file to read from (if reading from a file) |
89 | static FILE *yyInFile; | 89 | static FILE *yyInFile; |
90 | 90 | ||
91 | // the string to read from and current position in the string (otherwise) | 91 | // the string to read from and current position in the string (otherwise) |
92 | static QString yyInStr; | 92 | static QString yyInStr; |
93 | static int yyInPos; | 93 | static int yyInPos; |
94 | 94 | ||
95 | static int (*getChar)(); | 95 | static int (*getChar)(); |
96 | 96 | ||
97 | static int getCharFromFile() | 97 | static int getCharFromFile() |
98 | { | 98 | { |
99 | int c = getc( yyInFile ); | 99 | int c = getc( yyInFile ); |
100 | if ( c == '\n' ) | 100 | if ( c == '\n' ) |
101 | yyCurLineNo++; | 101 | yyCurLineNo++; |
102 | return c; | 102 | return c; |
103 | } | 103 | } |
104 | 104 | ||
105 | static int getCharFromString() | 105 | static int getCharFromString() |
106 | { | 106 | { |
107 | if ( yyInPos == (int) yyInStr.length() ) { | 107 | if ( yyInPos == (int) yyInStr.length() ) { |
108 | return EOF; | 108 | return EOF; |
109 | } else { | 109 | } else { |
110 | return yyInStr[yyInPos++].latin1(); | 110 | return yyInStr[yyInPos++].latin1(); |
111 | } | 111 | } |
112 | } | 112 | } |
113 | 113 | ||
114 | static void startTokenizer( const char *fileName, int (*getCharFunc)() ) | 114 | static void startTokenizer( const char *fileName, int (*getCharFunc)() ) |
115 | { | 115 | { |
116 | yyInPos = 0; | 116 | yyInPos = 0; |
117 | getChar = getCharFunc; | 117 | getChar = getCharFunc; |
118 | 118 | ||
119 | yyFileName = fileName; | 119 | yyFileName = fileName; |
120 | yyCh = getChar(); | 120 | yyCh = getChar(); |
121 | yySavedBraceDepth.clear(); | 121 | yySavedBraceDepth.clear(); |
122 | yyBraceDepth = 0; | 122 | yyBraceDepth = 0; |
123 | yyParenDepth = 0; | 123 | yyParenDepth = 0; |
124 | yyCurLineNo = 1; | 124 | yyCurLineNo = 1; |
125 | } | 125 | } |
126 | 126 | ||
127 | static int getToken() | 127 | static int getToken() |
128 | { | 128 | { |
129 | const char tab[] = "abfnrtv"; | 129 | const char tab[] = "abfnrtv"; |
130 | const char backTab[] = "\a\b\f\n\r\t\v"; | 130 | const char backTab[] = "\a\b\f\n\r\t\v"; |
131 | uint n; | 131 | uint n; |
132 | 132 | ||
133 | yyIdentLen = 0; | 133 | yyIdentLen = 0; |
134 | yyCommentLen = 0; | 134 | yyCommentLen = 0; |
135 | yyStringLen = 0; | 135 | yyStringLen = 0; |
136 | 136 | ||
137 | while ( yyCh != EOF ) { | 137 | while ( yyCh != EOF ) { |
138 | yyLineNo = yyCurLineNo; | 138 | yyLineNo = yyCurLineNo; |
139 | 139 | ||
140 | if ( isalpha(yyCh) || yyCh == '_' ) { | 140 | if ( isalpha(yyCh) || yyCh == '_' ) { |
141 | do { | 141 | do { |
142 | if ( yyIdentLen < sizeof(yyIdent) - 1 ) | 142 | if ( yyIdentLen < sizeof(yyIdent) - 1 ) |
143 | yyIdent[yyIdentLen++] = (char) yyCh; | 143 | yyIdent[yyIdentLen++] = (char) yyCh; |
144 | yyCh = getChar(); | 144 | yyCh = getChar(); |
145 | } while ( isalnum(yyCh) || yyCh == '_' ); | 145 | } while ( isalnum(yyCh) || yyCh == '_' ); |
146 | yyIdent[yyIdentLen] = '\0'; | 146 | yyIdent[yyIdentLen] = '\0'; |
147 | 147 | ||
148 | switch ( yyIdent[0] ) { | 148 | switch ( yyIdent[0] ) { |
149 | case 'Q': | 149 | case 'Q': |
150 | if ( strcmp(yyIdent + 1, "_OBJECT") == 0 ) { | 150 | if ( strcmp(yyIdent + 1, "_OBJECT") == 0 ) { |
151 | return Tok_Q_OBJECT; | 151 | return Tok_Q_OBJECT; |
152 | } else if ( strcmp(yyIdent + 1, "T_TR_NOOP") == 0 ) { | 152 | } else if ( strcmp(yyIdent + 1, "T_TR_NOOP") == 0 ) { |
153 | return Tok_tr; | 153 | return Tok_tr; |
154 | } else if ( strcmp(yyIdent + 1, "T_TRANSLATE_NOOP") == 0 ) { | 154 | } else if ( strcmp(yyIdent + 1, "T_TRANSLATE_NOOP") == 0 ) { |
155 | return Tok_translate; | 155 | return Tok_translate; |
156 | } | 156 | } |
157 | break; | 157 | break; |
158 | case 'T': | 158 | case 'T': |
159 | // TR() for when all else fails | 159 | // TR() for when all else fails |
160 | if ( qstricmp(yyIdent + 1, "R") == 0 ) | 160 | if ( qstricmp(yyIdent + 1, "R") == 0 ) |
161 | return Tok_tr; | 161 | return Tok_tr; |
162 | break; | 162 | break; |
163 | case 'c': | 163 | case 'c': |
164 | if ( strcmp(yyIdent + 1, "lass") == 0 ) | 164 | if ( strcmp(yyIdent + 1, "lass") == 0 ) |
165 | return Tok_class; | 165 | return Tok_class; |
166 | break; | 166 | break; |
167 | case 'n': | 167 | case 'n': |
168 | if ( strcmp(yyIdent + 1, "amespace") == 0 ) | 168 | if ( strcmp(yyIdent + 1, "amespace") == 0 ) |
169 | return Tok_namespace; | 169 | return Tok_namespace; |
170 | break; | 170 | break; |
171 | case 'r': | 171 | case 'r': |
172 | if ( strcmp(yyIdent + 1, "eturn") == 0 ) | 172 | if ( strcmp(yyIdent + 1, "eturn") == 0 ) |
173 | return Tok_return; | 173 | return Tok_return; |
174 | break; | 174 | break; |
175 | case 's': | 175 | case 's': |
176 | if ( strcmp(yyIdent + 1, "truct") == 0 ) | 176 | if ( strcmp(yyIdent + 1, "truct") == 0 ) |
177 | return Tok_class; | 177 | return Tok_class; |
178 | break; | 178 | break; |
179 | case 'i': | ||
180 | if( strcmp(yyIdent + 1, "18n") == 0 ) | ||
181 | return Tok_tr; | ||
179 | case 't': | 182 | case 't': |
180 | if ( strcmp(yyIdent + 1, "r") == 0 ) { | 183 | if ( strcmp(yyIdent + 1, "r") == 0 ) { |
181 | return Tok_tr; | 184 | return Tok_tr; |
182 | } else if ( qstrcmp(yyIdent + 1, "rUtf8") == 0 ) { | 185 | } else if ( qstrcmp(yyIdent + 1, "rUtf8") == 0 ) { |
183 | return Tok_trUtf8; | 186 | return Tok_trUtf8; |
184 | } else if ( qstrcmp(yyIdent + 1, "ranslate") == 0 ) { | 187 | } else if ( qstrcmp(yyIdent + 1, "ranslate") == 0 ) { |
185 | return Tok_translate; | 188 | return Tok_translate; |
186 | } | 189 | } |
187 | } | 190 | } |
188 | return Tok_Ident; | 191 | return Tok_Ident; |
189 | } else { | 192 | } else { |
190 | switch ( yyCh ) { | 193 | switch ( yyCh ) { |
191 | case '#': | 194 | case '#': |
192 | /* | 195 | /* |
193 | Early versions of lupdate complained about | 196 | Early versions of lupdate complained about |
194 | unbalanced braces in the following code: | 197 | unbalanced braces in the following code: |
195 | 198 | ||
196 | #ifdef ALPHA | 199 | #ifdef ALPHA |
197 | while ( beta ) { | 200 | while ( beta ) { |
198 | #else | 201 | #else |
199 | while ( gamma ) { | 202 | while ( gamma ) { |
200 | #endif | 203 | #endif |
201 | delta; | 204 | delta; |
202 | } | 205 | } |
203 | 206 | ||
204 | The code contains, indeed, two opening braces for | 207 | The code contains, indeed, two opening braces for |
205 | one closing brace; yet there's no reason to panic. | 208 | one closing brace; yet there's no reason to panic. |
206 | 209 | ||
207 | The solution is to remember yyBraceDepth as it was | 210 | The solution is to remember yyBraceDepth as it was |
208 | when #if, #ifdef or #ifndef was met, and to set | 211 | when #if, #ifdef or #ifndef was met, and to set |
209 | yyBraceDepth to that value when meeting #elif or | 212 | yyBraceDepth to that value when meeting #elif or |
210 | #else. | 213 | #else. |
211 | */ | 214 | */ |
212 | do { | 215 | do { |
213 | yyCh = getChar(); | 216 | yyCh = getChar(); |
214 | } while ( isspace(yyCh) && yyCh != '\n' ); | 217 | } while ( isspace(yyCh) && yyCh != '\n' ); |
215 | 218 | ||
216 | switch ( yyCh ) { | 219 | switch ( yyCh ) { |
217 | case 'i': | 220 | case 'i': |
218 | yyCh = getChar(); | 221 | yyCh = getChar(); |
219 | if ( yyCh == 'f' ) { | 222 | if ( yyCh == 'f' ) { |
220 | // if, ifdef, ifndef | 223 | // if, ifdef, ifndef |
221 | yySavedBraceDepth.push( yyBraceDepth ); | 224 | yySavedBraceDepth.push( yyBraceDepth ); |
222 | } | 225 | } |
223 | break; | 226 | break; |
224 | case 'e': | 227 | case 'e': |
225 | yyCh = getChar(); | 228 | yyCh = getChar(); |
226 | if ( yyCh == 'l' ) { | 229 | if ( yyCh == 'l' ) { |
227 | // elif, else | 230 | // elif, else |
228 | if ( !yySavedBraceDepth.isEmpty() ) | 231 | if ( !yySavedBraceDepth.isEmpty() ) |
229 | yyBraceDepth = yySavedBraceDepth.top(); | 232 | yyBraceDepth = yySavedBraceDepth.top(); |
230 | } else if ( yyCh == 'n' ) { | 233 | } else if ( yyCh == 'n' ) { |
231 | // endif | 234 | // endif |
232 | if ( !yySavedBraceDepth.isEmpty() ) | 235 | if ( !yySavedBraceDepth.isEmpty() ) |
233 | yySavedBraceDepth.pop(); | 236 | yySavedBraceDepth.pop(); |
234 | } | 237 | } |
235 | } | 238 | } |
236 | while ( isalnum(yyCh) || yyCh == '_' ) | 239 | while ( isalnum(yyCh) || yyCh == '_' ) |
237 | yyCh = getChar(); | 240 | yyCh = getChar(); |
238 | break; | 241 | break; |
239 | case '/': | 242 | case '/': |
240 | yyCh = getChar(); | 243 | yyCh = getChar(); |
241 | if ( yyCh == '/' ) { | 244 | if ( yyCh == '/' ) { |
242 | do { | 245 | do { |
243 | yyCh = getChar(); | 246 | yyCh = getChar(); |
244 | } while ( yyCh != EOF && yyCh != '\n' ); | 247 | } while ( yyCh != EOF && yyCh != '\n' ); |
245 | } else if ( yyCh == '*' ) { | 248 | } else if ( yyCh == '*' ) { |
246 | bool metAster = FALSE; | 249 | bool metAster = FALSE; |
247 | bool metAsterSlash = FALSE; | 250 | bool metAsterSlash = FALSE; |
248 | 251 | ||
249 | while ( !metAsterSlash ) { | 252 | while ( !metAsterSlash ) { |
250 | yyCh = getChar(); | 253 | yyCh = getChar(); |
251 | if ( yyCh == EOF ) { | 254 | if ( yyCh == EOF ) { |
252 | fprintf( stderr, | 255 | fprintf( stderr, |
253 | "%s: Unterminated C++ comment starting at" | 256 | "%s: Unterminated C++ comment starting at" |
254 | " line %d\n", | 257 | " line %d\n", |
255 | (const char *) yyFileName, yyLineNo ); | 258 | (const char *) yyFileName, yyLineNo ); |
256 | yyComment[yyCommentLen] = '\0'; | 259 | yyComment[yyCommentLen] = '\0'; |
257 | return Tok_Comment; | 260 | return Tok_Comment; |
258 | } | 261 | } |
259 | if ( yyCommentLen < sizeof(yyComment) - 1 ) | 262 | if ( yyCommentLen < sizeof(yyComment) - 1 ) |
260 | yyComment[yyCommentLen++] = (char) yyCh; | 263 | yyComment[yyCommentLen++] = (char) yyCh; |
261 | 264 | ||
262 | if ( yyCh == '*' ) | 265 | if ( yyCh == '*' ) |
263 | metAster = TRUE; | 266 | metAster = TRUE; |
264 | else if ( metAster && yyCh == '/' ) | 267 | else if ( metAster && yyCh == '/' ) |
265 | metAsterSlash = TRUE; | 268 | metAsterSlash = TRUE; |
266 | else | 269 | else |
267 | metAster = FALSE; | 270 | metAster = FALSE; |
268 | } | 271 | } |
269 | yyCh = getChar(); | 272 | yyCh = getChar(); |
270 | yyCommentLen -= 2; | 273 | yyCommentLen -= 2; |
271 | yyComment[yyCommentLen] = '\0'; | 274 | yyComment[yyCommentLen] = '\0'; |
272 | return Tok_Comment; | 275 | return Tok_Comment; |
273 | } | 276 | } |
274 | break; | 277 | break; |
275 | case '"': | 278 | case '"': |
276 | yyCh = getChar(); | 279 | yyCh = getChar(); |
277 | 280 | ||
278 | while ( yyCh != EOF && yyCh != '\n' && yyCh != '"' ) { | 281 | while ( yyCh != EOF && yyCh != '\n' && yyCh != '"' ) { |
279 | if ( yyCh == '\\' ) { | 282 | if ( yyCh == '\\' ) { |
280 | yyCh = getChar(); | 283 | yyCh = getChar(); |
281 | 284 | ||
282 | if ( yyCh == '\n' ) { | 285 | if ( yyCh == '\n' ) { |
283 | yyCh = getChar(); | 286 | yyCh = getChar(); |
284 | } else if ( yyCh == 'x' ) { | 287 | } else if ( yyCh == 'x' ) { |
285 | QCString hex = "0"; | 288 | QCString hex = "0"; |
286 | 289 | ||
287 | yyCh = getChar(); | 290 | yyCh = getChar(); |
288 | while ( isxdigit(yyCh) ) { | 291 | while ( isxdigit(yyCh) ) { |
289 | hex += (char) yyCh; | 292 | hex += (char) yyCh; |
290 | yyCh = getChar(); | 293 | yyCh = getChar(); |
291 | } | 294 | } |
292 | sscanf( hex, "%x", &n ); | 295 | sscanf( hex, "%x", &n ); |
293 | if ( yyStringLen < sizeof(yyString) - 1 ) | 296 | if ( yyStringLen < sizeof(yyString) - 1 ) |
294 | yyString[yyStringLen++] = (char) n; | 297 | yyString[yyStringLen++] = (char) n; |
295 | } else if ( yyCh >= '0' && yyCh < '8' ) { | 298 | } else if ( yyCh >= '0' && yyCh < '8' ) { |
296 | QCString oct = ""; | 299 | QCString oct = ""; |
297 | 300 | ||
298 | do { | 301 | do { |
299 | oct += (char) yyCh; | 302 | oct += (char) yyCh; |
300 | yyCh = getChar(); | 303 | yyCh = getChar(); |
301 | } while ( yyCh >= '0' && yyCh < '8' ); | 304 | } while ( yyCh >= '0' && yyCh < '8' ); |
302 | sscanf( oct, "%o", &n ); | 305 | sscanf( oct, "%o", &n ); |
303 | if ( yyStringLen < sizeof(yyString) - 1 ) | 306 | if ( yyStringLen < sizeof(yyString) - 1 ) |
304 | yyString[yyStringLen++] = (char) n; | 307 | yyString[yyStringLen++] = (char) n; |
305 | } else { | 308 | } else { |
306 | const char *p = strchr( tab, yyCh ); | 309 | const char *p = strchr( tab, yyCh ); |
307 | if ( yyStringLen < sizeof(yyString) - 1 ) | 310 | if ( yyStringLen < sizeof(yyString) - 1 ) |
308 | yyString[yyStringLen++] = ( p == 0 ) ? | 311 | yyString[yyStringLen++] = ( p == 0 ) ? |
309 | (char) yyCh : backTab[p - tab]; | 312 | (char) yyCh : backTab[p - tab]; |
310 | yyCh = getChar(); | 313 | yyCh = getChar(); |
311 | } | 314 | } |
312 | } else { | 315 | } else { |
313 | if ( yyStringLen < sizeof(yyString) - 1 ) | 316 | if ( yyStringLen < sizeof(yyString) - 1 ) |
314 | yyString[yyStringLen++] = (char) yyCh; | 317 | yyString[yyStringLen++] = (char) yyCh; |
315 | yyCh = getChar(); | 318 | yyCh = getChar(); |
316 | } | 319 | } |
317 | } | 320 | } |
318 | yyString[yyStringLen] = '\0'; | 321 | yyString[yyStringLen] = '\0'; |
319 | 322 | ||
320 | if ( yyCh != '"' ) | 323 | if ( yyCh != '"' ) |
321 | qWarning( "%s:%d: Unterminated C++ string", | 324 | qWarning( "%s:%d: Unterminated C++ string", |
322 | (const char *) yyFileName, yyLineNo ); | 325 | (const char *) yyFileName, yyLineNo ); |
323 | 326 | ||
324 | if ( yyCh == EOF ) { | 327 | if ( yyCh == EOF ) { |
325 | return Tok_Eof; | 328 | return Tok_Eof; |
326 | } else { | 329 | } else { |
327 | yyCh = getChar(); | 330 | yyCh = getChar(); |
328 | return Tok_String; | 331 | return Tok_String; |
329 | } | 332 | } |
330 | break; | 333 | break; |
331 | case '-': | 334 | case '-': |
332 | yyCh = getChar(); | 335 | yyCh = getChar(); |
333 | if ( yyCh == '>' ) { | 336 | if ( yyCh == '>' ) { |
334 | yyCh = getChar(); | 337 | yyCh = getChar(); |
335 | return Tok_Arrow; | 338 | return Tok_Arrow; |
336 | } | 339 | } |
337 | break; | 340 | break; |
338 | case ':': | 341 | case ':': |
339 | yyCh = getChar(); | 342 | yyCh = getChar(); |
340 | if ( yyCh == ':' ) { | 343 | if ( yyCh == ':' ) { |
341 | yyCh = getChar(); | 344 | yyCh = getChar(); |
342 | return Tok_Gulbrandsen; | 345 | return Tok_Gulbrandsen; |
343 | } | 346 | } |
344 | return Tok_Colon; | 347 | return Tok_Colon; |
345 | case '\'': | 348 | case '\'': |
346 | yyCh = getChar(); | 349 | yyCh = getChar(); |
347 | if ( yyCh == '\\' ) | 350 | if ( yyCh == '\\' ) |
348 | yyCh = getChar(); | 351 | yyCh = getChar(); |
349 | 352 | ||
350 | do { | 353 | do { |
351 | yyCh = getChar(); | 354 | yyCh = getChar(); |
352 | } while ( yyCh != EOF && yyCh != '\'' ); | 355 | } while ( yyCh != EOF && yyCh != '\'' ); |
353 | yyCh = getChar(); | 356 | yyCh = getChar(); |
354 | break; | 357 | break; |
355 | case '{': | 358 | case '{': |
356 | yyBraceDepth++; | 359 | yyBraceDepth++; |
357 | yyCh = getChar(); | 360 | yyCh = getChar(); |
358 | return Tok_LeftBrace; | 361 | return Tok_LeftBrace; |
359 | case '}': | 362 | case '}': |
360 | yyBraceDepth--; | 363 | yyBraceDepth--; |
361 | yyCh = getChar(); | 364 | yyCh = getChar(); |
362 | return Tok_RightBrace; | 365 | return Tok_RightBrace; |
363 | case '(': | 366 | case '(': |
364 | yyParenDepth++; | 367 | yyParenDepth++; |
365 | yyCh = getChar(); | 368 | yyCh = getChar(); |
366 | return Tok_LeftParen; | 369 | return Tok_LeftParen; |
367 | case ')': | 370 | case ')': |
368 | yyParenDepth--; | 371 | yyParenDepth--; |
369 | yyCh = getChar(); | 372 | yyCh = getChar(); |
370 | return Tok_RightParen; | 373 | return Tok_RightParen; |
371 | case ',': | 374 | case ',': |
372 | yyCh = getChar(); | 375 | yyCh = getChar(); |
373 | return Tok_Comma; | 376 | return Tok_Comma; |
374 | case ';': | 377 | case ';': |
375 | yyCh = getChar(); | 378 | yyCh = getChar(); |
376 | return Tok_Semicolon; | 379 | return Tok_Semicolon; |
377 | default: | 380 | default: |
378 | yyCh = getChar(); | 381 | yyCh = getChar(); |
379 | } | 382 | } |
380 | } | 383 | } |
381 | } | 384 | } |
382 | return Tok_Eof; | 385 | return Tok_Eof; |
383 | } | 386 | } |
384 | 387 | ||
385 | /* | 388 | /* |
386 | The second part of this source file is the parser. It accomplishes | 389 | The second part of this source file is the parser. It accomplishes |
387 | a very easy task: It finds all strings inside a tr() or translate() | 390 | a very easy task: It finds all strings inside a tr() or translate() |
388 | call, and possibly finds out the context of the call. It supports | 391 | call, and possibly finds out the context of the call. It supports |
389 | three cases: (1) the context is specified, as in | 392 | three cases: (1) the context is specified, as in |
390 | FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello"); | 393 | FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello"); |
391 | (2) the call appears within an inlined function; (3) the call | 394 | (2) the call appears within an inlined function; (3) the call |
392 | appears within a function defined outside the class definition. | 395 | appears within a function defined outside the class definition. |
393 | */ | 396 | */ |
394 | 397 | ||
395 | static int yyTok; | 398 | static int yyTok; |
396 | 399 | ||
397 | static bool match( int t ) | 400 | static bool match( int t ) |
398 | { | 401 | { |
399 | bool matches = ( yyTok == t ); | 402 | bool matches = ( yyTok == t ); |
400 | if ( matches ) | 403 | if ( matches ) |
401 | yyTok = getToken(); | 404 | yyTok = getToken(); |
402 | return matches; | 405 | return matches; |
403 | } | 406 | } |
404 | 407 | ||
405 | static bool matchString( QCString *s ) | 408 | static bool matchString( QCString *s ) |
406 | { | 409 | { |
407 | bool matches = ( yyTok == Tok_String ); | 410 | bool matches = ( yyTok == Tok_String ); |
408 | *s = ""; | 411 | *s = ""; |
409 | while ( yyTok == Tok_String ) { | 412 | while ( yyTok == Tok_String ) { |
410 | *s += yyString; | 413 | *s += yyString; |
411 | yyTok = getToken(); | 414 | yyTok = getToken(); |
412 | } | 415 | } |
413 | return matches; | 416 | return matches; |
414 | } | 417 | } |
415 | 418 | ||
416 | static bool matchEncoding( bool *utf8 ) | 419 | static bool matchEncoding( bool *utf8 ) |
417 | { | 420 | { |
418 | if ( yyTok == Tok_Ident ) { | 421 | if ( yyTok == Tok_Ident ) { |
419 | if ( strcmp(yyIdent, "QApplication") == 0 ) { | 422 | if ( strcmp(yyIdent, "QApplication") == 0 ) { |
420 | yyTok = getToken(); | 423 | yyTok = getToken(); |
421 | if ( yyTok == Tok_Gulbrandsen ) | 424 | if ( yyTok == Tok_Gulbrandsen ) |
422 | yyTok = getToken(); | 425 | yyTok = getToken(); |
423 | } | 426 | } |
424 | *utf8 = QString( yyIdent ).endsWith( QString("UTF8") ); | 427 | *utf8 = QString( yyIdent ).endsWith( QString("UTF8") ); |
425 | yyTok = getToken(); | 428 | yyTok = getToken(); |
426 | return TRUE; | 429 | return TRUE; |
427 | } else { | 430 | } else { |
428 | return FALSE; | 431 | return FALSE; |
429 | } | 432 | } |
430 | } | 433 | } |
431 | 434 | ||
432 | static void parse( MetaTranslator *tor, const char *initialContext, | 435 | static void parse( MetaTranslator *tor, const char *initialContext, |
433 | const char *defaultContext ) | 436 | const char *defaultContext ) |
434 | { | 437 | { |
435 | QMap<QCString, QCString> qualifiedContexts; | 438 | QMap<QCString, QCString> qualifiedContexts; |
436 | QStringList namespaces; | 439 | QStringList namespaces; |
437 | QCString context; | 440 | QCString context; |
438 | QCString text; | 441 | QCString text; |
439 | QCString com; | 442 | QCString com; |
440 | QCString functionContext = initialContext; | 443 | QCString functionContext = initialContext; |
441 | QCString prefix; | 444 | QCString prefix; |
442 | bool utf8 = FALSE; | 445 | bool utf8 = FALSE; |
443 | bool missing_Q_OBJECT = FALSE; | 446 | bool missing_Q_OBJECT = FALSE; |
444 | 447 | ||
445 | yyTok = getToken(); | 448 | yyTok = getToken(); |
446 | while ( yyTok != Tok_Eof ) { | 449 | while ( yyTok != Tok_Eof ) { |
447 | switch ( yyTok ) { | 450 | switch ( yyTok ) { |
448 | case Tok_class: | 451 | case Tok_class: |
449 | /* | 452 | /* |
450 | Partial support for inlined functions. | 453 | Partial support for inlined functions. |
451 | */ | 454 | */ |
452 | yyTok = getToken(); | 455 | yyTok = getToken(); |
453 | if ( yyBraceDepth == (int) namespaces.count() && | 456 | if ( yyBraceDepth == (int) namespaces.count() && |
454 | yyParenDepth == 0 ) { | 457 | yyParenDepth == 0 ) { |
455 | do { | 458 | do { |
456 | /* | 459 | /* |
457 | This code should execute only once, but we play | 460 | This code should execute only once, but we play |
458 | safe with impure definitions such as | 461 | safe with impure definitions such as |
459 | 'class Q_EXPORT QMessageBox', in which case | 462 | 'class Q_EXPORT QMessageBox', in which case |
460 | 'QMessageBox' is the class name, not 'Q_EXPORT'. | 463 | 'QMessageBox' is the class name, not 'Q_EXPORT'. |
461 | */ | 464 | */ |
462 | functionContext = yyIdent; | 465 | functionContext = yyIdent; |
463 | yyTok = getToken(); | 466 | yyTok = getToken(); |
464 | } while ( yyTok == Tok_Ident ); | 467 | } while ( yyTok == Tok_Ident ); |
465 | 468 | ||
466 | while ( yyTok == Tok_Gulbrandsen ) { | 469 | while ( yyTok == Tok_Gulbrandsen ) { |
467 | yyTok = getToken(); | 470 | yyTok = getToken(); |
468 | functionContext += "::"; | 471 | functionContext += "::"; |
469 | functionContext += yyIdent; | 472 | functionContext += yyIdent; |
470 | yyTok = getToken(); | 473 | yyTok = getToken(); |
471 | } | 474 | } |
472 | 475 | ||
473 | if ( yyTok == Tok_Colon ) { | 476 | if ( yyTok == Tok_Colon ) { |
474 | missing_Q_OBJECT = TRUE; | 477 | missing_Q_OBJECT = TRUE; |
475 | } else { | 478 | } else { |
476 | functionContext = defaultContext; | 479 | functionContext = defaultContext; |
477 | } | 480 | } |
478 | } | 481 | } |
479 | break; | 482 | break; |
480 | case Tok_namespace: | 483 | case Tok_namespace: |
481 | yyTok = getToken(); | 484 | yyTok = getToken(); |
482 | if ( yyTok == Tok_Ident ) { | 485 | if ( yyTok == Tok_Ident ) { |
483 | QCString ns = yyIdent; | 486 | QCString ns = yyIdent; |
484 | yyTok = getToken(); | 487 | yyTok = getToken(); |
485 | if ( yyTok == Tok_LeftBrace && | 488 | if ( yyTok == Tok_LeftBrace && |
486 | yyBraceDepth == (int) namespaces.count() + 1 ) | 489 | yyBraceDepth == (int) namespaces.count() + 1 ) |
487 | namespaces.append( QString(ns) ); | 490 | namespaces.append( QString(ns) ); |
488 | } | 491 | } |
489 | break; | 492 | break; |
490 | case Tok_tr: | 493 | case Tok_tr: |
491 | case Tok_trUtf8: | 494 | case Tok_trUtf8: |
492 | utf8 = ( yyTok == Tok_trUtf8 ); | 495 | utf8 = ( yyTok == Tok_trUtf8 ); |
493 | yyTok = getToken(); | 496 | yyTok = getToken(); |
494 | if ( match(Tok_LeftParen) && matchString(&text) ) { | 497 | if ( match(Tok_LeftParen) && matchString(&text) ) { |
495 | com = ""; | 498 | com = ""; |
496 | if ( match(Tok_RightParen) || (match(Tok_Comma) && | 499 | if ( match(Tok_RightParen) || (match(Tok_Comma) && |
497 | matchString(&com) && match(Tok_RightParen)) ) { | 500 | matchString(&com) && match(Tok_RightParen)) ) { |
498 | if ( prefix.isNull() ) { | 501 | if ( prefix.isNull() ) { |
499 | context = functionContext; | 502 | context = functionContext; |
500 | if ( !namespaces.isEmpty() ) | 503 | if ( !namespaces.isEmpty() ) |
501 | context.prepend( (namespaces.join(QString("::")) + | 504 | context.prepend( (namespaces.join(QString("::")) + |
502 | QString("::")).latin1() ); | 505 | QString("::")).latin1() ); |
503 | } else { | 506 | } else { |
504 | context = prefix; | 507 | context = prefix; |
505 | } | 508 | } |
506 | prefix = (const char *) 0; | 509 | prefix = (const char *) 0; |
507 | 510 | ||
508 | if ( qualifiedContexts.contains(context) ) | 511 | if ( qualifiedContexts.contains(context) ) |
509 | context = qualifiedContexts[context]; | 512 | context = qualifiedContexts[context]; |
510 | tor->insert( MetaTranslatorMessage(context, text, com, | 513 | tor->insert( MetaTranslatorMessage(context, text, com, |
511 | QString::null, utf8) ); | 514 | QString::null, utf8) ); |
512 | 515 | ||
513 | if ( lacks_Q_OBJECT.contains(context) ) { | 516 | if ( lacks_Q_OBJECT.contains(context) ) { |
514 | qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro", | 517 | qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro", |
515 | (const char *) yyFileName, yyLineNo, | 518 | (const char *) yyFileName, yyLineNo, |
516 | (const char *) context ); | 519 | (const char *) context ); |
517 | lacks_Q_OBJECT.remove( context ); | 520 | lacks_Q_OBJECT.remove( context ); |
518 | } else { | 521 | } else { |
519 | needs_Q_OBJECT.insert( context, 0 ); | 522 | needs_Q_OBJECT.insert( context, 0 ); |
520 | } | 523 | } |
521 | } | 524 | } |
522 | } | 525 | } |
523 | break; | 526 | break; |
524 | case Tok_translate: | 527 | case Tok_translate: |
525 | utf8 = FALSE; | 528 | utf8 = FALSE; |
526 | yyTok = getToken(); | 529 | yyTok = getToken(); |
527 | if ( match(Tok_LeftParen) && | 530 | if ( match(Tok_LeftParen) && |
528 | matchString(&context) && | 531 | matchString(&context) && |
529 | match(Tok_Comma) && | 532 | match(Tok_Comma) && |
530 | matchString(&text) ) { | 533 | matchString(&text) ) { |
531 | com = ""; | 534 | com = ""; |
532 | if ( match(Tok_RightParen) || | 535 | if ( match(Tok_RightParen) || |
533 | (match(Tok_Comma) && | 536 | (match(Tok_Comma) && |
534 | matchString(&com) && | 537 | matchString(&com) && |
535 | (match(Tok_RightParen) || | 538 | (match(Tok_RightParen) || |
536 | match(Tok_Comma) && | 539 | match(Tok_Comma) && |
537 | matchEncoding(&utf8) && | 540 | matchEncoding(&utf8) && |
538 | match(Tok_RightParen))) ) | 541 | match(Tok_RightParen))) ) |
539 | tor->insert( MetaTranslatorMessage(context, text, com, | 542 | tor->insert( MetaTranslatorMessage(context, text, com, |
540 | QString::null, utf8) ); | 543 | QString::null, utf8) ); |
541 | } | 544 | } |
542 | break; | 545 | break; |
543 | case Tok_Q_OBJECT: | 546 | case Tok_Q_OBJECT: |
544 | missing_Q_OBJECT = FALSE; | 547 | missing_Q_OBJECT = FALSE; |
545 | yyTok = getToken(); | 548 | yyTok = getToken(); |
546 | break; | 549 | break; |
547 | case Tok_Ident: | 550 | case Tok_Ident: |
548 | if ( !prefix.isNull() ) | 551 | if ( !prefix.isNull() ) |
549 | prefix += "::"; | 552 | prefix += "::"; |
550 | prefix += yyIdent; | 553 | prefix += yyIdent; |
551 | yyTok = getToken(); | 554 | yyTok = getToken(); |
552 | if ( yyTok != Tok_Gulbrandsen ) | 555 | if ( yyTok != Tok_Gulbrandsen ) |
553 | prefix = (const char *) 0; | 556 | prefix = (const char *) 0; |
554 | break; | 557 | break; |
555 | case Tok_Comment: | 558 | case Tok_Comment: |
556 | com = yyComment; | 559 | com = yyComment; |
557 | com = com.simplifyWhiteSpace(); | 560 | com = com.simplifyWhiteSpace(); |
558 | if ( com.left(sizeof(MagicComment) - 1) == MagicComment ) { | 561 | if ( com.left(sizeof(MagicComment) - 1) == MagicComment ) { |
559 | com.remove( 0, sizeof(MagicComment) - 1 ); | 562 | com.remove( 0, sizeof(MagicComment) - 1 ); |
560 | int k = com.find( ' ' ); | 563 | int k = com.find( ' ' ); |
561 | if ( k == -1 ) { | 564 | if ( k == -1 ) { |
562 | context = com; | 565 | context = com; |
563 | } else { | 566 | } else { |
564 | context = com.left( k ); | 567 | context = com.left( k ); |
565 | com.remove( 0, k + 1 ); | 568 | com.remove( 0, k + 1 ); |
566 | tor->insert( MetaTranslatorMessage(context, "", com, | 569 | tor->insert( MetaTranslatorMessage(context, "", com, |
567 | QString::null, FALSE) ); | 570 | QString::null, FALSE) ); |
568 | } | 571 | } |
569 | 572 | ||
570 | /* | 573 | /* |
571 | Provide a backdoor for people using "using | 574 | Provide a backdoor for people using "using |
572 | namespace". See the manual for details. | 575 | namespace". See the manual for details. |
573 | */ | 576 | */ |
574 | k = 0; | 577 | k = 0; |
575 | while ( (k = context.find("::", k)) != -1 ) { | 578 | while ( (k = context.find("::", k)) != -1 ) { |
576 | qualifiedContexts.insert( context.mid(k + 2), context ); | 579 | qualifiedContexts.insert( context.mid(k + 2), context ); |
577 | k++; | 580 | k++; |
578 | } | 581 | } |
579 | } | 582 | } |
580 | yyTok = getToken(); | 583 | yyTok = getToken(); |
581 | break; | 584 | break; |
582 | case Tok_Arrow: | 585 | case Tok_Arrow: |
583 | yyTok = getToken(); | 586 | yyTok = getToken(); |
584 | if ( yyTok == Tok_tr || yyTok == Tok_trUtf8 ) | 587 | if ( yyTok == Tok_tr || yyTok == Tok_trUtf8 ) |
585 | qWarning( "%s:%d: Cannot invoke tr() like this", | 588 | qWarning( "%s:%d: Cannot invoke tr() like this", |
586 | (const char *) yyFileName, yyLineNo ); | 589 | (const char *) yyFileName, yyLineNo ); |
587 | break; | 590 | break; |
588 | case Tok_Gulbrandsen: | 591 | case Tok_Gulbrandsen: |
589 | // at top level? | 592 | // at top level? |
590 | if ( yyBraceDepth == (int) namespaces.count() && yyParenDepth == 0 ) | 593 | if ( yyBraceDepth == (int) namespaces.count() && yyParenDepth == 0 ) |
591 | functionContext = prefix; | 594 | functionContext = prefix; |
592 | yyTok = getToken(); | 595 | yyTok = getToken(); |
593 | break; | 596 | break; |
594 | case Tok_RightBrace: | 597 | case Tok_RightBrace: |
595 | case Tok_Semicolon: | 598 | case Tok_Semicolon: |
596 | if ( yyBraceDepth >= 0 && | 599 | if ( yyBraceDepth >= 0 && |
597 | yyBraceDepth + 1 == (int) namespaces.count() ) | 600 | yyBraceDepth + 1 == (int) namespaces.count() ) |
598 | namespaces.remove( namespaces.fromLast() ); | 601 | namespaces.remove( namespaces.fromLast() ); |
599 | if ( yyBraceDepth == (int) namespaces.count() ) { | 602 | if ( yyBraceDepth == (int) namespaces.count() ) { |
600 | if ( missing_Q_OBJECT ) { | 603 | if ( missing_Q_OBJECT ) { |
601 | if ( needs_Q_OBJECT.contains(functionContext) ) { | 604 | if ( needs_Q_OBJECT.contains(functionContext) ) { |
602 | qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro", | 605 | qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro", |
603 | (const char *) yyFileName, yyLineNo, | 606 | (const char *) yyFileName, yyLineNo, |
604 | (const char *) functionContext ); | 607 | (const char *) functionContext ); |
605 | } else { | 608 | } else { |
606 | lacks_Q_OBJECT.insert( functionContext, 0 ); | 609 | lacks_Q_OBJECT.insert( functionContext, 0 ); |
607 | } | 610 | } |
608 | } | 611 | } |
609 | functionContext = defaultContext; | 612 | functionContext = defaultContext; |
610 | missing_Q_OBJECT = FALSE; | 613 | missing_Q_OBJECT = FALSE; |
611 | } | 614 | } |
612 | yyTok = getToken(); | 615 | yyTok = getToken(); |
613 | break; | 616 | break; |
614 | default: | 617 | default: |
615 | yyTok = getToken(); | 618 | yyTok = getToken(); |
616 | } | 619 | } |
617 | } | 620 | } |
618 | 621 | ||
619 | if ( yyBraceDepth != 0 ) | 622 | if ( yyBraceDepth != 0 ) |
620 | fprintf( stderr, | 623 | fprintf( stderr, |
621 | "%s: Unbalanced braces in C++ code (or abuse of the C++" | 624 | "%s: Unbalanced braces in C++ code (or abuse of the C++" |
622 | " preprocessor)\n", | 625 | " preprocessor)\n", |
623 | (const char *) yyFileName ); | 626 | (const char *) yyFileName ); |
624 | if ( yyParenDepth != 0 ) | 627 | if ( yyParenDepth != 0 ) |
625 | fprintf( stderr, | 628 | fprintf( stderr, |
626 | "%s: Unbalanced parentheses in C++ code (or abuse of the C++" | 629 | "%s: Unbalanced parentheses in C++ code (or abuse of the C++" |
627 | " preprocessor)\n", | 630 | " preprocessor)\n", |
628 | (const char *) yyFileName ); | 631 | (const char *) yyFileName ); |
629 | } | 632 | } |
630 | 633 | ||
631 | void fetchtr_cpp( const char *fileName, MetaTranslator *tor, | 634 | void fetchtr_cpp( const char *fileName, MetaTranslator *tor, |
632 | const char *defaultContext, bool mustExist ) | 635 | const char *defaultContext, bool mustExist ) |
633 | { | 636 | { |
634 | yyInFile = fopen( fileName, "r" ); | 637 | yyInFile = fopen( fileName, "r" ); |
635 | if ( yyInFile == 0 ) { | 638 | if ( yyInFile == 0 ) { |
636 | if ( mustExist ) | 639 | if ( mustExist ) |
637 | fprintf( stderr, | 640 | fprintf( stderr, |
638 | "lupdate error: Cannot open C++ source file '%s': %s\n", | 641 | "lupdate error: Cannot open C++ source file '%s': %s\n", |
639 | fileName, strerror(errno) ); | 642 | fileName, strerror(errno) ); |
640 | return; | 643 | return; |
641 | } | 644 | } |
642 | 645 | ||
643 | startTokenizer( fileName, getCharFromFile ); | 646 | startTokenizer( fileName, getCharFromFile ); |
644 | parse( tor, 0, defaultContext ); | 647 | parse( tor, 0, defaultContext ); |
645 | fclose( yyInFile ); | 648 | fclose( yyInFile ); |
646 | } | 649 | } |
647 | 650 | ||
648 | /* | 651 | /* |
649 | In addition to C++, we support Qt Designer UI files. | 652 | In addition to C++, we support Qt Designer UI files. |
650 | */ | 653 | */ |
651 | 654 | ||
652 | /* | 655 | /* |
653 | Fetches tr() calls in C++ code in UI files (inside "<function>" | 656 | Fetches tr() calls in C++ code in UI files (inside "<function>" |
654 | tag). This mechanism is obsolete. | 657 | tag). This mechanism is obsolete. |
655 | */ | 658 | */ |
656 | void fetchtr_inlined_cpp( const char *fileName, const QString& in, | 659 | void fetchtr_inlined_cpp( const char *fileName, const QString& in, |
657 | MetaTranslator *tor, const char *context ) | 660 | MetaTranslator *tor, const char *context ) |
658 | { | 661 | { |
659 | yyInStr = in; | 662 | yyInStr = in; |
660 | startTokenizer( fileName, getCharFromString ); | 663 | startTokenizer( fileName, getCharFromString ); |
661 | parse( tor, context, 0 ); | 664 | parse( tor, context, 0 ); |
662 | yyInStr = QString::null; | 665 | yyInStr = QString::null; |
663 | } | 666 | } |
664 | 667 | ||
665 | class UiHandler : public QXmlDefaultHandler | 668 | class UiHandler : public QXmlDefaultHandler |
666 | { | 669 | { |
667 | public: | 670 | public: |
668 | UiHandler( MetaTranslator *translator, const char *fileName ) | 671 | UiHandler( MetaTranslator *translator, const char *fileName ) |
669 | : tor( translator ), fname( fileName ), comment( "" ) { } | 672 | : tor( translator ), fname( fileName ), comment( "" ) { } |
670 | 673 | ||
671 | virtual bool startElement( const QString& namespaceURI, | 674 | virtual bool startElement( const QString& namespaceURI, |
672 | const QString& localName, const QString& qName, | 675 | const QString& localName, const QString& qName, |
673 | const QXmlAttributes& atts ); | 676 | const QXmlAttributes& atts ); |
674 | virtual bool endElement( const QString& namespaceURI, | 677 | virtual bool endElement( const QString& namespaceURI, |
675 | const QString& localName, const QString& qName ); | 678 | const QString& localName, const QString& qName ); |
676 | virtual bool characters( const QString& ch ); | 679 | virtual bool characters( const QString& ch ); |
677 | virtual bool fatalError( const QXmlParseException& exception ); | 680 | virtual bool fatalError( const QXmlParseException& exception ); |
678 | 681 | ||
679 | private: | 682 | private: |
680 | void flush(); | 683 | void flush(); |
681 | 684 | ||
682 | MetaTranslator *tor; | 685 | MetaTranslator *tor; |
683 | QCString fname; | 686 | QCString fname; |
684 | QString context; | 687 | QString context; |
685 | QString source; | 688 | QString source; |
686 | QString comment; | 689 | QString comment; |
687 | 690 | ||
688 | QString accum; | 691 | QString accum; |
689 | }; | 692 | }; |
690 | 693 | ||
691 | bool UiHandler::startElement( const QString& /* namespaceURI */, | 694 | bool UiHandler::startElement( const QString& /* namespaceURI */, |
692 | const QString& /* localName */, | 695 | const QString& /* localName */, |
693 | const QString& qName, | 696 | const QString& qName, |
694 | const QXmlAttributes& atts ) | 697 | const QXmlAttributes& atts ) |
695 | { | 698 | { |
696 | if ( qName == QString("item") ) { | 699 | if ( qName == QString("item") ) { |
697 | flush(); | 700 | flush(); |
698 | if ( !atts.value(QString("text")).isEmpty() ) | 701 | if ( !atts.value(QString("text")).isEmpty() ) |
699 | source = atts.value( QString("text") ); | 702 | source = atts.value( QString("text") ); |
700 | } else if ( qName == QString("string") ) { | 703 | } else if ( qName == QString("string") ) { |
701 | flush(); | 704 | flush(); |
702 | } | 705 | } |
703 | accum.truncate( 0 ); | 706 | accum.truncate( 0 ); |
704 | return TRUE; | 707 | return TRUE; |
705 | } | 708 | } |
706 | 709 | ||
707 | bool UiHandler::endElement( const QString& /* namespaceURI */, | 710 | bool UiHandler::endElement( const QString& /* namespaceURI */, |
708 | const QString& /* localName */, | 711 | const QString& /* localName */, |
709 | const QString& qName ) | 712 | const QString& qName ) |
710 | { | 713 | { |
711 | accum.replace( QRegExp(QString("\r\n")), "\n" ); | 714 | accum.replace( QRegExp(QString("\r\n")), "\n" ); |
712 | 715 | ||
713 | if ( qName == QString("class") ) { | 716 | if ( qName == QString("class") ) { |
714 | if ( context.isEmpty() ) | 717 | if ( context.isEmpty() ) |
715 | context = accum; | 718 | context = accum; |
716 | } else if ( qName == QString("string") ) { | 719 | } else if ( qName == QString("string") ) { |
717 | source = accum; | 720 | source = accum; |
718 | } else if ( qName == QString("comment") ) { | 721 | } else if ( qName == QString("comment") ) { |
719 | comment = accum; | 722 | comment = accum; |
720 | flush(); | 723 | flush(); |
721 | } else if ( qName == QString("function") ) { | 724 | } else if ( qName == QString("function") ) { |
722 | fetchtr_inlined_cpp( (const char *) fname, accum, tor, | 725 | fetchtr_inlined_cpp( (const char *) fname, accum, tor, |
723 | context.latin1() ); | 726 | context.latin1() ); |
724 | } else { | 727 | } else { |
725 | flush(); | 728 | flush(); |
726 | } | 729 | } |
727 | return TRUE; | 730 | return TRUE; |
728 | } | 731 | } |
729 | 732 | ||
730 | bool UiHandler::characters( const QString& ch ) | 733 | bool UiHandler::characters( const QString& ch ) |
731 | { | 734 | { |
732 | accum += ch; | 735 | accum += ch; |
733 | return TRUE; | 736 | return TRUE; |
734 | } | 737 | } |
735 | 738 | ||
736 | bool UiHandler::fatalError( const QXmlParseException& exception ) | 739 | bool UiHandler::fatalError( const QXmlParseException& exception ) |
737 | { | 740 | { |
738 | QString msg; | 741 | QString msg; |
739 | msg.sprintf( "Parse error at line %d, column %d (%s).", | 742 | msg.sprintf( "Parse error at line %d, column %d (%s).", |
740 | exception.lineNumber(), exception.columnNumber(), | 743 | exception.lineNumber(), exception.columnNumber(), |
741 | exception.message().latin1() ); | 744 | exception.message().latin1() ); |
742 | fprintf( stderr, "XML error: %s\n", msg.latin1() ); | 745 | fprintf( stderr, "XML error: %s\n", msg.latin1() ); |
743 | return FALSE; | 746 | return FALSE; |
744 | } | 747 | } |
745 | 748 | ||
746 | void UiHandler::flush() | 749 | void UiHandler::flush() |
747 | { | 750 | { |
748 | if ( !context.isEmpty() && !source.isEmpty() ) | 751 | if ( !context.isEmpty() && !source.isEmpty() ) |
749 | tor->insert( MetaTranslatorMessage(context.utf8(), source.utf8(), | 752 | tor->insert( MetaTranslatorMessage(context.utf8(), source.utf8(), |
750 | comment.utf8(), QString::null, | 753 | comment.utf8(), QString::null, |
751 | TRUE) ); | 754 | TRUE) ); |
752 | source.truncate( 0 ); | 755 | source.truncate( 0 ); |
753 | comment.truncate( 0 ); | 756 | comment.truncate( 0 ); |
754 | } | 757 | } |
755 | 758 | ||
756 | void fetchtr_ui( const char *fileName, MetaTranslator *tor, | 759 | void fetchtr_ui( const char *fileName, MetaTranslator *tor, |
757 | const char * /* defaultContext */, bool mustExist ) | 760 | const char * /* defaultContext */, bool mustExist ) |
758 | { | 761 | { |
759 | QFile f( fileName ); | 762 | QFile f( fileName ); |
760 | if ( !f.open(IO_ReadOnly) ) { | 763 | if ( !f.open(IO_ReadOnly) ) { |
761 | if ( mustExist ) | 764 | if ( mustExist ) |
762 | fprintf( stderr, "lupdate error: cannot open UI file '%s': %s\n", | 765 | fprintf( stderr, "lupdate error: cannot open UI file '%s': %s\n", |
763 | fileName, strerror(errno) ); | 766 | fileName, strerror(errno) ); |
764 | return; | 767 | return; |
765 | } | 768 | } |
766 | 769 | ||
767 | QTextStream t( &f ); | 770 | QTextStream t( &f ); |
768 | QXmlInputSource in( t ); | 771 | QXmlInputSource in( t ); |
769 | QXmlSimpleReader reader; | 772 | QXmlSimpleReader reader; |
770 | reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE ); | 773 | reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE ); |
771 | reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE ); | 774 | reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE ); |
772 | reader.setFeature( "http://trolltech.com/xml/features/report-whitespace" | 775 | reader.setFeature( "http://trolltech.com/xml/features/report-whitespace" |
773 | "-only-CharData", FALSE ); | 776 | "-only-CharData", FALSE ); |
774 | QXmlDefaultHandler *hand = new UiHandler( tor, fileName ); | 777 | QXmlDefaultHandler *hand = new UiHandler( tor, fileName ); |
775 | reader.setContentHandler( hand ); | 778 | reader.setContentHandler( hand ); |
776 | reader.setErrorHandler( hand ); | 779 | reader.setErrorHandler( hand ); |
777 | 780 | ||
778 | if ( !reader.parse(in) ) | 781 | if ( !reader.parse(in) ) |
779 | fprintf( stderr, "%s: Parse error in UI file\n", fileName ); | 782 | fprintf( stderr, "%s: Parse error in UI file\n", fileName ); |
780 | reader.setContentHandler( 0 ); | 783 | reader.setContentHandler( 0 ); |
781 | reader.setErrorHandler( 0 ); | 784 | reader.setErrorHandler( 0 ); |
782 | delete hand; | 785 | delete hand; |
783 | f.close(); | 786 | f.close(); |
784 | } | 787 | } |