summaryrefslogtreecommitdiffstats
path: root/tools/linguist/shared
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2011-07-10 15:24:15 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2011-07-10 15:24:15 -0500
commitbd0f3345a938b35ce6a12f6150373b0955b8dd12 (patch)
tree7a520322212d48ebcb9fbe1087e7fca28b76185c /tools/linguist/shared
downloadqt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.tar.gz
qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.zip
Add Qt3 development HEAD version
Diffstat (limited to 'tools/linguist/shared')
-rw-r--r--tools/linguist/shared/metatranslator.cpp601
-rw-r--r--tools/linguist/shared/metatranslator.h120
-rw-r--r--tools/linguist/shared/proparser.cpp217
-rw-r--r--tools/linguist/shared/proparser.h42
4 files changed, 980 insertions, 0 deletions
diff --git a/tools/linguist/shared/metatranslator.cpp b/tools/linguist/shared/metatranslator.cpp
new file mode 100644
index 0000000..85f6199
--- /dev/null
+++ b/tools/linguist/shared/metatranslator.cpp
@@ -0,0 +1,601 @@
+/**********************************************************************
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of Qt Linguist.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with
+** the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "metatranslator.h"
+
+#include <qapplication.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qmessagebox.h>
+#include <qtextcodec.h>
+#include <qtextstream.h>
+#include <qxml.h>
+
+static bool encodingIsUtf8( const QXmlAttributes& atts )
+{
+ for ( int i = 0; i < atts.length(); i++ ) {
+ // utf8="true" is a pre-3.0 syntax
+ if ( atts.qName(i) == QString("utf8") ) {
+ return ( atts.value(i) == QString("true") );
+ } else if ( atts.qName(i) == QString("encoding") ) {
+ return ( atts.value(i) == QString("UTF-8") );
+ }
+ }
+ return FALSE;
+}
+
+class TsHandler : public QXmlDefaultHandler
+{
+public:
+ TsHandler( MetaTranslator *translator )
+ : tor( translator ), type( MetaTranslatorMessage::Finished ),
+ inMessage( FALSE ), ferrorCount( 0 ), contextIsUtf8( FALSE ),
+ messageIsUtf8( FALSE ) { }
+
+ virtual bool startElement( const QString& namespaceURI,
+ const QString& localName, const QString& qName,
+ const QXmlAttributes& atts );
+ virtual bool endElement( const QString& namespaceURI,
+ const QString& localName, const QString& qName );
+ virtual bool characters( const QString& ch );
+ virtual bool fatalError( const QXmlParseException& exception );
+
+private:
+ MetaTranslator *tor;
+ MetaTranslatorMessage::Type type;
+ bool inMessage;
+ QString context;
+ QString source;
+ QString comment;
+ QString translation;
+
+ QString accum;
+ int ferrorCount;
+ bool contextIsUtf8;
+ bool messageIsUtf8;
+};
+
+bool TsHandler::startElement( const QString& /* namespaceURI */,
+ const QString& /* localName */,
+ const QString& qName,
+ const QXmlAttributes& atts )
+{
+ if ( qName == QString("byte") ) {
+ for ( int i = 0; i < atts.length(); i++ ) {
+ if ( atts.qName(i) == QString("value") ) {
+ QString value = atts.value( i );
+ int base = 10;
+ if ( value.startsWith("x") ) {
+ base = 16;
+ value = value.mid( 1 );
+ }
+ int n = value.toUInt( 0, base );
+ if ( n != 0 )
+ accum += QChar( n );
+ }
+ }
+ } else {
+ if ( qName == QString("context") ) {
+ context.truncate( 0 );
+ source.truncate( 0 );
+ comment.truncate( 0 );
+ translation.truncate( 0 );
+ contextIsUtf8 = encodingIsUtf8( atts );
+ } else if ( qName == QString("message") ) {
+ inMessage = TRUE;
+ type = MetaTranslatorMessage::Finished;
+ source.truncate( 0 );
+ comment.truncate( 0 );
+ translation.truncate( 0 );
+ messageIsUtf8 = encodingIsUtf8( atts );
+ } else if ( qName == QString("translation") ) {
+ for ( int i = 0; i < atts.length(); i++ ) {
+ if ( atts.qName(i) == QString("type") ) {
+ if ( atts.value(i) == QString("unfinished") )
+ type = MetaTranslatorMessage::Unfinished;
+ else if ( atts.value(i) == QString("obsolete") )
+ type = MetaTranslatorMessage::Obsolete;
+ else
+ type = MetaTranslatorMessage::Finished;
+ }
+ }
+ }
+ accum.truncate( 0 );
+ }
+ return TRUE;
+}
+
+bool TsHandler::endElement( const QString& /* namespaceURI */,
+ const QString& /* localName */,
+ const QString& qName )
+{
+ if ( qName == QString("codec") || qName == QString("defaultcodec") ) {
+ // "codec" is a pre-3.0 syntax
+ tor->setCodec( accum );
+ } else if ( qName == QString("name") ) {
+ context = accum;
+ } else if ( qName == QString("source") ) {
+ source = accum;
+ } else if ( qName == QString("comment") ) {
+ if ( inMessage ) {
+ comment = accum;
+ } else {
+ if ( contextIsUtf8 )
+ tor->insert( MetaTranslatorMessage(context.utf8(),
+ ContextComment,
+ accum.utf8(), QString::null, TRUE,
+ MetaTranslatorMessage::Unfinished) );
+ else
+ tor->insert( MetaTranslatorMessage(context.ascii(),
+ ContextComment,
+ accum.ascii(), QString::null, FALSE,
+ MetaTranslatorMessage::Unfinished) );
+ }
+ } else if ( qName == QString("translation") ) {
+ translation = accum;
+ } else if ( qName == QString("message") ) {
+ if ( messageIsUtf8 )
+ tor->insert( MetaTranslatorMessage(context.utf8(), source.utf8(),
+ comment.utf8(), translation,
+ TRUE, type) );
+ else
+ tor->insert( MetaTranslatorMessage(context.ascii(), source.ascii(),
+ comment.ascii(), translation,
+ FALSE, type) );
+ inMessage = FALSE;
+ }
+ return TRUE;
+}
+
+bool TsHandler::characters( const QString& ch )
+{
+ QString t = ch;
+ t.replace( "\r", "" );
+ accum += t;
+ return TRUE;
+}
+
+bool TsHandler::fatalError( const QXmlParseException& exception )
+{
+ if ( ferrorCount++ == 0 ) {
+ QString msg;
+ msg.sprintf( "Parse error at line %d, column %d (%s).",
+ exception.lineNumber(), exception.columnNumber(),
+ exception.message().latin1() );
+ if ( qApp == 0 )
+ fprintf( stderr, "XML error: %s\n", msg.latin1() );
+ else
+ QMessageBox::information( qApp->mainWidget(),
+ QObject::tr("Qt Linguist"), msg );
+ }
+ return FALSE;
+}
+
+static QString numericEntity( int ch )
+{
+ return QString( ch <= 0x20 ? "<byte value=\"x%1\"/>" : "&#x%1;" )
+ .arg( ch, 0, 16 );
+}
+
+static QString protect( const QCString& str )
+{
+ QString result;
+ int len = (int) str.length();
+ for ( int k = 0; k < len; k++ ) {
+ switch( str[k] ) {
+ case '\"':
+ result += QString( "&quot;" );
+ break;
+ case '&':
+ result += QString( "&amp;" );
+ break;
+ case '>':
+ result += QString( "&gt;" );
+ break;
+ case '<':
+ result += QString( "&lt;" );
+ break;
+ case '\'':
+ result += QString( "&apos;" );
+ break;
+ default:
+ if ( (uchar) str[k] < 0x20 && str[k] != '\n' )
+ result += numericEntity( (uchar) str[k] );
+ else
+ result += str[k];
+ }
+ }
+ return result;
+}
+
+static QString evilBytes( const QCString& str, bool utf8 )
+{
+ if ( utf8 ) {
+ return protect( str );
+ } else {
+ QString result;
+ QCString t = protect( str ).latin1();
+ int len = (int) t.length();
+ for ( int k = 0; k < len; k++ ) {
+ if ( (uchar) t[k] >= 0x7f )
+ result += numericEntity( (uchar) t[k] );
+ else
+ result += QChar( t[k] );
+ }
+ return result;
+ }
+}
+
+MetaTranslatorMessage::MetaTranslatorMessage()
+ : utfeight( FALSE ), ty( Unfinished )
+{
+}
+
+MetaTranslatorMessage::MetaTranslatorMessage( const char *context,
+ const char *sourceText,
+ const char *comment,
+ const QString& translation,
+ bool utf8, Type type )
+ : QTranslatorMessage( context, sourceText, comment, translation ),
+ utfeight( FALSE ), ty( type )
+{
+ /*
+ Don't use UTF-8 if it makes no difference. UTF-8 should be
+ reserved for the real problematic case: non-ASCII (possibly
+ non-Latin-1) characters in .ui files.
+ */
+ if ( utf8 ) {
+ if ( sourceText != 0 ) {
+ int i = 0;
+ while ( sourceText[i] != '\0' ) {
+ if ( (uchar) sourceText[i] >= 0x80 ) {
+ utfeight = TRUE;
+ break;
+ }
+ i++;
+ }
+ }
+ if ( !utfeight && comment != 0 ) {
+ int i = 0;
+ while ( comment[i] != '\0' ) {
+ if ( (uchar) comment[i] >= 0x80 ) {
+ utfeight = TRUE;
+ break;
+ }
+ i++;
+ }
+ }
+ }
+}
+
+MetaTranslatorMessage::MetaTranslatorMessage( const MetaTranslatorMessage& m )
+ : QTranslatorMessage( m ), utfeight( m.utfeight ), ty( m.ty )
+{
+}
+
+MetaTranslatorMessage& MetaTranslatorMessage::operator=(
+ const MetaTranslatorMessage& m )
+{
+ QTranslatorMessage::operator=( m );
+ utfeight = m.utfeight;
+ ty = m.ty;
+ return *this;
+}
+
+bool MetaTranslatorMessage::operator==( const MetaTranslatorMessage& m ) const
+{
+ return qstrcmp( context(), m.context() ) == 0 &&
+ qstrcmp( sourceText(), m.sourceText() ) == 0 &&
+ qstrcmp( comment(), m.comment() ) == 0;
+}
+
+bool MetaTranslatorMessage::operator<( const MetaTranslatorMessage& m ) const
+{
+ int delta = qstrcmp( context(), m.context() );
+ if ( delta == 0 )
+ delta = qstrcmp( sourceText(), m.sourceText() );
+ if ( delta == 0 )
+ delta = qstrcmp( comment(), m.comment() );
+ return delta < 0;
+}
+
+MetaTranslator::MetaTranslator()
+{
+ clear();
+}
+
+MetaTranslator::MetaTranslator( const MetaTranslator& tor )
+ : mm( tor.mm ), codecName( tor.codecName ), codec( tor.codec )
+{
+}
+
+MetaTranslator& MetaTranslator::operator=( const MetaTranslator& tor )
+{
+ mm = tor.mm;
+ codecName = tor.codecName;
+ codec = tor.codec;
+ return *this;
+}
+
+void MetaTranslator::clear()
+{
+ mm.clear();
+ codecName = "ISO-8859-1";
+ codec = 0;
+}
+
+bool MetaTranslator::load( const QString& filename )
+{
+ QFile f( filename );
+ if ( !f.open(IO_ReadOnly) )
+ return FALSE;
+
+ QTextStream t( &f );
+ QXmlInputSource in( t );
+ QXmlSimpleReader reader;
+ reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE );
+ reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE );
+ QXmlDefaultHandler *hand = new TsHandler( this );
+ reader.setContentHandler( hand );
+ reader.setErrorHandler( hand );
+
+ bool ok = reader.parse( in );
+ reader.setContentHandler( 0 );
+ reader.setErrorHandler( 0 );
+ delete hand;
+ f.close();
+ return ok;
+}
+
+bool MetaTranslator::save( const QString& filename ) const
+{
+ QFile f( filename );
+ if ( !f.open(IO_WriteOnly) )
+ return FALSE;
+
+ QTextStream t( &f );
+ t.setCodec( QTextCodec::codecForName("ISO-8859-1") );
+
+ t << "<!DOCTYPE TS><TS>\n";
+ if ( codecName != "ISO-8859-1" )
+ t << "<defaultcodec>" << codecName << "</defaultcodec>\n";
+ TMM::ConstIterator m = mm.begin();
+ while ( m != mm.end() ) {
+ TMMInv inv;
+ TMMInv::Iterator i;
+ bool contextIsUtf8 = m.key().utf8();
+ QCString context = m.key().context();
+ QCString comment = "";
+
+ do {
+ if ( QCString(m.key().sourceText()) == ContextComment ) {
+ if ( m.key().type() != MetaTranslatorMessage::Obsolete ) {
+ contextIsUtf8 = m.key().utf8();
+ comment = QCString( m.key().comment() );
+ }
+ } else {
+ inv.insert( *m, m.key() );
+ }
+ } while ( ++m != mm.end() && QCString(m.key().context()) == context );
+
+ t << "<context";
+ if ( contextIsUtf8 )
+ t << " encoding=\"UTF-8\"";
+ t << ">\n";
+ t << " <name>" << evilBytes( context, contextIsUtf8 )
+ << "</name>\n";
+ if ( !comment.isEmpty() )
+ t << " <comment>" << evilBytes( comment, contextIsUtf8 )
+ << "</comment>\n";
+
+ for ( i = inv.begin(); i != inv.end(); ++i ) {
+ // no need for such noise
+ if ( (*i).type() == MetaTranslatorMessage::Obsolete &&
+ (*i).translation().isEmpty() )
+ continue;
+
+ t << " <message";
+ if ( (*i).utf8() )
+ t << " encoding=\"UTF-8\"";
+ t << ">\n"
+ << " <source>" << evilBytes( (*i).sourceText(),
+ (*i).utf8() )
+ << "</source>\n";
+ if ( !QCString((*i).comment()).isEmpty() )
+ t << " <comment>" << evilBytes( (*i).comment(),
+ (*i).utf8() )
+ << "</comment>\n";
+ t << " <translation";
+ if ( (*i).type() == MetaTranslatorMessage::Unfinished )
+ t << " type=\"unfinished\"";
+ else if ( (*i).type() == MetaTranslatorMessage::Obsolete )
+ t << " type=\"obsolete\"";
+ t << ">" << protect( (*i).translation().utf8() )
+ << "</translation>\n";
+ t << " </message>\n";
+ }
+ t << "</context>\n";
+ }
+ t << "</TS>\n";
+ f.close();
+ return TRUE;
+}
+
+bool MetaTranslator::release( const QString& filename, bool verbose,
+ QTranslator::SaveMode mode ) const
+{
+ QTranslator tor( 0 );
+ int finished = 0;
+ int unfinished = 0;
+ int untranslated = 0;
+ TMM::ConstIterator m;
+
+ for ( m = mm.begin(); m != mm.end(); ++m ) {
+ if ( m.key().type() != MetaTranslatorMessage::Obsolete ) {
+ if ( m.key().translation().isEmpty() ) {
+ untranslated++;
+ } else {
+ if ( m.key().type() == MetaTranslatorMessage::Unfinished )
+ unfinished++;
+ else
+ finished++;
+
+ QCString context = m.key().context();
+ QCString sourceText = m.key().sourceText();
+ QCString comment = m.key().comment();
+ QString translation = m.key().translation();
+
+ /*
+ Drop the comment in (context, sourceText, comment),
+ unless (context, sourceText, "") already exists, or
+ unless we already dropped the comment of (context,
+ sourceText, comment0).
+ */
+ if ( comment.isEmpty()
+ || contains(context, sourceText, "")
+ || !tor.findMessage(context, sourceText, "").translation()
+ .isNull() ) {
+ tor.insert( m.key() );
+ } else {
+ tor.insert( QTranslatorMessage(context, sourceText, "",
+ translation) );
+ }
+ }
+ }
+ }
+
+ bool saved = tor.save( filename, mode );
+ if ( saved && verbose )
+ fprintf( stderr,
+ " %d finished, %d unfinished and %d untranslated messages\n",
+ finished, unfinished, untranslated );
+
+ return saved;
+}
+
+bool MetaTranslator::contains( const char *context, const char *sourceText,
+ const char *comment ) const
+{
+ return mm.find( MetaTranslatorMessage(context, sourceText, comment) ) !=
+ mm.end();
+}
+
+void MetaTranslator::insert( const MetaTranslatorMessage& m )
+{
+ int pos = (int)mm.count();
+ TMM::Iterator n = mm.find( m );
+ if ( n != mm.end() )
+ pos = *n;
+ mm.replace( m, pos );
+}
+
+void MetaTranslator::stripObsoleteMessages()
+{
+ TMM newmm;
+
+ TMM::Iterator m = mm.begin();
+ while ( m != mm.end() ) {
+ if ( m.key().type() != MetaTranslatorMessage::Obsolete )
+ newmm.insert( m.key(), *m );
+ ++m;
+ }
+ mm = newmm;
+}
+
+void MetaTranslator::stripEmptyContexts()
+{
+ TMM newmm;
+
+ TMM::Iterator m = mm.begin();
+ while ( m != mm.end() ) {
+ if ( QCString(m.key().sourceText()) == ContextComment ) {
+ TMM::Iterator n = m;
+ ++n;
+ // the context comment is followed by other messages
+ if ( n != newmm.end() &&
+ qstrcmp(m.key().context(), n.key().context()) == 0 )
+ newmm.insert( m.key(), *m );
+ } else {
+ newmm.insert( m.key(), *m );
+ }
+ ++m;
+ }
+ mm = newmm;
+}
+
+void MetaTranslator::setCodec( const char *name )
+{
+ const int latin1 = 4;
+
+ codecName = name;
+ codec = QTextCodec::codecForName( name );
+ if ( codec == 0 || codec->mibEnum() == latin1 )
+ codec = 0;
+}
+
+QString MetaTranslator::toUnicode( const char *str, bool utf8 ) const
+{
+ if ( utf8 )
+ return QString::fromUtf8( str );
+ else if ( codec == 0 )
+ return QString( str );
+ else
+ return codec->toUnicode( str );
+}
+
+QValueList<MetaTranslatorMessage> MetaTranslator::messages() const
+{
+ int n = (int)mm.count();
+ TMM::ConstIterator *t = new TMM::ConstIterator[n + 1];
+ TMM::ConstIterator m;
+ for ( m = mm.begin(); m != mm.end(); ++m )
+ t[*m] = m;
+
+ QValueList<MetaTranslatorMessage> val;
+ for ( int i = 0; i < n; i++ )
+ val.append( t[i].key() );
+
+ delete[] t;
+ return val;
+}
+
+QValueList<MetaTranslatorMessage> MetaTranslator::translatedMessages() const
+{
+ QValueList<MetaTranslatorMessage> val;
+ TMM::ConstIterator m;
+ for ( m = mm.begin(); m != mm.end(); ++m ) {
+ if ( m.key().type() == MetaTranslatorMessage::Finished )
+ val.append( m.key() );
+ }
+ return val;
+}
diff --git a/tools/linguist/shared/metatranslator.h b/tools/linguist/shared/metatranslator.h
new file mode 100644
index 0000000..25adfb0
--- /dev/null
+++ b/tools/linguist/shared/metatranslator.h
@@ -0,0 +1,120 @@
+/**********************************************************************
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of Qt Linguist.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with
+** the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef METATRANSLATOR_H
+#define METATRANSLATOR_H
+
+#include <qmap.h>
+#include <qstring.h>
+#include <qtranslator.h>
+#include <qvaluelist.h>
+
+class QTextCodec;
+
+class MetaTranslatorMessage : public QTranslatorMessage
+{
+public:
+ enum Type { Unfinished, Finished, Obsolete };
+
+ MetaTranslatorMessage();
+ MetaTranslatorMessage( const char *context, const char *sourceText,
+ const char *comment,
+ const QString& translation = QString::null,
+ bool utf8 = FALSE, Type type = Unfinished );
+ MetaTranslatorMessage( const MetaTranslatorMessage& m );
+
+ MetaTranslatorMessage& operator=( const MetaTranslatorMessage& m );
+
+ void setType( Type nt ) { ty = nt; }
+ Type type() const { return ty; }
+ bool utf8() const { return utfeight; }
+
+ bool operator==( const MetaTranslatorMessage& m ) const;
+ bool operator!=( const MetaTranslatorMessage& m ) const
+ { return !operator==( m ); }
+ bool operator<( const MetaTranslatorMessage& m ) const;
+ bool operator<=( const MetaTranslatorMessage& m )
+ { return !operator>( m ); }
+ bool operator>( const MetaTranslatorMessage& m ) const
+ { return this->operator<( m ); }
+ bool operator>=( const MetaTranslatorMessage& m ) const
+ { return !operator<( m ); }
+
+private:
+ bool utfeight;
+ Type ty;
+};
+
+class MetaTranslator
+{
+public:
+ MetaTranslator();
+ MetaTranslator( const MetaTranslator& tor );
+
+ MetaTranslator& operator=( const MetaTranslator& tor );
+
+ void clear();
+ bool load( const QString& filename );
+ bool save( const QString& filename ) const;
+ bool release( const QString& filename, bool verbose = FALSE,
+ QTranslator::SaveMode mode = QTranslator::Stripped ) const;
+
+ bool contains( const char *context, const char *sourceText,
+ const char *comment ) const;
+ void insert( const MetaTranslatorMessage& m );
+
+ void stripObsoleteMessages();
+ void stripEmptyContexts();
+
+ void setCodec( const char *name );
+ QString toUnicode( const char *str, bool utf8 ) const;
+
+ QValueList<MetaTranslatorMessage> messages() const;
+ QValueList<MetaTranslatorMessage> translatedMessages() const;
+
+private:
+ typedef QMap<MetaTranslatorMessage, int> TMM;
+ typedef QMap<int, MetaTranslatorMessage> TMMInv;
+
+ TMM mm;
+ QCString codecName;
+ QTextCodec *codec;
+};
+
+/*
+ This is a quick hack. The proper way to handle this would be
+ to extend MetaTranslator's interface.
+*/
+#define ContextComment "QT_LINGUIST_INTERNAL_CONTEXT_COMMENT"
+
+#endif
diff --git a/tools/linguist/shared/proparser.cpp b/tools/linguist/shared/proparser.cpp
new file mode 100644
index 0000000..7528361
--- /dev/null
+++ b/tools/linguist/shared/proparser.cpp
@@ -0,0 +1,217 @@
+/**********************************************************************
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of Qt Linguist.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with
+** the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "proparser.h"
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#endif
+
+#ifdef Q_OS_WIN32
+#define QT_POPEN _popen
+#else
+#define QT_POPEN popen
+#endif
+
+QString loadFile( const QString &fileName )
+{
+ QFile file( fileName );
+ if ( !file.open(IO_ReadOnly) ) {
+ fprintf( stderr, "error: Cannot load '%s': %s\n",
+ file.name().latin1(),
+ file.errorString().latin1() );
+ return QString();
+ }
+
+ QTextStream in( &file );
+ return in.read();
+}
+
+QMap<QString, QString> proFileTagMap( const QString& text )
+{
+ QString t = text;
+ QMap<QString, QString> tagMap;
+ bool stillProcess = true; // If include() has a $$tag then we need to reprocess
+
+ while(stillProcess) {
+
+ /*
+ Strip any commments before we try to include. We
+ still need to do it after we include to make sure the
+ included file does not have comments
+ */
+ t.replace( QRegExp(QString("#[^\n]*\n")), QString(" ") );
+
+ /*
+ Process include() commands.
+ $$PWD is a special case so we have to change it while
+ we know where the included file is.
+ */
+ QRegExp callToInclude("include\\s*\\(\\s*([^()\\s]+)\\s*\\)");
+ int i = 0;
+ while ( (i = callToInclude.search(t, i)) != -1 ) {
+ bool doneWithVar = false;
+ QString fileName = callToInclude.cap(1);
+ QString after = fileName.replace("$$PWD", QDir::currentDirPath());
+ if (!tagMap.isEmpty() && after.contains("$$")) {
+ QRegExp var( "\\$\\$[({]?([a-zA-Z0-9_]+)[)}]?" );
+ int ii = 0;
+ while ((ii = after.find(var, ii)) != -1) {
+ if (tagMap.contains(var.cap(1))) {
+ after.replace(ii, var.cap(0).length(), tagMap[var.cap(1)]);
+ } else { // Couldn't find it
+ doneWithVar = true;
+ break;
+ }
+ }
+
+ }
+ if (doneWithVar || !after.contains("$$")) {
+ after = loadFile(after);
+ QFileInfo fi(callToInclude.cap(1));
+ after.replace("$$PWD", fi.dirPath());
+ t.replace( i, callToInclude.matchedLength(), after );
+ }
+ i += after.length();
+ }
+
+ /*
+ Strip comments, merge lines ending with backslash, add
+ spaces around '=' and '+=', replace '\n' with ';', and
+ simplify white spaces.
+ */
+ t.replace( QRegExp(QString("#[^\n]*\n")), QString(" ") );
+ t.replace( QRegExp(QString("\\\\[^\n\\S]*\n")), QString(" ") );
+ t.replace( "=", QString(" = ") );
+ t.replace( "+ =", QString(" += ") );
+ t.replace( "\n", QString(";") );
+ t = t.simplifyWhiteSpace();
+
+ /*
+ Populate tagMap with 'key = value' entries.
+ */
+ QStringList lines = QStringList::split( QChar(';'), t );
+ QStringList::Iterator line;
+ for ( line = lines.begin(); line != lines.end(); ++line ) {
+ QStringList toks = QStringList::split( QChar(' '), *line );
+
+ if ( toks.count() >= 3 &&
+ (toks[1] == QString("=") || toks[1] == QString("+=")) ) {
+ QString tag = toks.first();
+ int k = tag.findRev( QChar(':') ); // as in 'unix:'
+ if ( k != -1 )
+ tag = tag.mid( k + 1 );
+ toks.remove( toks.begin() );
+
+ QString action = toks.first();
+ toks.remove( toks.begin() );
+
+ if ( tagMap.contains(tag) ) {
+ if ( action == QString("=") )
+ tagMap.replace( tag, toks.join(QChar(' ')) );
+ else
+ tagMap[tag] += QChar( ' ' ) + toks.join( QChar(' ') );
+ } else {
+ tagMap[tag] = toks.join( QChar(' ') );
+ }
+ }
+ }
+
+ /*
+ Expand $$variables within the 'value' part of a 'key = value'
+ pair.
+ */
+ QRegExp var( "\\$\\$[({]?([a-zA-Z0-9_]+)[)}]?" );
+ QMap<QString, QString>::Iterator it;
+ for ( it = tagMap.begin(); it != tagMap.end(); ++it ) {
+ int i = 0;
+ while ( (i = var.search((*it), i)) != -1 ) {
+ int len = var.matchedLength();
+ QString invocation = var.cap(1);
+ QString after;
+
+ if ( invocation == "system" ) {
+ // skip system(); it will be handled in the next pass
+ ++i;
+ } else {
+ if ( tagMap.contains(invocation) )
+ after = tagMap[invocation];
+ else if (invocation.lower() == "pwd")
+ after = QDir::currentDirPath();
+ (*it).replace( i, len, after );
+ i += after.length();
+ }
+ }
+ }
+
+ /*
+ Execute system() calls.
+ */
+ QRegExp callToSystem( "\\$\\$system\\s*\\(([^()]*)\\)" );
+ for ( it = tagMap.begin(); it != tagMap.end(); ++it ) {
+ int i = 0;
+ while ( (i = callToSystem.search((*it), i)) != -1 ) {
+ /*
+ This code is stolen from qmake's project.cpp file.
+ Ideally we would use the same parser, so we wouldn't
+ have this code duplication.
+ */
+ QString after;
+ char buff[256];
+ FILE *proc = QT_POPEN( callToSystem.cap(1).latin1(), "r" );
+ while ( proc && !feof(proc) ) {
+ int read_in = (int)fread( buff, 1, 255, proc );
+ if ( !read_in )
+ break;
+ for ( int i = 0; i < read_in; i++ ) {
+ if ( buff[i] == '\n' || buff[i] == '\t' )
+ buff[i] = ' ';
+ }
+ buff[read_in] = '\0';
+ after += buff;
+ }
+ (*it).replace( i, callToSystem.matchedLength(), after );
+ i += after.length();
+ }
+ }
+ stillProcess = callToInclude.search(t) != -1;
+ }
+ return tagMap;
+}
diff --git a/tools/linguist/shared/proparser.h b/tools/linguist/shared/proparser.h
new file mode 100644
index 0000000..7e05090
--- /dev/null
+++ b/tools/linguist/shared/proparser.h
@@ -0,0 +1,42 @@
+/**********************************************************************
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of Qt Linguist.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with
+** the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef PROPARSER_H
+#define PROPARSER_H
+
+#include <qmap.h>
+#include <qstring.h>
+
+QMap<QString, QString> proFileTagMap( const QString& text );
+
+#endif