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