Changeset 561 for trunk/tools/linguist/shared
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 9 deleted
- 22 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/tools/linguist/shared/abstractproitemvisitor.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 50 50 { 51 51 virtual ~AbstractProItemVisitor() {} 52 virtual bool visitBeginProBlock(ProBlock *block) = 0;53 virtual bool visitEndProBlock(ProBlock *block) = 0;54 52 55 virtual bool visitBeginProVariable(ProVariable *variable) = 0;56 virtual bool visitEndProVariable(ProVariable *variable) = 0;53 virtual ProItem::ProItemReturn visitBeginProBlock(ProBlock *block) = 0; 54 virtual void visitEndProBlock(ProBlock *block) = 0; 57 55 58 virtual bool visitBeginProFile(ProFile *value) = 0;59 virtual bool visitEndProFile(ProFile *value) = 0;56 virtual ProItem::ProItemReturn visitProLoopIteration() = 0; 57 virtual void visitProLoopCleanup() = 0; 60 58 61 virtual bool visitProValue(ProValue *value) = 0; 62 virtual bool visitProFunction(ProFunction *function) = 0; 63 virtual bool visitProOperator(ProOperator *function) = 0; 64 virtual bool visitProCondition(ProCondition *function) = 0; 59 virtual void visitBeginProVariable(ProVariable *variable) = 0; 60 virtual void visitEndProVariable(ProVariable *variable) = 0; 61 62 virtual ProItem::ProItemReturn visitBeginProFile(ProFile *value) = 0; 63 virtual ProItem::ProItemReturn visitEndProFile(ProFile *value) = 0; 64 65 virtual void visitProValue(ProValue *value) = 0; 66 virtual ProItem::ProItemReturn visitProFunction(ProFunction *function) = 0; 67 virtual void visitProOperator(ProOperator *function) = 0; 68 virtual void visitProCondition(ProCondition *function) = 0; 65 69 }; 66 70 -
trunk/tools/linguist/shared/formats.pri
r2 r561 20 20 $$PWD/po.cpp \ 21 21 $$PWD/ts.cpp \ 22 $$PWD/ui.cpp \23 $$PWD/cpp.cpp \24 $$PWD/java.cpp \25 $$PWD/qscript.cpp \26 22 $$PWD/xliff.cpp -
trunk/tools/linguist/shared/numerus.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 42 42 #include "translator.h" 43 43 44 #include <QtCore/QCoreApplication>45 44 #include <QtCore/QByteArray> 46 45 #include <QtCore/QDebug> … … 61 60 { Q_MOD_10 | Q_EQ, 1, Q_AND, Q_MOD_100 | Q_NEQ, 11, Q_NEWRULE, 62 61 Q_NEQ, 0 }; 62 static const uchar icelandicRules[] = 63 { Q_MOD_10 | Q_EQ, 1, Q_AND, Q_MOD_100 | Q_NEQ, 11 }; 63 64 static const uchar irishStyleRules[] = 64 65 { Q_EQ, 1, Q_NEWRULE, 65 66 Q_EQ, 2 }; 66 static const uchar czechRules[] =67 { Q_MOD_100 | Q_EQ, 1, Q_NEWRULE,68 Q_MOD_100 | Q_BETWEEN, 2, 4 };69 67 static const uchar slovakRules[] = 70 68 { Q_EQ, 1, Q_NEWRULE, … … 75 73 static const uchar lithuanianRules[] = 76 74 { Q_MOD_10 | Q_EQ, 1, Q_AND, Q_MOD_100 | Q_NEQ, 11, Q_NEWRULE, 77 Q_MOD_10 | Q_ EQ, 2, Q_AND, Q_MOD_100 | Q_NOT_BETWEEN, 10, 19 };75 Q_MOD_10 | Q_NEQ, 0, Q_AND, Q_MOD_100 | Q_NOT_BETWEEN, 10, 19 }; 78 76 static const uchar russianStyleRules[] = 79 77 { Q_MOD_10 | Q_EQ, 1, Q_AND, Q_MOD_100 | Q_NEQ, 11, Q_NEWRULE, … … 103 101 Q_EQ, 2, Q_NEWRULE, 104 102 Q_MOD_100 | Q_BETWEEN, 3, 10, Q_NEWRULE, 105 Q_MOD_100 | Q_NEQ, 0 }; 103 Q_MOD_100 | Q_NOT | Q_BETWEEN, 0, 2 }; 104 static const uchar tagalogRules[] = 105 { Q_LEQ, 1, Q_NEWRULE, 106 Q_MOD_10 | Q_EQ, 4, Q_OR, Q_MOD_10 | Q_EQ, 6, Q_OR, Q_MOD_10 | Q_EQ, 9 }; 107 static const uchar catalanRules[] = 108 { Q_EQ, 1, Q_NEWRULE, 109 Q_LEAD_1000 | Q_EQ, 11 }; 106 110 107 111 static const char * const japaneseStyleForms[] = { "Universal Form", 0 }; 108 112 static const char * const englishStyleForms[] = { "Singular", "Plural", 0 }; 109 113 static const char * const frenchStyleForms[] = { "Singular", "Plural", 0 }; 114 static const char * const icelandicForms[] = { "Singular", "Plural", 0 }; 110 115 static const char * const latvianForms[] = { "Singular", "Plural", "Nullar", 0 }; 111 116 static const char * const irishStyleForms[] = { "Singular", "Dual", "Plural", 0 }; 112 static const char * const czechForms[] = { "Singular", "Dual", "Plural", 0 }; 113 static const char * const slovakForms[] = { "Singular", "Dual", "Plural", 0 }; 117 static const char * const slovakForms[] = { "Singular", "Paucal", "Plural", 0 }; 114 118 static const char * const macedonianForms[] = { "Singular", "Dual", "Plural", 0 }; 115 static const char * const lithuanianForms[] = { "Singular", " Dual", "Plural", 0 };119 static const char * const lithuanianForms[] = { "Singular", "Paucal", "Plural", 0 }; 116 120 static const char * const russianStyleForms[] = { "Singular", "Dual", "Plural", 0 }; 117 121 static const char * const polishForms[] = { "Singular", "Paucal", "Plural", 0 }; 118 static const char * const romanianForms[] = 119 { "Singular", "Plural Form for 2 to 19", "Plural", 0 }; 122 static const char * const romanianForms[] = { "Singular", "Paucal", "Plural", 0 }; 120 123 static const char * const slovenianForms[] = { "Singular", "Dual", "Trial", "Plural", 0 }; 121 124 static const char * const malteseForms[] = 122 { "Singular", "P lural Form for 2 to 10", "Plural Form for 11 to 19", "Plural", 0 };125 { "Singular", "Paucal", "Greater Paucal", "Plural", 0 }; 123 126 static const char * const welshForms[] = 124 127 { "Nullar", "Singular", "Dual", "Sexal", "Plural", 0 }; 125 128 static const char * const arabicForms[] = 126 { "Nullar", "Singular", "Dual", "Minority Plural", "Plural", "Plural Form for 100, 200, ...", 0 }; 129 { "Nullar", "Singular", "Dual", "Minority Plural", "Plural", "Plural (100-102, ...)", 0 }; 130 static const char * const tagalogForms[] = 131 { "Singular", "Plural (consonant-ended)", "Plural (vowel-ended)", 0 }; 132 static const char * const catalanForms[] = { "Singular", "Undecal (11)", "Plural", 0 }; 127 133 128 134 #define EOL QLocale::C … … 148 154 QLocale::Thai, 149 155 QLocale::Tibetan, 156 QLocale::Turkish, 150 157 QLocale::Vietnamese, 151 158 QLocale::Yoruba, … … 170 177 QLocale::Bulgarian, 171 178 QLocale::Cambodian, 172 QLocale::Catalan,173 179 QLocale::Cornish, 174 180 QLocale::Corsican, … … 191 197 QLocale::Hebrew, 192 198 QLocale::Hindi, 193 QLocale::Icelandic,194 199 QLocale::Interlingua, 195 200 QLocale::Interlingue, … … 232 237 QLocale::Swahili, 233 238 QLocale::Swedish, 234 QLocale::Tagalog,235 239 QLocale::Tajik, 236 240 QLocale::Tamil, … … 239 243 QLocale::TongaLanguage, 240 244 QLocale::Tsonga, 241 QLocale::Turkish,242 245 QLocale::Turkmen, 243 246 QLocale::Twi, 244 247 QLocale::Uigur, 248 QLocale::Urdu, 245 249 QLocale::Uzbek, 246 250 QLocale::Volapuk, … … 262 266 }; 263 267 static const QLocale::Language latvianLanguage[] = { QLocale::Latvian, EOL }; 268 static const QLocale::Language icelandicLanguage[] = { QLocale::Icelandic, EOL }; 264 269 static const QLocale::Language irishStyleLanguages[] = { 265 270 QLocale::Divehi, … … 275 280 EOL 276 281 }; 277 static const QLocale::Language czechLanguage[] = { QLocale::Czech, EOL }; 278 static const QLocale::Language slovakLanguage[] = { QLocale::Slovak, EOL }; 282 static const QLocale::Language slovakLanguages[] = { QLocale::Slovak, QLocale::Czech, EOL }; 279 283 static const QLocale::Language macedonianLanguage[] = { QLocale::Macedonian, EOL }; 280 284 static const QLocale::Language lithuanianLanguage[] = { QLocale::Lithuanian, EOL }; … … 299 303 static const QLocale::Language welshLanguage[] = { QLocale::Welsh, EOL }; 300 304 static const QLocale::Language arabicLanguage[] = { QLocale::Arabic, EOL }; 305 static const QLocale::Language tagalogLanguage[] = { QLocale::Tagalog, EOL }; 306 static const QLocale::Language catalanLanguage[] = { QLocale::Catalan, EOL }; 301 307 302 308 static const QLocale::Country frenchStyleCountries[] = { … … 321 327 frenchStyleCountries }, 322 328 { latvianRules, sizeof(latvianRules), latvianForms, latvianLanguage, 0 }, 329 { icelandicRules, sizeof(icelandicRules), icelandicForms, icelandicLanguage, 0 }, 323 330 { irishStyleRules, sizeof(irishStyleRules), irishStyleForms, irishStyleLanguages, 0 }, 324 { czechRules, sizeof(czechRules), czechForms, czechLanguage, 0 }, 325 { slovakRules, sizeof(slovakRules), slovakForms, slovakLanguage, 0 }, 331 { slovakRules, sizeof(slovakRules), slovakForms, slovakLanguages, 0 }, 326 332 { macedonianRules, sizeof(macedonianRules), macedonianForms, macedonianLanguage, 0 }, 327 333 { lithuanianRules, sizeof(lithuanianRules), lithuanianForms, lithuanianLanguage, 0 }, … … 332 338 { malteseRules, sizeof(malteseRules), malteseForms, malteseLanguage, 0 }, 333 339 { welshRules, sizeof(welshRules), welshForms, welshLanguage, 0 }, 334 { arabicRules, sizeof(arabicRules), arabicForms, arabicLanguage, 0 } 340 { arabicRules, sizeof(arabicRules), arabicForms, arabicLanguage, 0 }, 341 { tagalogRules, sizeof(tagalogRules), tagalogForms, tagalogLanguage, 0 }, 342 { catalanRules, sizeof(catalanRules), catalanForms, catalanLanguage, 0 } 335 343 }; 336 344 -
trunk/tools/linguist/shared/po.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 360 360 const QChar newline = QLatin1Char('\n'); 361 361 QTextStream in(&dev); 362 in.setCodec(cd.m_codecForSource.isEmpty() ? QByteArray("UTF-8") : cd.m_codecForSource); 362 363 bool error = false; 363 364 … … 396 397 while (true) { 397 398 int idx = line.indexOf(QLatin1Char(' '), prefix.length()); 398 item.msgStr.append(slurpEscapedString(lines, l, idx, prefix, cd)); 399 QString str = slurpEscapedString(lines, l, idx, prefix, cd); 400 str.replace(QChar(Translator::TextVariantSeparator), 401 QChar(Translator::BinaryVariantSeparator)); 402 item.msgStr.append(str); 399 403 if (l + 1 >= lines.size() || !isTranslationLine(lines.at(l + 1))) 400 404 break; … … 552 556 bool ok = true; 553 557 QTextStream out(&dev); 554 //qDebug() << "OUT CODEC: " << out.codec()->name();558 out.setCodec(cd.m_outputCodec.isEmpty() ? QByteArray("UTF-8") : cd.m_outputCodec); 555 559 556 560 bool first = true; … … 634 638 plural = msg.sourceText(); 635 639 out << poEscapedString(prefix, QLatin1String("msgid_plural"), noWrap, plural); 636 QStringList translations = translator.normalizedTranslations(msg, cd, &ok);640 const QStringList &translations = msg.translations(); 637 641 for (int i = 0; i != translations.size(); ++i) { 642 QString str = translations.at(i); 643 str.replace(QChar(Translator::BinaryVariantSeparator), 644 QChar(Translator::TextVariantSeparator)); 638 645 out << poEscapedString(prefix, QString::fromLatin1("msgstr[%1]").arg(i), noWrap, 639 translations.at(i));646 str); 640 647 } 641 648 } -
trunk/tools/linguist/shared/profileevaluator.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 45 45 46 46 #include <QtCore/QByteArray> 47 #include <QtCore/QDateTime> 47 48 #include <QtCore/QDebug> 48 49 #include <QtCore/QDir> … … 57 58 #include <QtCore/QTextStream> 58 59 60 #ifdef Q_OS_UNIX 61 #include <unistd.h> 62 #include <sys/utsname.h> 63 #else 64 #include <Windows.h> 65 #endif 66 #include <stdio.h> 67 #include <stdlib.h> 68 59 69 #ifdef Q_OS_WIN32 60 70 #define QT_POPEN _popen 71 #define QT_PCLOSE _pclose 61 72 #else 62 73 #define QT_POPEN popen 74 #define QT_PCLOSE pclose 63 75 #endif 64 76 65 77 QT_BEGIN_NAMESPACE 78 79 /////////////////////////////////////////////////////////////////////// 80 // 81 // Option 82 // 83 /////////////////////////////////////////////////////////////////////// 84 85 QString 86 Option::fixString(QString string, uchar flags) 87 { 88 // XXX Ripped out caching, so this will be slow. Should not matter for current uses. 89 90 //fix the environment variables 91 if (flags & Option::FixEnvVars) { 92 int rep; 93 QRegExp reg_variableName(QLatin1String("\\$\\(.*\\)")); 94 reg_variableName.setMinimal(true); 95 while ((rep = reg_variableName.indexIn(string)) != -1) 96 string.replace(rep, reg_variableName.matchedLength(), 97 QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_variableName.matchedLength() - 3).toLatin1().constData()).constData())); 98 } 99 100 //canonicalize it (and treat as a path) 101 if (flags & Option::FixPathCanonicalize) { 102 #if 0 103 string = QFileInfo(string).canonicalFilePath(); 104 #endif 105 string = QDir::cleanPath(string); 106 } 107 108 if (string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':')) 109 string[0] = string[0].toLower(); 110 111 //fix separators 112 Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators))); 113 if (flags & Option::FixPathToLocalSeparators) { 114 #if defined(Q_OS_WIN32) 115 string = string.replace(QLatin1Char('/'), QLatin1Char('\\')); 116 #else 117 string = string.replace(QLatin1Char('\\'), QLatin1Char('/')); 118 #endif 119 } else if (flags & Option::FixPathToTargetSeparators) { 120 string = string.replace(QLatin1Char('/'), Option::dir_sep) 121 .replace(QLatin1Char('\\'), Option::dir_sep); 122 } 123 124 if ((string.startsWith(QLatin1Char('"')) && string.endsWith(QLatin1Char('"'))) || 125 (string.startsWith(QLatin1Char('\'')) && string.endsWith(QLatin1Char('\'')))) 126 string = string.mid(1, string.length() - 2); 127 128 return string; 129 } 66 130 67 131 /////////////////////////////////////////////////////////////////////// … … 75 139 public: 76 140 Private(ProFileEvaluator *q_); 141 142 ProFileEvaluator *q; 143 int m_lineNo; // Error reporting 144 bool m_verbose; 145 146 /////////////// Reading pro file 77 147 78 148 bool read(ProFile *pro); … … 88 158 void finalizeBlock(); 89 159 90 // implementation of AbstractProItemVisitor91 bool visitBeginProBlock(ProBlock *block);92 bool visitEndProBlock(ProBlock *block);93 bool visitBeginProVariable(ProVariable *variable);94 bool visitEndProVariable(ProVariable *variable);95 bool visitBeginProFile(ProFile *value);96 bool visitEndProFile(ProFile *value);97 bool visitProValue(ProValue *value);98 bool visitProFunction(ProFunction *function);99 bool visitProOperator(ProOperator *oper);100 bool visitProCondition(ProCondition *condition);101 102 QStringList valuesDirect(const QString &variableName) const { return m_valuemap[variableName]; }103 QStringList values(const QString &variableName) const;104 QStringList values(const QString &variableName, const ProFile *pro) const;105 QString propertyValue(const QString &val) const;106 107 bool isActiveConfig(const QString &config, bool regex = false);108 QStringList expandPattern(const QString &pattern);109 void expandPatternHelper(const QString &relName, const QString &absName,110 QStringList &sources_out);111 QStringList expandVariableReferences(const QString &value);112 QStringList evaluateExpandFunction(const QString &function, const QString &arguments);113 QString format(const char *format) const;114 115 QString currentFileName() const;116 QString getcwd() const;117 ProFile *currentProFile() const;118 119 bool evaluateConditionalFunction(const QString &function, const QString &arguments, bool *result);120 bool evaluateFile(const QString &fileName, bool *result);121 bool evaluateFeatureFile(const QString &fileName, bool *result);122 123 QStringList qmakeFeaturePaths();124 125 ProFileEvaluator *q;126 127 160 QStack<ProBlock *> m_blockstack; 128 161 ProBlock *m_block; … … 133 166 bool m_syntaxError; 134 167 bool m_contNextLine; 135 bool m_condition; 136 bool m_invertNext; 168 bool m_inQuote; 169 int m_parens; 170 171 /////////////// Evaluating pro file contents 172 173 // implementation of AbstractProItemVisitor 174 ProItem::ProItemReturn visitBeginProBlock(ProBlock *block); 175 void visitEndProBlock(ProBlock *block); 176 ProItem::ProItemReturn visitProLoopIteration(); 177 void visitProLoopCleanup(); 178 void visitBeginProVariable(ProVariable *variable); 179 void visitEndProVariable(ProVariable *variable); 180 ProItem::ProItemReturn visitBeginProFile(ProFile *value); 181 ProItem::ProItemReturn visitEndProFile(ProFile *value); 182 void visitProValue(ProValue *value); 183 ProItem::ProItemReturn visitProFunction(ProFunction *function); 184 void visitProOperator(ProOperator *oper); 185 void visitProCondition(ProCondition *condition); 186 187 QStringList valuesDirect(const QString &variableName) const { return m_valuemap[variableName]; } 188 QStringList values(const QString &variableName) const; 189 QStringList values(const QString &variableName, const ProFile *pro) const; 190 QStringList values(const QString &variableName, const QHash<QString, QStringList> &place, 191 const ProFile *pro) const; 192 QString propertyValue(const QString &val) const; 193 194 bool isActiveConfig(const QString &config, bool regex = false); 195 QStringList expandVariableReferences(const QString &value); 196 void doVariableReplace(QString *str); 197 QStringList evaluateExpandFunction(const QString &function, const QString &arguments); 198 QString format(const char *format) const; 199 200 QString currentFileName() const; 201 QString currentDirectory() const; 202 ProFile *currentProFile() const; 203 204 ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments); 205 bool evaluateFile(const QString &fileName); 206 bool evaluateFeatureFile(const QString &fileName); 207 208 static inline ProItem::ProItemReturn returnBool(bool b) 209 { return b ? ProItem::ReturnTrue : ProItem::ReturnFalse; } 210 211 QStringList evaluateFunction(ProBlock *funcPtr, const QStringList &argumentsList, bool *ok); 212 213 QStringList qmakeFeaturePaths(); 214 215 struct State { 216 bool condition; 217 bool prevCondition; 218 } m_sts; 219 bool m_invertNext; // Short-lived, so not in State 220 int m_skipLevel; 221 bool m_cumulative; 222 bool m_isFirstVariableValue; 137 223 QString m_lastVarName; 138 224 ProVariable::VariableOperator m_variableOperator; 139 int m_lineNo; // Error reporting225 QString m_origfile; 140 226 QString m_oldPath; // To restore the current path to the path 141 227 QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri' 228 struct ProLoop { 229 QString variable; 230 QStringList oldVarVal; 231 QStringList list; 232 int index; 233 bool infinite; 234 }; 235 QStack<ProLoop> m_loopStack; 236 237 // we need the following two variables for handling 238 // CONFIG = foo bar $$CONFIG 239 QHash<QString, QStringList> m_tempValuemap; // used while evaluating (variable operator value1 value2 ...) 240 QHash<const ProFile*, QHash<QString, QStringList> > m_tempFilevaluemap; // used while evaluating (variable operator value1 value2 ...) 142 241 143 242 QHash<QString, QStringList> m_valuemap; // VariableName must be us-ascii, the content however can be non-us-ascii. 144 243 QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file 145 244 QHash<QString, QString> m_properties; 146 QString m_origfile; 245 QString m_outputDir; 246 247 bool m_definingTest; 248 QString m_definingFunc; 249 QHash<QString, ProBlock *> m_testFunctions; 250 QHash<QString, ProBlock *> m_replaceFunctions; 251 QStringList m_returnValue; 252 QStack<QHash<QString, QStringList> > m_valuemapStack; 253 QStack<QHash<const ProFile*, QHash<QString, QStringList> > > m_filevaluemapStack; 147 254 148 255 int m_prevLineNo; // Checking whether we're assigning the same TARGET 149 256 ProFile *m_prevProFile; // See m_prevLineNo 150 151 bool m_verbose;152 257 }; 258 259 Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::State, Q_PRIMITIVE_TYPE); 260 Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::ProLoop, Q_MOVABLE_TYPE); 153 261 154 262 ProFileEvaluator::Private::Private(ProFileEvaluator *q_) 155 263 : q(q_) 156 264 { 265 // Global parser state 157 266 m_prevLineNo = 0; 158 267 m_prevProFile = 0; 268 269 // Configuration, more or less 159 270 m_verbose = true; 271 m_cumulative = true; 272 273 // Evaluator state 274 m_sts.condition = false; 275 m_sts.prevCondition = false; 276 m_invertNext = false; 277 m_skipLevel = 0; 278 m_isFirstVariableValue = true; 279 m_definingFunc.clear(); 160 280 } 161 281 … … 168 288 } 169 289 290 // Parser state 170 291 m_block = 0; 171 292 m_commentItem = 0; 293 m_inQuote = false; 294 m_parens = 0; 172 295 m_contNextLine = false; 173 296 m_syntaxError = false; … … 193 316 return false; 194 317 195 ushort quote = 0;196 int parens = 0;197 bool contNextLine= false;318 int parens = m_parens; 319 bool inQuote = m_inQuote; 320 bool escaped = false; 198 321 QString line = line0.simplified(); 199 322 200 323 for (int i = 0; !m_syntaxError && i < line.length(); ++i) { 201 324 ushort c = line.at(i).unicode(); 202 if (quote && c == quote) 203 quote = 0; 204 else if (c == '(') 205 ++parens; 206 else if (c == ')') 207 --parens; 208 else if (c == '"' && (i == 0 || line.at(i - 1).unicode() != '\\')) 209 quote = c; 210 else if (!parens && !quote) { 211 if (c == '#') { 212 insertComment(line.mid(i + 1)); 213 contNextLine = m_contNextLine; 214 break; 215 } 216 if (c == '\\' && i >= line.count() - 1) { 217 updateItem(); 218 contNextLine = true; 325 if (c == '#') { // Yep - no escaping possible 326 insertComment(line.mid(i + 1)); 327 escaped = m_contNextLine; 328 break; 329 } 330 if (!escaped) { 331 if (c == '\\') { 332 escaped = true; 333 m_proitem += c; 219 334 continue; 220 } 221 if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) { 222 if (c == ' ') 223 updateItem(); 224 else 225 m_proitem += c; 335 } else if (c == '"') { 336 inQuote = !inQuote; 337 m_proitem += c; 226 338 continue; 227 339 } 228 if (c == ':') { 229 enterScope(false); 230 continue; 231 } 232 if (c == '{') { 233 enterScope(true); 234 continue; 235 } 236 if (c == '}') { 237 leaveScope(); 238 continue; 239 } 240 if (c == '=') { 241 insertVariable(line, &i); 242 continue; 243 } 244 if (c == '|' || c == '!') { 245 insertOperator(c); 246 continue; 340 } else { 341 escaped = false; 342 } 343 if (!inQuote) { 344 if (c == '(') { 345 ++parens; 346 } else if (c == ')') { 347 --parens; 348 } else if (!parens) { 349 if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) { 350 if (c == ' ') 351 updateItem(); 352 else 353 m_proitem += c; 354 continue; 355 } 356 if (c == ':') { 357 enterScope(false); 358 continue; 359 } 360 if (c == '{') { 361 enterScope(true); 362 continue; 363 } 364 if (c == '}') { 365 leaveScope(); 366 continue; 367 } 368 if (c == '=') { 369 insertVariable(line, &i); 370 continue; 371 } 372 if (c == '|' || c == '!') { 373 insertOperator(c); 374 continue; 375 } 247 376 } 248 377 } … … 250 379 m_proitem += c; 251 380 } 252 m_contNextLine = contNextLine; 253 254 if (!m_syntaxError) { 381 m_inQuote = inQuote; 382 m_parens = parens; 383 m_contNextLine = escaped; 384 if (escaped) { 385 m_proitem.chop(1); 255 386 updateItem(); 256 if (!m_contNextLine) 387 return true; 388 } else { 389 if (!m_syntaxError) { 390 updateItem(); 257 391 finalizeBlock(); 258 } 259 return !m_syntaxError; 392 return true; 393 } 394 return false; 395 } 260 396 } 261 397 … … 276 412 ProVariable::VariableOperator opkind; 277 413 414 if (m_proitem.isEmpty()) // Line starting with '=', like a conflict marker 415 return; 416 278 417 switch (m_proitem.at(m_proitem.length() - 1).unicode()) { 279 418 case '+': … … 450 589 451 590 452 bool ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block) 453 { 454 if (block->blockKind() == ProBlock::ScopeKind) { 455 m_invertNext = false; 456 m_condition = false; 457 } 458 return true; 459 } 460 461 bool ProFileEvaluator::Private::visitEndProBlock(ProBlock *block) 462 { 463 Q_UNUSED(block); 464 return true; 465 } 466 467 bool ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable) 591 ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block) 592 { 593 if (block->blockKind() & ProBlock::ScopeContentsKind) { 594 if (!m_definingFunc.isEmpty()) { 595 if (!m_skipLevel || m_cumulative) { 596 QHash<QString, ProBlock *> *hash = 597 (m_definingTest ? &m_testFunctions : &m_replaceFunctions); 598 if (ProBlock *def = hash->value(m_definingFunc)) 599 def->deref(); 600 hash->insert(m_definingFunc, block); 601 block->ref(); 602 block->setBlockKind(block->blockKind() | ProBlock::FunctionBodyKind); 603 } 604 m_definingFunc.clear(); 605 return ProItem::ReturnSkip; 606 } else if (!(block->blockKind() & ProBlock::FunctionBodyKind)) { 607 if (!m_sts.condition) 608 ++m_skipLevel; 609 else 610 Q_ASSERT(!m_skipLevel); 611 } 612 } else { 613 if (!m_skipLevel) { 614 if (m_sts.condition) { 615 m_sts.prevCondition = true; 616 m_sts.condition = false; 617 } 618 } else { 619 Q_ASSERT(!m_sts.condition); 620 } 621 } 622 return ProItem::ReturnTrue; 623 } 624 625 void ProFileEvaluator::Private::visitEndProBlock(ProBlock *block) 626 { 627 if ((block->blockKind() & ProBlock::ScopeContentsKind) 628 && !(block->blockKind() & ProBlock::FunctionBodyKind)) { 629 if (m_skipLevel) { 630 Q_ASSERT(!m_sts.condition); 631 --m_skipLevel; 632 } else if (!(block->blockKind() & ProBlock::SingleLine)) { 633 // Conditionals contained inside this block may have changed the state. 634 // So we reset it here to make an else following us do the right thing. 635 m_sts.condition = true; 636 } 637 } 638 } 639 640 ProItem::ProItemReturn ProFileEvaluator::Private::visitProLoopIteration() 641 { 642 ProLoop &loop = m_loopStack.top(); 643 644 if (loop.infinite) { 645 if (!loop.variable.isEmpty()) 646 m_valuemap[loop.variable] = QStringList(QString::number(loop.index++)); 647 if (loop.index > 1000) { 648 q->errorMessage(format("ran into infinite loop (> 1000 iterations).")); 649 return ProItem::ReturnFalse; 650 } 651 } else { 652 QString val; 653 do { 654 if (loop.index >= loop.list.count()) 655 return ProItem::ReturnFalse; 656 val = loop.list.at(loop.index++); 657 } while (val.isEmpty()); // stupid, but qmake is like that 658 m_valuemap[loop.variable] = QStringList(val); 659 } 660 return ProItem::ReturnTrue; 661 } 662 663 void ProFileEvaluator::Private::visitProLoopCleanup() 664 { 665 ProLoop &loop = m_loopStack.top(); 666 m_valuemap[loop.variable] = loop.oldVarVal; 667 m_loopStack.pop_back(); 668 } 669 670 void ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable) 468 671 { 469 672 m_lastVarName = variable->variable(); 470 673 m_variableOperator = variable->variableOperator(); 471 return true; 472 } 473 474 bool ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable) 674 m_isFirstVariableValue = true; 675 m_tempValuemap = m_valuemap; 676 m_tempFilevaluemap = m_filevaluemap; 677 } 678 679 void ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable) 475 680 { 476 681 Q_UNUSED(variable); 682 m_valuemap = m_tempValuemap; 683 m_filevaluemap = m_tempFilevaluemap; 477 684 m_lastVarName.clear(); 478 return true; 479 } 480 481 bool ProFileEvaluator::Private::visitProOperator(ProOperator *oper) 685 } 686 687 void ProFileEvaluator::Private::visitProOperator(ProOperator *oper) 482 688 { 483 689 m_invertNext = (oper->operatorKind() == ProOperator::NotOperator); 484 return true; 485 } 486 487 bool ProFileEvaluator::Private::visitProCondition(ProCondition *cond) 488 { 489 if (!m_condition) { 490 if (m_invertNext) 491 m_condition |= !isActiveConfig(cond->text(), true); 492 else 493 m_condition |= isActiveConfig(cond->text(), true); 494 } 495 return true; 496 } 497 498 bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro) 690 } 691 692 void ProFileEvaluator::Private::visitProCondition(ProCondition *cond) 693 { 694 if (!m_skipLevel) { 695 if (!cond->text().compare(QLatin1String("else"), Qt::CaseInsensitive)) { 696 m_sts.condition = !m_sts.prevCondition; 697 } else { 698 m_sts.prevCondition = false; 699 if (!m_sts.condition && isActiveConfig(cond->text(), true) ^ m_invertNext) 700 m_sts.condition = true; 701 } 702 } 703 m_invertNext = false; 704 } 705 706 ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pro) 499 707 { 500 708 PRE(pro); 501 bool ok = true;502 709 m_lineNo = pro->lineNumber(); 710 if (m_origfile.isEmpty()) 711 m_origfile = pro->fileName(); 503 712 if (m_oldPath.isEmpty()) { 504 713 // change the working directory for the initial profile we visit, since 505 714 // that is *the* profile. All the other times we reach this function will be due to 506 715 // include(file) or load(file) 716 507 717 m_oldPath = QDir::currentPath(); 718 508 719 m_profileStack.push(pro); 509 ok = QDir::setCurrent(pro->directoryName()); 510 } 511 512 if (m_origfile.isEmpty()) 513 m_origfile = pro->fileName(); 514 515 return ok; 516 } 517 518 bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro) 720 721 const QString mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); 722 if (!mkspecDirectory.isEmpty()) { 723 bool cumulative = m_cumulative; 724 m_cumulative = false; 725 // This is what qmake does, everything set in the mkspec is also set 726 // But this also creates a lot of problems 727 evaluateFile(mkspecDirectory + QLatin1String("/default/qmake.conf")); 728 evaluateFile(mkspecDirectory + QLatin1String("/features/default_pre.prf")); 729 m_cumulative = cumulative; 730 } 731 732 return returnBool(QDir::setCurrent(pro->directoryName())); 733 } 734 735 return ProItem::ReturnTrue; 736 } 737 738 ProItem::ProItemReturn ProFileEvaluator::Private::visitEndProFile(ProFile * pro) 519 739 { 520 740 PRE(pro); 521 bool ok = true;522 741 m_lineNo = pro->lineNumber(); 523 742 if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) { 743 const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); 744 if (!mkspecDirectory.isEmpty()) { 745 bool cumulative = m_cumulative; 746 m_cumulative = false; 747 748 evaluateFile(mkspecDirectory + QLatin1String("/features/default_post.prf")); 749 750 QSet<QString> processed; 751 forever { 752 bool finished = true; 753 QStringList configs = valuesDirect(QLatin1String("CONFIG")); 754 for (int i = configs.size() - 1; i >= 0; --i) { 755 const QString config = configs[i].toLower(); 756 if (!processed.contains(config)) { 757 processed.insert(config); 758 if (evaluateFile(mkspecDirectory + QLatin1String("/features/") 759 + config + QLatin1String(".prf"))) { 760 finished = false; 761 break; 762 } 763 } 764 } 765 if (finished) 766 break; 767 } 768 769 foreach (ProBlock *itm, m_replaceFunctions) 770 itm->deref(); 771 m_replaceFunctions.clear(); 772 foreach (ProBlock *itm, m_testFunctions) 773 itm->deref(); 774 m_testFunctions.clear(); 775 776 m_cumulative = cumulative; 777 } 778 524 779 m_profileStack.pop(); 525 ok = QDir::setCurrent(m_oldPath); 526 } 527 return ok; 528 } 529 530 bool ProFileEvaluator::Private::visitProValue(ProValue *value) 780 return returnBool(QDir::setCurrent(m_oldPath)); 781 } 782 783 return ProItem::ReturnTrue; 784 } 785 786 static void replaceInList(QStringList *varlist, 787 const QRegExp ®exp, const QString &replace, bool global) 788 { 789 for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) { 790 if ((*varit).contains(regexp)) { 791 (*varit).replace(regexp, replace); 792 if ((*varit).isEmpty()) 793 varit = varlist->erase(varit); 794 else 795 ++varit; 796 if(!global) 797 break; 798 } else { 799 ++varit; 800 } 801 } 802 } 803 804 void ProFileEvaluator::Private::visitProValue(ProValue *value) 531 805 { 532 806 PRE(value); … … 545 819 && m_lineNo == m_prevLineNo 546 820 && currentProFile() == m_prevProFile) { 547 QStringList targets = m_ valuemap.value(QLatin1String("TARGET"));548 m_ valuemap.remove(QLatin1String("TARGET"));821 QStringList targets = m_tempValuemap.value(QLatin1String("TARGET")); 822 m_tempValuemap.remove(QLatin1String("TARGET")); 549 823 QStringList lastTarget(targets.takeLast()); 550 824 lastTarget << v.join(QLatin1String(" ")); … … 555 829 m_prevProFile = currentProFile(); 556 830 557 // The following two blocks fix bug 180128 by making all "interesting"558 // file name absolute in each .pro file, not just the top most one559 if (varName == QLatin1String("SOURCES")560 || varName == QLatin1String("HEADERS")561 || varName == QLatin1String("INTERFACES")562 || varName == QLatin1String("FORMS")563 || varName == QLatin1String("FORMS3")564 || varName == QLatin1String("RESOURCES")) {565 // matches only existent files, expand certain(?) patterns566 QStringList vv;567 for (int i = v.count(); --i >= 0; )568 vv << expandPattern(v[i]);569 v = vv;570 }571 572 if (varName == QLatin1String("TRANSLATIONS")) {573 // also matches non-existent files, but does not expand pattern574 QString dir = QFileInfo(currentFileName()).absolutePath();575 dir += QLatin1Char('/');576 for (int i = v.count(); --i >= 0; )577 v[i] = QFileInfo(dir, v[i]).absoluteFilePath();578 }579 580 831 switch (m_variableOperator) { 581 case ProVariable::UniqueAddOperator: // *582 insertUnique(&m_valuemap, varName, v, true);583 insertUnique(&m_filevaluemap[currentProFile()], varName, v, true);584 break;585 832 case ProVariable::SetOperator: // = 586 case ProVariable::AddOperator: // + 587 insertUnique(&m_valuemap, varName, v, false); 588 insertUnique(&m_filevaluemap[currentProFile()], varName, v, false); 589 break; 590 case ProVariable::RemoveOperator: // - 591 // fix me: interaction between AddOperator and RemoveOperator 592 insertUnique(&m_valuemap, varName.prepend(QLatin1Char('-')), v, false); 593 insertUnique(&m_filevaluemap[currentProFile()], 594 varName.prepend(QLatin1Char('-')), v, false); 595 break; 596 case ProVariable::ReplaceOperator: // ~ 833 if (!m_cumulative) { 834 if (!m_skipLevel) { 835 if (m_isFirstVariableValue) { 836 m_tempValuemap[varName] = v; 837 m_tempFilevaluemap[currentProFile()][varName] = v; 838 } else { // handle lines "CONFIG = foo bar" 839 m_tempValuemap[varName] += v; 840 m_tempFilevaluemap[currentProFile()][varName] += v; 841 } 842 } 843 } else { 844 // We are greedy for values. 845 m_tempValuemap[varName] += v; 846 m_tempFilevaluemap[currentProFile()][varName] += v; 847 } 848 break; 849 case ProVariable::UniqueAddOperator: // *= 850 if (!m_skipLevel || m_cumulative) { 851 insertUnique(&m_tempValuemap, varName, v); 852 insertUnique(&m_tempFilevaluemap[currentProFile()], varName, v); 853 } 854 break; 855 case ProVariable::AddOperator: // += 856 if (!m_skipLevel || m_cumulative) { 857 m_tempValuemap[varName] += v; 858 m_tempFilevaluemap[currentProFile()][varName] += v; 859 } 860 break; 861 case ProVariable::RemoveOperator: // -= 862 if (!m_cumulative) { 863 if (!m_skipLevel) { 864 removeEach(&m_tempValuemap, varName, v); 865 removeEach(&m_tempFilevaluemap[currentProFile()], varName, v); 866 } 867 } else { 868 // We are stingy with our values, too. 869 } 870 break; 871 case ProVariable::ReplaceOperator: // ~= 597 872 { 598 873 // DEFINES ~= s/a/b/?[gqi] 599 874 600 /* Create a superset by executing replacement + adding items that have changed 601 to original list. We're not sure if this is really the right approach, so for 602 the time being we will just do nothing ... 603 875 doVariableReplace(&val); 876 if (val.length() < 4 || val[0] != QLatin1Char('s')) { 877 q->logMessage(format("the ~= operator can handle only the s/// function.")); 878 break; 879 } 604 880 QChar sep = val.at(1); 605 881 QStringList func = val.split(sep); 606 882 if (func.count() < 3 || func.count() > 4) { 607 q->logMessage(format("'~= operator '(function s///) expects 3 or 4 arguments.")); 608 return false; 609 } 610 if (func[0] != QLatin1String("s")) { 611 q->logMessage(format("~= operator can only handle s/// function.")); 612 return false; 883 q->logMessage(format("the s/// function expects 3 or 4 arguments.")); 884 break; 613 885 } 614 886 … … 626 898 QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive); 627 899 628 QStringList replaceList = replaceInList(m_valuemap.value(varName), regexp, replace, 629 global); 630 // Add changed entries to list 631 foreach (const QString &entry, replaceList) 632 if (!m_valuemap.value(varName).contains(entry)) 633 insertUnique(&m_valuemap, varName, QStringList() << entry, false); 634 635 replaceList = replaceInList(m_filevaluemap[currentProFile()].value(varName), regexp, 636 replace, global); 637 foreach (const QString &entry, replaceList) 638 if (!m_filevaluemap[currentProFile()].value(varName).contains(entry)) 639 insertUnique(&m_filevaluemap[currentProFile()], varName, 640 QStringList() << entry, false); */ 641 } 642 break; 643 644 } 645 return true; 646 } 647 648 bool ProFileEvaluator::Private::visitProFunction(ProFunction *func) 649 { 650 m_lineNo = func->lineNumber(); 651 bool result = true; 652 bool ok = true; 653 QString text = func->text(); 654 int lparen = text.indexOf(QLatin1Char('(')); 655 int rparen = text.lastIndexOf(QLatin1Char(')')); 656 Q_ASSERT(lparen < rparen); 657 658 QString arguments = text.mid(lparen + 1, rparen - lparen - 1); 659 QString funcName = text.left(lparen); 660 ok &= evaluateConditionalFunction(funcName.trimmed(), arguments, &result); 661 return ok; 900 if (!m_skipLevel || m_cumulative) { 901 // We could make a union of modified and unmodified values, 902 // but this will break just as much as it fixes, so leave it as is. 903 replaceInList(&m_tempValuemap[varName], regexp, replace, global); 904 replaceInList(&m_tempFilevaluemap[currentProFile()][varName], regexp, replace, global); 905 } 906 } 907 break; 908 909 } 910 m_isFirstVariableValue = false; 911 } 912 913 ProItem::ProItemReturn ProFileEvaluator::Private::visitProFunction(ProFunction *func) 914 { 915 // Make sure that called subblocks don't inherit & destroy the state 916 bool invertThis = m_invertNext; 917 m_invertNext = false; 918 if (!m_skipLevel) 919 m_sts.prevCondition = false; 920 if (m_cumulative || !m_sts.condition) { 921 QString text = func->text(); 922 int lparen = text.indexOf(QLatin1Char('(')); 923 int rparen = text.lastIndexOf(QLatin1Char(')')); 924 Q_ASSERT(lparen < rparen); 925 QString arguments = text.mid(lparen + 1, rparen - lparen - 1); 926 QString funcName = text.left(lparen); 927 m_lineNo = func->lineNumber(); 928 ProItem::ProItemReturn result = evaluateConditionalFunction(funcName.trimmed(), arguments); 929 if (result != ProItem::ReturnFalse && result != ProItem::ReturnTrue) 930 return result; 931 if (!m_skipLevel && ((result == ProItem::ReturnTrue) ^ invertThis)) 932 m_sts.condition = true; 933 } 934 return ProItem::ReturnTrue; 662 935 } 663 936 … … 667 940 QStringList concat; 668 941 { 669 const QString base_concat = QDir::separator() + Q String(QLatin1String("features"));942 const QString base_concat = QDir::separator() + QLatin1String("features"); 670 943 concat << base_concat + QDir::separator() + QLatin1String("mac"); 671 944 concat << base_concat + QDir::separator() + QLatin1String("macx"); … … 676 949 concat << base_concat; 677 950 } 678 const QString mkspecs_concat = QDir::separator() + Q String(QLatin1String("mkspecs"));951 const QString mkspecs_concat = QDir::separator() + QLatin1String("mkspecs"); 679 952 QStringList feature_roots; 680 953 QByteArray mkspec_path = qgetenv("QMAKEFEATURES"); … … 779 1052 } 780 1053 781 QString ProFileEvaluator::Private:: getcwd() const1054 QString ProFileEvaluator::Private::currentDirectory() const 782 1055 { 783 1056 ProFile *cur = m_profileStack.top(); 784 1057 return cur->directoryName(); 1058 } 1059 1060 void ProFileEvaluator::Private::doVariableReplace(QString *str) 1061 { 1062 *str = expandVariableReferences(*str).join(QString(Option::field_sep)); 785 1063 } 786 1064 … … 999 1277 } 1000 1278 1279 QStringList ProFileEvaluator::Private::evaluateFunction( 1280 ProBlock *funcPtr, const QStringList &argumentsList, bool *ok) 1281 { 1282 bool oki; 1283 QStringList ret; 1284 1285 if (m_valuemapStack.count() >= 100) { 1286 q->errorMessage(format("ran into infinite recursion (depth > 100).")); 1287 oki = false; 1288 } else { 1289 State sts = m_sts; 1290 m_valuemapStack.push(m_valuemap); 1291 m_filevaluemapStack.push(m_filevaluemap); 1292 1293 QStringList args; 1294 for (int i = 0; i < argumentsList.count(); ++i) { 1295 QStringList theArgs = expandVariableReferences(argumentsList[i]); 1296 args += theArgs; 1297 m_valuemap[QString::number(i+1)] = theArgs; 1298 } 1299 m_valuemap[QLatin1String("ARGS")] = args; 1300 oki = (funcPtr->Accept(this) != ProItem::ReturnFalse); // True || Return 1301 ret = m_returnValue; 1302 m_returnValue.clear(); 1303 1304 m_valuemap = m_valuemapStack.pop(); 1305 m_filevaluemap = m_filevaluemapStack.pop(); 1306 m_sts = sts; 1307 } 1308 if (ok) 1309 *ok = oki; 1310 if (oki) 1311 return ret; 1312 return QStringList(); 1313 } 1314 1001 1315 QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments) 1002 1316 { 1003 1317 QStringList argumentsList = split_arg_list(arguments); 1318 1319 if (ProBlock *funcPtr = m_replaceFunctions.value(func, 0)) 1320 return evaluateFunction(funcPtr, argumentsList, 0); 1004 1321 1005 1322 QStringList args; … … 1013 1330 E_REPLACE }; 1014 1331 1015 static QHash<QString, int> *expands = 0; 1016 if (!expands) { 1017 expands = new QHash<QString, int>; 1018 expands->insert(QLatin1String("member"), E_MEMBER); //v (implemented) 1019 expands->insert(QLatin1String("first"), E_FIRST); //v 1020 expands->insert(QLatin1String("last"), E_LAST); //v 1021 expands->insert(QLatin1String("cat"), E_CAT); 1022 expands->insert(QLatin1String("fromfile"), E_FROMFILE); 1023 expands->insert(QLatin1String("eval"), E_EVAL); 1024 expands->insert(QLatin1String("list"), E_LIST); 1025 expands->insert(QLatin1String("sprintf"), E_SPRINTF); 1026 expands->insert(QLatin1String("join"), E_JOIN); //v 1027 expands->insert(QLatin1String("split"), E_SPLIT); //v 1028 expands->insert(QLatin1String("basename"), E_BASENAME); //v 1029 expands->insert(QLatin1String("dirname"), E_DIRNAME); //v 1030 expands->insert(QLatin1String("section"), E_SECTION); 1031 expands->insert(QLatin1String("find"), E_FIND); 1032 expands->insert(QLatin1String("system"), E_SYSTEM); //v 1033 expands->insert(QLatin1String("unique"), E_UNIQUE); 1034 expands->insert(QLatin1String("quote"), E_QUOTE); //v 1035 expands->insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND); 1036 expands->insert(QLatin1String("upper"), E_UPPER); 1037 expands->insert(QLatin1String("lower"), E_LOWER); 1038 expands->insert(QLatin1String("re_escape"), E_RE_ESCAPE); 1039 expands->insert(QLatin1String("files"), E_FILES); 1040 expands->insert(QLatin1String("prompt"), E_PROMPT); 1041 expands->insert(QLatin1String("replace"), E_REPLACE); 1042 } 1043 ExpandFunc func_t = ExpandFunc(expands->value(func.toLower())); 1332 static QHash<QString, int> expands; 1333 if (expands.isEmpty()) { 1334 expands.insert(QLatin1String("member"), E_MEMBER); 1335 expands.insert(QLatin1String("first"), E_FIRST); 1336 expands.insert(QLatin1String("last"), E_LAST); 1337 expands.insert(QLatin1String("cat"), E_CAT); 1338 expands.insert(QLatin1String("fromfile"), E_FROMFILE); // implementation disabled (see comment below) 1339 expands.insert(QLatin1String("eval"), E_EVAL); 1340 expands.insert(QLatin1String("list"), E_LIST); 1341 expands.insert(QLatin1String("sprintf"), E_SPRINTF); 1342 expands.insert(QLatin1String("join"), E_JOIN); 1343 expands.insert(QLatin1String("split"), E_SPLIT); 1344 expands.insert(QLatin1String("basename"), E_BASENAME); 1345 expands.insert(QLatin1String("dirname"), E_DIRNAME); 1346 expands.insert(QLatin1String("section"), E_SECTION); 1347 expands.insert(QLatin1String("find"), E_FIND); 1348 expands.insert(QLatin1String("system"), E_SYSTEM); 1349 expands.insert(QLatin1String("unique"), E_UNIQUE); 1350 expands.insert(QLatin1String("quote"), E_QUOTE); 1351 expands.insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND); 1352 expands.insert(QLatin1String("upper"), E_UPPER); 1353 expands.insert(QLatin1String("lower"), E_LOWER); 1354 expands.insert(QLatin1String("re_escape"), E_RE_ESCAPE); 1355 expands.insert(QLatin1String("files"), E_FILES); 1356 expands.insert(QLatin1String("prompt"), E_PROMPT); // interactive, so cannot be implemented 1357 expands.insert(QLatin1String("replace"), E_REPLACE); 1358 } 1359 ExpandFunc func_t = ExpandFunc(expands.value(func.toLower())); 1044 1360 1045 1361 QStringList ret; … … 1087 1403 break; 1088 1404 } 1405 case E_SPRINTF: 1406 if(args.count() < 1) { 1407 q->logMessage(format("sprintf(format, ...) requires at least one argument")); 1408 } else { 1409 QString tmp = args.at(0); 1410 for (int i = 1; i < args.count(); ++i) 1411 tmp = tmp.arg(args.at(i)); 1412 ret = split_value_list(tmp); 1413 } 1414 break; 1089 1415 case E_JOIN: { 1090 1416 if (args.count() < 1 || args.count() > 4) { … … 1106 1432 case E_SPLIT: { 1107 1433 if (args.count() != 2) { 1108 q->logMessage(format("split(var, sep) requires two arguments"));1434 q->logMessage(format("split(var, sep) requires one or two arguments")); 1109 1435 } else { 1110 QString sep = args.at(1);1436 const QString &sep = (args.count() == 2) ? args[1] : QString(Option::field_sep); 1111 1437 foreach (const QString &var, values(args.first())) 1112 1438 foreach (const QString &splt, var.split(sep)) … … 1179 1505 break; 1180 1506 } 1181 case E_SYSTEM: { 1182 if (m_condition) { 1507 case E_CAT: 1508 if (args.count() < 1 || args.count() > 2) { 1509 q->logMessage(format("cat(file, singleline=true) requires one or two arguments.")); 1510 } else { 1511 QString file = args[0]; 1512 file = Option::fixPathToLocalOS(file); 1513 1514 bool singleLine = true; 1515 if (args.count() > 1) 1516 singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive)); 1517 1518 QFile qfile(file); 1519 if (qfile.open(QIODevice::ReadOnly)) { 1520 QTextStream stream(&qfile); 1521 while (!stream.atEnd()) { 1522 ret += split_value_list(stream.readLine().trimmed()); 1523 if (!singleLine) 1524 ret += QLatin1String("\n"); 1525 } 1526 qfile.close(); 1527 } 1528 } 1529 break; 1530 #if 0 // Used only by Qt's configure for caching 1531 case E_FROMFILE: 1532 if (args.count() != 2) { 1533 q->logMessage(format("fromfile(file, variable) requires two arguments.")); 1534 } else { 1535 QString file = args[0], seek_variableName = args[1]; 1536 1537 ProFile pro(Option::fixPathToLocalOS(file)); 1538 1539 ProFileEvaluator visitor; 1540 visitor.setVerbose(m_verbose); 1541 visitor.setCumulative(m_cumulative); 1542 1543 if (!visitor.queryProFile(&pro)) 1544 break; 1545 1546 if (!visitor.accept(&pro)) 1547 break; 1548 1549 ret = visitor.values(seek_variableName); 1550 } 1551 break; 1552 #endif 1553 case E_EVAL: { 1554 if (args.count() != 1) { 1555 q->logMessage(format("eval(variable) requires one argument")); 1556 1557 } else { 1558 ret += values(args.at(0)); 1559 } 1560 break; } 1561 case E_LIST: { 1562 static int x = 0; 1563 QString tmp; 1564 tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", x++); 1565 ret = QStringList(tmp); 1566 QStringList lst; 1567 foreach (const QString &arg, args) 1568 lst += split_value_list(arg); 1569 m_valuemap[tmp] = lst; 1570 break; } 1571 case E_FIND: 1572 if (args.count() != 2) { 1573 q->logMessage(format("find(var, str) requires two arguments.")); 1574 } else { 1575 QRegExp regx(args[1]); 1576 foreach (const QString &val, values(args.first())) 1577 if (regx.indexIn(val) != -1) 1578 ret += val; 1579 } 1580 break; 1581 case E_SYSTEM: 1582 if (!m_skipLevel) { 1183 1583 if (args.count() < 1 || args.count() > 2) { 1184 1584 q->logMessage(format("system(execute) requires one or two arguments.")); … … 1188 1588 bool singleLine = true; 1189 1589 if (args.count() > 1) 1190 singleLine = ( args[1].toLower() == QLatin1String("true"));1590 singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive)); 1191 1591 QString output; 1192 1592 while (proc && !feof(proc)) { … … 1202 1602 } 1203 1603 ret += split_value_list(output); 1204 } 1205 } 1206 break; } 1604 if (proc) 1605 QT_PCLOSE(proc); 1606 } 1607 } 1608 break; 1609 case E_UNIQUE: 1610 if(args.count() != 1) { 1611 q->logMessage(format("unique(var) requires one argument.")); 1612 } else { 1613 foreach (const QString &var, values(args.first())) 1614 if (!ret.contains(var)) 1615 ret.append(var); 1616 } 1617 break; 1207 1618 case E_QUOTE: 1208 1619 for (int i = 0; i < args.count(); ++i) 1209 1620 ret += QStringList(args.at(i)); 1210 1621 break; 1622 case E_ESCAPE_EXPAND: 1623 for (int i = 0; i < args.size(); ++i) { 1624 QChar *i_data = args[i].data(); 1625 int i_len = args[i].length(); 1626 for (int x = 0; x < i_len; ++x) { 1627 if (*(i_data+x) == QLatin1Char('\\') && x < i_len-1) { 1628 if (*(i_data+x+1) == QLatin1Char('\\')) { 1629 ++x; 1630 } else { 1631 struct { 1632 char in, out; 1633 } mapped_quotes[] = { 1634 { 'n', '\n' }, 1635 { 't', '\t' }, 1636 { 'r', '\r' }, 1637 { 0, 0 } 1638 }; 1639 for (int i = 0; mapped_quotes[i].in; ++i) { 1640 if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) { 1641 *(i_data+x) = QLatin1Char(mapped_quotes[i].out); 1642 if (x < i_len-2) 1643 memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar)); 1644 --i_len; 1645 break; 1646 } 1647 } 1648 } 1649 } 1650 } 1651 ret.append(QString(i_data, i_len)); 1652 } 1653 break; 1654 case E_RE_ESCAPE: 1655 for (int i = 0; i < args.size(); ++i) 1656 ret += QRegExp::escape(args[i]); 1657 break; 1658 case E_UPPER: 1659 case E_LOWER: 1660 for (int i = 0; i < args.count(); ++i) 1661 if (func_t == E_UPPER) 1662 ret += args[i].toUpper(); 1663 else 1664 ret += args[i].toLower(); 1665 break; 1666 case E_FILES: 1667 if (args.count() != 1 && args.count() != 2) { 1668 q->logMessage(format("files(pattern, recursive=false) requires one or two arguments")); 1669 } else { 1670 bool recursive = false; 1671 if (args.count() == 2) 1672 recursive = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive) || args[1].toInt()); 1673 QStringList dirs; 1674 QString r = Option::fixPathToLocalOS(args[0]); 1675 int slash = r.lastIndexOf(QDir::separator()); 1676 if (slash != -1) { 1677 dirs.append(r.left(slash)); 1678 r = r.mid(slash+1); 1679 } else { 1680 dirs.append(QString()); 1681 } 1682 1683 const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard); 1684 for (int d = 0; d < dirs.count(); d++) { 1685 QString dir = dirs[d]; 1686 if (!dir.isEmpty() && !dir.endsWith(Option::dir_sep)) 1687 dir += QLatin1Char('/'); 1688 1689 QDir qdir(dir); 1690 for (int i = 0; i < (int)qdir.count(); ++i) { 1691 if (qdir[i] == QLatin1String(".") || qdir[i] == QLatin1String("..")) 1692 continue; 1693 QString fname = dir + qdir[i]; 1694 if (QFileInfo(fname).isDir()) { 1695 if (recursive) 1696 dirs.append(fname); 1697 } 1698 if (regex.exactMatch(qdir[i])) 1699 ret += fname; 1700 } 1701 } 1702 } 1703 break; 1704 case E_REPLACE: 1705 if(args.count() != 3 ) { 1706 q->logMessage(format("replace(var, before, after) requires three arguments")); 1707 } else { 1708 const QRegExp before(args[1]); 1709 const QString after(args[2]); 1710 foreach (QString val, values(args.first())) 1711 ret += val.replace(before, after); 1712 } 1713 break; 1211 1714 case 0: 1212 q->logMessage(format("'%1' is not a function").arg(func));1715 q->logMessage(format("'%1' is not a recognized replace function").arg(func)); 1213 1716 break; 1214 1717 default: … … 1220 1723 } 1221 1724 1222 bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &function, 1223 const QString &arguments, bool *result)1725 ProItem::ProItemReturn ProFileEvaluator::Private::evaluateConditionalFunction( 1726 const QString &function, const QString &arguments) 1224 1727 { 1225 1728 QStringList argumentsList = split_arg_list(arguments); 1729 1730 if (ProBlock *funcPtr = m_testFunctions.value(function, 0)) { 1731 bool ok; 1732 QStringList ret = evaluateFunction(funcPtr, argumentsList, &ok); 1733 if (ok) { 1734 if (ret.isEmpty()) { 1735 return ProItem::ReturnTrue; 1736 } else { 1737 if (ret.first() != QLatin1String("false")) { 1738 if (ret.first() == QLatin1String("true")) { 1739 return ProItem::ReturnTrue; 1740 } else { 1741 bool ok; 1742 int val = ret.first().toInt(&ok); 1743 if (ok) { 1744 if (val) 1745 return ProItem::ReturnTrue; 1746 } else { 1747 q->logMessage(format("Unexpected return value from test '%1': %2") 1748 .arg(function).arg(ret.join(QLatin1String(" :: ")))); 1749 } 1750 } 1751 } 1752 } 1753 } 1754 return ProItem::ReturnFalse; 1755 } 1756 1226 1757 QString sep; 1227 1758 sep.append(Option::field_sep); 1228 1229 1759 QStringList args; 1230 1760 for (int i = 0; i < argumentsList.count(); ++i) 1231 1761 args += expandVariableReferences(argumentsList[i]).join(sep); 1232 1762 1233 enum ConditionFunc { CF_CONFIG = 1, CF_CONTAINS, CF_COUNT, CF_EXISTS, CF_INCLUDE, 1234 CF_LOAD, CF_ISEMPTY, CF_SYSTEM, CF_MESSAGE}; 1235 1236 static QHash<QString, int> *functions = 0; 1237 if (!functions) { 1238 functions = new QHash<QString, int>; 1239 functions->insert(QLatin1String("load"), CF_LOAD); //v 1240 functions->insert(QLatin1String("include"), CF_INCLUDE); //v 1241 functions->insert(QLatin1String("message"), CF_MESSAGE); //v 1242 functions->insert(QLatin1String("warning"), CF_MESSAGE); //v 1243 functions->insert(QLatin1String("error"), CF_MESSAGE); //v 1244 } 1245 1246 bool cond = false; 1247 bool ok = true; 1248 1249 ConditionFunc func_t = (ConditionFunc)functions->value(function); 1763 enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS, 1764 T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM, 1765 T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE, 1766 T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF, 1767 T_FOR, T_DEFINE_TEST, T_DEFINE_REPLACE }; 1768 1769 static QHash<QString, int> functions; 1770 if (functions.isEmpty()) { 1771 functions.insert(QLatin1String("requires"), T_REQUIRES); 1772 functions.insert(QLatin1String("greaterThan"), T_GREATERTHAN); 1773 functions.insert(QLatin1String("lessThan"), T_LESSTHAN); 1774 functions.insert(QLatin1String("equals"), T_EQUALS); 1775 functions.insert(QLatin1String("isEqual"), T_EQUALS); 1776 functions.insert(QLatin1String("exists"), T_EXISTS); 1777 functions.insert(QLatin1String("export"), T_EXPORT); 1778 functions.insert(QLatin1String("clear"), T_CLEAR); 1779 functions.insert(QLatin1String("unset"), T_UNSET); 1780 functions.insert(QLatin1String("eval"), T_EVAL); 1781 functions.insert(QLatin1String("CONFIG"), T_CONFIG); 1782 functions.insert(QLatin1String("if"), T_IF); 1783 functions.insert(QLatin1String("isActiveConfig"), T_CONFIG); 1784 functions.insert(QLatin1String("system"), T_SYSTEM); 1785 functions.insert(QLatin1String("return"), T_RETURN); 1786 functions.insert(QLatin1String("break"), T_BREAK); 1787 functions.insert(QLatin1String("next"), T_NEXT); 1788 functions.insert(QLatin1String("defined"), T_DEFINED); 1789 functions.insert(QLatin1String("contains"), T_CONTAINS); 1790 functions.insert(QLatin1String("infile"), T_INFILE); 1791 functions.insert(QLatin1String("count"), T_COUNT); 1792 functions.insert(QLatin1String("isEmpty"), T_ISEMPTY); 1793 functions.insert(QLatin1String("load"), T_LOAD); //v 1794 functions.insert(QLatin1String("include"), T_INCLUDE); //v 1795 functions.insert(QLatin1String("debug"), T_DEBUG); 1796 functions.insert(QLatin1String("message"), T_MESSAGE); //v 1797 functions.insert(QLatin1String("warning"), T_MESSAGE); //v 1798 functions.insert(QLatin1String("error"), T_MESSAGE); //v 1799 functions.insert(QLatin1String("for"), T_FOR); //v 1800 functions.insert(QLatin1String("defineTest"), T_DEFINE_TEST); //v 1801 functions.insert(QLatin1String("defineReplace"), T_DEFINE_REPLACE); //v 1802 } 1803 1804 TestFunc func_t = (TestFunc)functions.value(function); 1250 1805 1251 1806 switch (func_t) { 1252 case CF_CONFIG: { 1807 case T_DEFINE_TEST: 1808 m_definingTest = true; 1809 goto defineFunc; 1810 case T_DEFINE_REPLACE: 1811 m_definingTest = false; 1812 defineFunc: 1813 if (args.count() != 1) { 1814 q->logMessage(format("%s(function) requires one argument.").arg(function)); 1815 return ProItem::ReturnFalse; 1816 } 1817 m_definingFunc = args.first(); 1818 return ProItem::ReturnTrue; 1819 case T_DEFINED: 1820 if (args.count() < 1 || args.count() > 2) { 1821 q->logMessage(format("defined(function, [\"test\"|\"replace\"])" 1822 " requires one or two arguments.")); 1823 return ProItem::ReturnFalse; 1824 } 1825 if (args.count() > 1) { 1826 if (args[1] == QLatin1String("test")) 1827 return returnBool(m_testFunctions.contains(args[0])); 1828 else if (args[1] == QLatin1String("replace")) 1829 return returnBool(m_replaceFunctions.contains(args[0])); 1830 q->logMessage(format("defined(function, type):" 1831 " unexpected type [%1].\n").arg(args[1])); 1832 return ProItem::ReturnFalse; 1833 } 1834 return returnBool(m_replaceFunctions.contains(args[0]) 1835 || m_testFunctions.contains(args[0])); 1836 case T_RETURN: 1837 m_returnValue = args; 1838 // It is "safe" to ignore returns - due to qmake brokeness 1839 // they cannot be used to terminate loops anyway. 1840 if (m_skipLevel || m_cumulative) 1841 return ProItem::ReturnTrue; 1842 if (m_valuemapStack.isEmpty()) { 1843 q->logMessage(format("unexpected return().")); 1844 return ProItem::ReturnFalse; 1845 } 1846 return ProItem::ReturnReturn; 1847 case T_EXPORT: 1848 if (m_skipLevel && !m_cumulative) 1849 return ProItem::ReturnTrue; 1850 if (args.count() != 1) { 1851 q->logMessage(format("export(variable) requires one argument.")); 1852 return ProItem::ReturnFalse; 1853 } 1854 for (int i = 0; i < m_valuemapStack.size(); ++i) { 1855 m_valuemapStack[i][args[0]] = m_valuemap[args[0]]; 1856 m_filevaluemapStack[i][currentProFile()][args[0]] = 1857 m_filevaluemap[currentProFile()][args[0]]; 1858 } 1859 return ProItem::ReturnTrue; 1860 #if 0 1861 case T_INFILE: 1862 case T_REQUIRES: 1863 case T_EVAL: 1864 #endif 1865 case T_FOR: { 1866 if (m_cumulative) // This is a no-win situation, so just pretend it's no loop 1867 return ProItem::ReturnTrue; 1868 if (m_skipLevel) 1869 return ProItem::ReturnFalse; 1870 if (args.count() > 2 || args.count() < 1) { 1871 q->logMessage(format("for({var, list|var, forever|ever})" 1872 " requires one or two arguments.")); 1873 return ProItem::ReturnFalse; 1874 } 1875 ProLoop loop; 1876 loop.infinite = false; 1877 loop.index = 0; 1878 QString it_list; 1879 if (args.count() == 1) { 1880 doVariableReplace(&args[0]); 1881 it_list = args[0]; 1882 if (args[0] != QLatin1String("ever")) { 1883 q->logMessage(format("for({var, list|var, forever|ever})" 1884 " requires one or two arguments.")); 1885 return ProItem::ReturnFalse; 1886 } 1887 it_list = QLatin1String("forever"); 1888 } else { 1889 loop.variable = args[0]; 1890 loop.oldVarVal = m_valuemap.value(loop.variable); 1891 doVariableReplace(&args[1]); 1892 it_list = args[1]; 1893 } 1894 loop.list = m_valuemap[it_list]; 1895 if (loop.list.isEmpty()) { 1896 if (it_list == QLatin1String("forever")) { 1897 loop.infinite = true; 1898 } else { 1899 int dotdot = it_list.indexOf(QLatin1String("..")); 1900 if (dotdot != -1) { 1901 bool ok; 1902 int start = it_list.left(dotdot).toInt(&ok); 1903 if (ok) { 1904 int end = it_list.mid(dotdot+2).toInt(&ok); 1905 if (ok) { 1906 if (start < end) { 1907 for (int i = start; i <= end; i++) 1908 loop.list << QString::number(i); 1909 } else { 1910 for (int i = start; i >= end; i--) 1911 loop.list << QString::number(i); 1912 } 1913 } 1914 } 1915 } 1916 } 1917 } 1918 m_loopStack.push(loop); 1919 m_sts.condition = true; 1920 return ProItem::ReturnLoop; 1921 } 1922 case T_BREAK: 1923 if (m_skipLevel) 1924 return ProItem::ReturnFalse; 1925 if (!m_loopStack.isEmpty()) 1926 return ProItem::ReturnBreak; 1927 // ### missing: breaking out of multiline blocks 1928 q->logMessage(format("unexpected break().")); 1929 return ProItem::ReturnFalse; 1930 case T_NEXT: 1931 if (m_skipLevel) 1932 return ProItem::ReturnFalse; 1933 if (!m_loopStack.isEmpty()) 1934 return ProItem::ReturnNext; 1935 q->logMessage(format("unexpected next().")); 1936 return ProItem::ReturnFalse; 1937 case T_IF: { 1938 if (args.count() != 1) { 1939 q->logMessage(format("if(condition) requires one argument.")); 1940 return ProItem::ReturnFalse; 1941 } 1942 QString cond = args.first(); 1943 bool escaped = false; // This is more than qmake does 1944 bool quoted = false; 1945 bool ret = true; 1946 bool orOp = false; 1947 bool invert = false; 1948 bool isFunc = false; 1949 int parens = 0; 1950 QString test; 1951 test.reserve(20); 1952 QString args; 1953 args.reserve(50); 1954 const QChar *d = cond.unicode(); 1955 const QChar *ed = d + cond.length(); 1956 while (d < ed) { 1957 ushort c = (d++)->unicode(); 1958 if (!escaped) { 1959 if (c == '\\') { 1960 escaped = true; 1961 args += c; // Assume no-one quotes the test name 1962 continue; 1963 } else if (c == '"') { 1964 quoted = !quoted; 1965 args += c; // Ditto 1966 continue; 1967 } 1968 } else { 1969 escaped = false; 1970 } 1971 if (quoted) { 1972 args += c; // Ditto 1973 } else { 1974 bool isOp = false; 1975 if (c == '(') { 1976 isFunc = true; 1977 if (parens) 1978 args += c; 1979 ++parens; 1980 } else if (c == ')') { 1981 --parens; 1982 if (parens) 1983 args += c; 1984 } else if (!parens) { 1985 if (c == ':' || c == '|') 1986 isOp = true; 1987 else if (c == '!') 1988 invert = true; 1989 else 1990 test += c; 1991 } else { 1992 args += c; 1993 } 1994 if (!parens && (isOp || d == ed)) { 1995 // Yes, qmake doesn't shortcut evaluations here. We can't, either, 1996 // as some test functions have side effects. 1997 bool success; 1998 if (isFunc) { 1999 success = evaluateConditionalFunction(test, args); 2000 } else { 2001 success = isActiveConfig(test, true); 2002 } 2003 success ^= invert; 2004 if (orOp) 2005 ret |= success; 2006 else 2007 ret &= success; 2008 orOp = (c == '|'); 2009 invert = false; 2010 isFunc = false; 2011 test.clear(); 2012 args.clear(); 2013 } 2014 } 2015 } 2016 return returnBool(ret); 2017 } 2018 case T_CONFIG: { 1253 2019 if (args.count() < 1 || args.count() > 2) { 1254 2020 q->logMessage(format("CONFIG(config) requires one or two arguments.")); 1255 ok = false; 1256 break; 2021 return ProItem::ReturnFalse; 1257 2022 } 1258 2023 if (args.count() == 1) { 1259 2024 //cond = isActiveConfig(args.first()); XXX 1260 break;2025 return ProItem::ReturnFalse; 1261 2026 } 1262 2027 const QStringList mutuals = args[1].split(QLatin1Char('|')); 1263 2028 const QStringList &configs = valuesDirect(QLatin1String("CONFIG")); 1264 for (int i = configs.size() - 1 && ok; i >= 0; i--) {2029 for (int i = configs.size() - 1; i >= 0; i--) { 1265 2030 for (int mut = 0; mut < mutuals.count(); mut++) { 1266 2031 if (configs[i] == mutuals[mut].trimmed()) { 1267 cond = (configs[i] == args[0]); 1268 goto done_T_CONFIG; 2032 return returnBool(configs[i] == args[0]); 1269 2033 } 1270 2034 } 1271 2035 } 1272 done_T_CONFIG: 1273 break; 1274 } 1275 case CF_CONTAINS: { 2036 return ProItem::ReturnFalse; 2037 } 2038 case T_CONTAINS: { 1276 2039 if (args.count() < 2 || args.count() > 3) { 1277 2040 q->logMessage(format("contains(var, val) requires two or three arguments.")); 1278 ok = false; 1279 break; 2041 return ProItem::ReturnFalse; 1280 2042 } 1281 2043 … … 1286 2048 const QString val = l[i]; 1287 2049 if (regx.exactMatch(val) || val == args[1]) { 1288 cond = true; 1289 break; 2050 return ProItem::ReturnTrue; 1290 2051 } 1291 2052 } … … 1296 2057 for (int mut = 0; mut < mutuals.count(); mut++) { 1297 2058 if (val == mutuals[mut].trimmed()) { 1298 cond = (regx.exactMatch(val) || val == args[1]); 1299 goto done_T_CONTAINS; 2059 return returnBool(regx.exactMatch(val) || val == args[1]); 1300 2060 } 1301 2061 } 1302 2062 } 1303 2063 } 1304 done_T_CONTAINS: 1305 break; 1306 } 1307 case CF_COUNT: { 2064 return ProItem::ReturnFalse; 2065 } 2066 case T_COUNT: { 1308 2067 if (args.count() != 2 && args.count() != 3) { 1309 q->logMessage(format("count(var, count) requires two or three arguments.")); 1310 ok = false; 1311 break; 2068 q->logMessage(format("count(var, count, op=\"equals\") requires two or three arguments.")); 2069 return ProItem::ReturnFalse; 1312 2070 } 1313 2071 if (args.count() == 3) { 1314 2072 QString comp = args[2]; 1315 2073 if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) { 1316 cond = values(args.first()).count() > args[1].toInt();2074 return returnBool(values(args.first()).count() > args[1].toInt()); 1317 2075 } else if (comp == QLatin1String(">=")) { 1318 cond = values(args.first()).count() >= args[1].toInt();2076 return returnBool(values(args.first()).count() >= args[1].toInt()); 1319 2077 } else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) { 1320 cond = values(args.first()).count() < args[1].toInt();2078 return returnBool(values(args.first()).count() < args[1].toInt()); 1321 2079 } else if (comp == QLatin1String("<=")) { 1322 cond = values(args.first()).count() <= args[1].toInt(); 1323 } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") || comp == QLatin1String("=") || comp == QLatin1String("==")) { 1324 cond = values(args.first()).count() == args[1].toInt(); 2080 return returnBool(values(args.first()).count() <= args[1].toInt()); 2081 } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") 2082 || comp == QLatin1String("=") || comp == QLatin1String("==")) { 2083 return returnBool(values(args.first()).count() == args[1].toInt()); 1325 2084 } else { 1326 ok = false;1327 2085 q->logMessage(format("unexpected modifier to count(%2)").arg(comp)); 1328 } 1329 break; 1330 } 1331 cond = values(args.first()).count() == args[1].toInt(); 1332 break; 1333 } 1334 case CF_INCLUDE: { 2086 return ProItem::ReturnFalse; 2087 } 2088 } 2089 return returnBool(values(args.first()).count() == args[1].toInt()); 2090 } 2091 case T_GREATERTHAN: 2092 case T_LESSTHAN: { 2093 if (args.count() != 2) { 2094 q->logMessage(format("%1(variable, value) requires two arguments.").arg(function)); 2095 return ProItem::ReturnFalse; 2096 } 2097 QString rhs(args[1]), lhs(values(args[0]).join(QString(Option::field_sep))); 2098 bool ok; 2099 int rhs_int = rhs.toInt(&ok); 2100 if (ok) { // do integer compare 2101 int lhs_int = lhs.toInt(&ok); 2102 if (ok) { 2103 if (func_t == T_GREATERTHAN) 2104 return returnBool(lhs_int > rhs_int); 2105 return returnBool(lhs_int < rhs_int); 2106 } 2107 } 2108 if (func_t == T_GREATERTHAN) 2109 return returnBool(lhs > rhs); 2110 return returnBool(lhs < rhs); 2111 } 2112 case T_EQUALS: 2113 if (args.count() != 2) { 2114 q->logMessage(format("%1(variable, value) requires two arguments.").arg(function)); 2115 return ProItem::ReturnFalse; 2116 } 2117 return returnBool(values(args[0]).join(QString(Option::field_sep)) == args[1]); 2118 case T_CLEAR: { 2119 if (m_skipLevel && !m_cumulative) 2120 return ProItem::ReturnFalse; 2121 if (args.count() != 1) { 2122 q->logMessage(format("%1(variable) requires one argument.").arg(function)); 2123 return ProItem::ReturnFalse; 2124 } 2125 QHash<QString, QStringList>::Iterator it = m_valuemap.find(args[0]); 2126 if (it == m_valuemap.end()) 2127 return ProItem::ReturnFalse; 2128 it->clear(); 2129 return ProItem::ReturnTrue; 2130 } 2131 case T_UNSET: { 2132 if (m_skipLevel && !m_cumulative) 2133 return ProItem::ReturnFalse; 2134 if (args.count() != 1) { 2135 q->logMessage(format("%1(variable) requires one argument.").arg(function)); 2136 return ProItem::ReturnFalse; 2137 } 2138 QHash<QString, QStringList>::Iterator it = m_valuemap.find(args[0]); 2139 if (it == m_valuemap.end()) 2140 return ProItem::ReturnFalse; 2141 m_valuemap.erase(it); 2142 return ProItem::ReturnTrue; 2143 } 2144 case T_INCLUDE: { 2145 if (m_skipLevel && !m_cumulative) 2146 return ProItem::ReturnFalse; 1335 2147 QString parseInto; 1336 if (args.count() == 2) { 2148 // the third optional argument to include() controls warnings 2149 // and is not used here 2150 if ((args.count() == 2) || (args.count() == 3)) { 1337 2151 parseInto = args[1]; 1338 2152 } else if (args.count() != 1) { 1339 q->logMessage(format("include(file) requires one or two arguments.")); 1340 ok = false; 1341 break; 2153 q->logMessage(format("include(file) requires one, two or three arguments.")); 2154 return ProItem::ReturnFalse; 1342 2155 } 1343 2156 QString fileName = args.first(); 1344 2157 // ### this breaks if we have include(c:/reallystupid.pri) but IMHO that's really bad style. 1345 QDir currentProPath( getcwd());2158 QDir currentProPath(currentDirectory()); 1346 2159 fileName = QDir::cleanPath(currentProPath.absoluteFilePath(fileName)); 1347 ok = evaluateFile(fileName, &ok); 1348 break; 1349 } 1350 case CF_LOAD: { 2160 State sts = m_sts; 2161 bool ok = evaluateFile(fileName); 2162 m_sts = sts; 2163 return returnBool(ok); 2164 } 2165 case T_LOAD: { 2166 if (m_skipLevel && !m_cumulative) 2167 return ProItem::ReturnFalse; 1351 2168 QString parseInto; 1352 2169 bool ignore_error = false; 1353 2170 if (args.count() == 2) { 1354 2171 QString sarg = args[1]; 1355 ignore_error = ( sarg.toLower() == QLatin1String("true") || sarg.toInt());2172 ignore_error = (!sarg.compare(QLatin1String("true"), Qt::CaseInsensitive) || sarg.toInt()); 1356 2173 } else if (args.count() != 1) { 1357 2174 q->logMessage(format("load(feature) requires one or two arguments.")); 1358 ok = false; 1359 break; 1360 } 1361 ok = evaluateFeatureFile( args.first(), &cond); 1362 break; 1363 } 1364 case CF_MESSAGE: { 2175 return ProItem::ReturnFalse; 2176 } 2177 // XXX ignore_error unused 2178 return returnBool(evaluateFeatureFile(args.first())); 2179 } 2180 case T_DEBUG: 2181 // Yup - do nothing. Nothing is going to enable debug output anyway. 2182 return ProItem::ReturnFalse; 2183 case T_MESSAGE: { 1365 2184 if (args.count() != 1) { 1366 2185 q->logMessage(format("%1(message) requires one argument.").arg(function)); 1367 ok = false; 1368 break; 1369 } 1370 QString msg = args.first(); 1371 if (function == QLatin1String("error")) { 1372 QStringList parents; 1373 foreach (ProFile *proFile, m_profileStack) 1374 parents.append(proFile->fileName()); 1375 if (!parents.isEmpty()) 1376 parents.takeLast(); 1377 if (parents.isEmpty()) 1378 q->fileMessage(format("Project ERROR: %1").arg(msg)); 1379 else 1380 q->fileMessage(format("Project ERROR: %1. File was included from: '%2'") 1381 .arg(msg).arg(parents.join(QLatin1String("', '")))); 1382 } else { 1383 q->fileMessage(format("Project MESSAGE: %1").arg(msg)); 1384 } 1385 break; 1386 } 1387 case CF_SYSTEM: { 2186 return ProItem::ReturnFalse; 2187 } 2188 QString msg = fixEnvVariables(args.first()); 2189 q->fileMessage(QString::fromLatin1("Project %1: %2").arg(function.toUpper(), msg)); 2190 // ### Consider real termination in non-cumulative mode 2191 return returnBool(function != QLatin1String("error")); 2192 } 2193 #if 0 // Way too dangerous to enable. 2194 case T_SYSTEM: { 1388 2195 if (args.count() != 1) { 1389 2196 q->logMessage(format("system(exec) requires one argument.")); 1390 ok = false; 1391 break; 1392 } 1393 ok = system(args.first().toLatin1().constData()) == 0; 1394 break; 1395 } 1396 case CF_ISEMPTY: { 2197 ProItem::ReturnFalse; 2198 } 2199 return returnBool(system(args.first().toLatin1().constData()) == 0); 2200 } 2201 #endif 2202 case T_ISEMPTY: { 1397 2203 if (args.count() != 1) { 1398 2204 q->logMessage(format("isEmpty(var) requires one argument.")); 1399 ok = false; 1400 break; 2205 return ProItem::ReturnFalse; 1401 2206 } 1402 2207 QStringList sl = values(args.first()); 1403 2208 if (sl.count() == 0) { 1404 cond = true;2209 return ProItem::ReturnTrue; 1405 2210 } else if (sl.count() > 0) { 1406 2211 QString var = sl.first(); 1407 cond = (var.isEmpty()); 1408 } 1409 break; 1410 } 1411 case CF_EXISTS: { 2212 if (var.isEmpty()) 2213 return ProItem::ReturnTrue; 2214 } 2215 return ProItem::ReturnFalse; 2216 } 2217 case T_EXISTS: { 1412 2218 if (args.count() != 1) { 1413 2219 q->logMessage(format("exists(file) requires one argument.")); 1414 ok = false; 1415 break; 2220 return ProItem::ReturnFalse; 1416 2221 } 1417 2222 QString file = args.first(); 1418 1419 file = QDir::cleanPath(file); 2223 file = Option::fixPathToLocalOS(file); 1420 2224 1421 2225 if (QFile::exists(file)) { 1422 cond = true; 1423 break; 2226 return ProItem::ReturnTrue; 1424 2227 } 1425 2228 //regular expression I guess 1426 QString dirstr = getcwd();2229 QString dirstr = currentDirectory(); 1427 2230 int slsh = file.lastIndexOf(Option::dir_sep); 1428 2231 if (slsh != -1) { … … 1430 2233 file = file.right(file.length() - slsh - 1); 1431 2234 } 1432 cond = QDir(dirstr).entryList(QStringList(file)).count(); 1433 1434 break; 1435 } 1436 } 1437 1438 if (result) 1439 *result = cond; 1440 1441 return ok; 2235 if (file.contains(QLatin1Char('*')) || file.contains(QLatin1Char('?'))) 2236 if (!QDir(dirstr).entryList(QStringList(file)).isEmpty()) 2237 return ProItem::ReturnTrue; 2238 2239 return ProItem::ReturnFalse; 2240 } 2241 case 0: 2242 q->logMessage(format("'%1' is not a recognized test function").arg(function)); 2243 return ProItem::ReturnFalse; 2244 default: 2245 q->logMessage(format("Function '%1' is not implemented").arg(function)); 2246 return ProItem::ReturnFalse; 2247 } 2248 } 2249 2250 QStringList ProFileEvaluator::Private::values(const QString &variableName, 2251 const QHash<QString, QStringList> &place, 2252 const ProFile *pro) const 2253 { 2254 if (variableName == QLatin1String("LITERAL_WHITESPACE")) //a real space in a token 2255 return QStringList(QLatin1String("\t")); 2256 if (variableName == QLatin1String("LITERAL_DOLLAR")) //a real $ 2257 return QStringList(QLatin1String("$")); 2258 if (variableName == QLatin1String("LITERAL_HASH")) //a real # 2259 return QStringList(QLatin1String("#")); 2260 if (variableName == QLatin1String("OUT_PWD")) //the out going dir 2261 return QStringList(m_outputDir); 2262 if (variableName == QLatin1String("PWD") || //current working dir (of _FILE_) 2263 variableName == QLatin1String("IN_PWD")) 2264 return QStringList(currentDirectory()); 2265 if (variableName == QLatin1String("DIR_SEPARATOR")) 2266 return QStringList(Option::dir_sep); 2267 if (variableName == QLatin1String("DIRLIST_SEPARATOR")) 2268 return QStringList(Option::dirlist_sep); 2269 if (variableName == QLatin1String("_LINE_")) //parser line number 2270 return QStringList(QString::number(m_lineNo)); 2271 if (variableName == QLatin1String("_FILE_")) //parser file; qmake is a bit weird here 2272 return QStringList(m_profileStack.size() == 1 ? pro->fileName() : QFileInfo(pro->fileName()).fileName()); 2273 if (variableName == QLatin1String("_DATE_")) //current date/time 2274 return QStringList(QDateTime::currentDateTime().toString()); 2275 if (variableName == QLatin1String("_PRO_FILE_")) 2276 return QStringList(m_origfile); 2277 if (variableName == QLatin1String("_PRO_FILE_PWD_")) 2278 return QStringList(QFileInfo(m_origfile).absolutePath()); 2279 if (variableName == QLatin1String("_QMAKE_CACHE_")) 2280 return QStringList(); // FIXME? 2281 if (variableName.startsWith(QLatin1String("QMAKE_HOST."))) { 2282 QString ret, type = variableName.mid(11); 2283 #if defined(Q_OS_WIN32) 2284 if (type == QLatin1String("os")) { 2285 ret = QLatin1String("Windows"); 2286 } else if (type == QLatin1String("name")) { 2287 DWORD name_length = 1024; 2288 wchar_t name[1024]; 2289 if (GetComputerName(name, &name_length)) 2290 ret = QString::fromWCharArray(name); 2291 } else if (type == QLatin1String("version") || type == QLatin1String("version_string")) { 2292 QSysInfo::WinVersion ver = QSysInfo::WindowsVersion; 2293 if (type == QLatin1String("version")) 2294 ret = QString::number(ver); 2295 else if (ver == QSysInfo::WV_Me) 2296 ret = QLatin1String("WinMe"); 2297 else if (ver == QSysInfo::WV_95) 2298 ret = QLatin1String("Win95"); 2299 else if (ver == QSysInfo::WV_98) 2300 ret = QLatin1String("Win98"); 2301 else if (ver == QSysInfo::WV_NT) 2302 ret = QLatin1String("WinNT"); 2303 else if (ver == QSysInfo::WV_2000) 2304 ret = QLatin1String("Win2000"); 2305 else if (ver == QSysInfo::WV_2000) 2306 ret = QLatin1String("Win2003"); 2307 else if (ver == QSysInfo::WV_XP) 2308 ret = QLatin1String("WinXP"); 2309 else if (ver == QSysInfo::WV_VISTA) 2310 ret = QLatin1String("WinVista"); 2311 else 2312 ret = QLatin1String("Unknown"); 2313 } else if (type == QLatin1String("arch")) { 2314 SYSTEM_INFO info; 2315 GetSystemInfo(&info); 2316 switch(info.wProcessorArchitecture) { 2317 #ifdef PROCESSOR_ARCHITECTURE_AMD64 2318 case PROCESSOR_ARCHITECTURE_AMD64: 2319 ret = QLatin1String("x86_64"); 2320 break; 2321 #endif 2322 case PROCESSOR_ARCHITECTURE_INTEL: 2323 ret = QLatin1String("x86"); 2324 break; 2325 case PROCESSOR_ARCHITECTURE_IA64: 2326 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 2327 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: 2328 #endif 2329 ret = QLatin1String("IA64"); 2330 break; 2331 default: 2332 ret = QLatin1String("Unknown"); 2333 break; 2334 } 2335 } 2336 #elif defined(Q_OS_UNIX) 2337 struct utsname name; 2338 if (!uname(&name)) { 2339 if (type == QLatin1String("os")) 2340 ret = QString::fromLatin1(name.sysname); 2341 else if (type == QLatin1String("name")) 2342 ret = QString::fromLatin1(name.nodename); 2343 else if (type == QLatin1String("version")) 2344 ret = QString::fromLatin1(name.release); 2345 else if (type == QLatin1String("version_string")) 2346 ret = QString::fromLatin1(name.version); 2347 else if (type == QLatin1String("arch")) 2348 ret = QString::fromLatin1(name.machine); 2349 } 2350 #endif 2351 return QStringList(ret); 2352 } 2353 2354 QStringList result = place[variableName]; 2355 if (result.isEmpty()) { 2356 if (variableName == QLatin1String("TARGET")) { 2357 result.append(QFileInfo(m_origfile).baseName()); 2358 } else if (variableName == QLatin1String("TEMPLATE")) { 2359 result.append(QLatin1String("app")); 2360 } else if (variableName == QLatin1String("QMAKE_DIR_SEP")) { 2361 result.append(Option::dirlist_sep); 2362 } 2363 } 2364 return result; 1442 2365 } 1443 2366 1444 2367 QStringList ProFileEvaluator::Private::values(const QString &variableName) const 1445 2368 { 1446 if (variableName == QLatin1String("TARGET")) { 1447 QStringList list = m_valuemap.value(variableName); 1448 if (!m_origfile.isEmpty()) 1449 list.append(QFileInfo(m_origfile).baseName()); 1450 return list; 1451 } 1452 if (variableName == QLatin1String("PWD")) { 1453 return QStringList(getcwd()); 1454 } 1455 return m_valuemap.value(variableName); 2369 return values(variableName, m_valuemap, currentProFile()); 1456 2370 } 1457 2371 1458 2372 QStringList ProFileEvaluator::Private::values(const QString &variableName, const ProFile *pro) const 1459 2373 { 1460 if (variableName == QLatin1String("TARGET")) { 1461 QStringList list = m_filevaluemap[pro].value(variableName); 1462 if (!m_origfile.isEmpty()) 1463 list.append(QFileInfo(m_origfile).baseName()); 1464 return list; 1465 } 1466 if (variableName == QLatin1String("PWD")) { 1467 return QStringList(QFileInfo(pro->fileName()).absoluteFilePath()); 1468 } 1469 return m_filevaluemap[pro].value(variableName); 2374 return values(variableName, m_filevaluemap[pro], pro); 1470 2375 } 1471 2376 … … 1474 2379 QFileInfo fi(fileName); 1475 2380 if (fi.exists()) { 1476 ProFile *pro = new ProFile(fi.absoluteFilePath()); 2381 QString fn = QDir::cleanPath(fi.absoluteFilePath()); 2382 foreach (const ProFile *pf, d->m_profileStack) 2383 if (pf->fileName() == fn) { 2384 errorMessage(d->format("circular inclusion of %1").arg(fn)); 2385 return 0; 2386 } 2387 ProFile *pro = new ProFile(fn); 1477 2388 if (d->read(pro)) 1478 2389 return pro; … … 1487 2398 } 1488 2399 1489 bool ProFileEvaluator::Private::evaluateFile(const QString &fileName, bool *result) 1490 { 1491 bool ok = true; 2400 bool ProFileEvaluator::Private::evaluateFile(const QString &fileName) 2401 { 1492 2402 ProFile *pro = q->parsedProFile(fileName); 1493 2403 if (pro) { 1494 2404 m_profileStack.push(pro); 1495 ok = (currentProFile() ? pro->Accept(this) : false);2405 bool ok = (pro->Accept(this) == ProItem::ReturnTrue); 1496 2406 m_profileStack.pop(); 1497 2407 q->releaseParsedProFile(pro); 1498 1499 if (result) 1500 *result = true; 2408 return ok; 1501 2409 } else { 1502 if (result) 1503 *result = false; 1504 } 1505 /* if (ok && readFeatures) { 1506 QStringList configs = values("CONFIG"); 1507 QSet<QString> processed; 1508 foreach (const QString &fn, configs) { 1509 if (!processed.contains(fn)) { 1510 processed.insert(fn); 1511 evaluateFeatureFile(fn, 0); 1512 } 1513 } 1514 } */ 1515 1516 return ok; 1517 } 1518 1519 bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName, bool *result) 2410 return false; 2411 } 2412 } 2413 2414 bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName) 1520 2415 { 1521 2416 QString fn; … … 1532 2427 } 1533 2428 } 1534 return fn.isEmpty() ? false : evaluateFile(fn, result); 1535 } 1536 1537 void ProFileEvaluator::Private::expandPatternHelper(const QString &relName, const QString &absName, 1538 QStringList &sources_out) 1539 { 1540 const QStringList vpaths = values(QLatin1String("VPATH")) 1541 + values(QLatin1String("QMAKE_ABSOLUTE_SOURCE_PATH")) 1542 + values(QLatin1String("DEPENDPATH")) 1543 + values(QLatin1String("VPATH_SOURCES")); 1544 1545 QFileInfo fi(absName); 1546 bool found = fi.exists(); 1547 // Search in all vpaths 1548 if (!found) { 1549 foreach (const QString &vpath, vpaths) { 1550 fi.setFile(vpath + QDir::separator() + relName); 1551 if (fi.exists()) { 1552 found = true; 1553 break; 1554 } 1555 } 1556 } 1557 1558 if (found) { 1559 sources_out += fi.absoluteFilePath(); // Not resolving symlinks 1560 } else { 1561 QString val = relName; 1562 QString dir; 1563 QString wildcard = val; 1564 QString real_dir; 1565 if (wildcard.lastIndexOf(QLatin1Char('/')) != -1) { 1566 dir = wildcard.left(wildcard.lastIndexOf(QLatin1Char('/')) + 1); 1567 real_dir = dir; 1568 wildcard = wildcard.right(wildcard.length() - dir.length()); 1569 } 1570 1571 if (real_dir.isEmpty() || QFileInfo(real_dir).exists()) { 1572 QStringList files = QDir(real_dir).entryList(QStringList(wildcard)); 1573 if (files.isEmpty()) { 1574 q->logMessage(format("Failure to find %1").arg(val)); 1575 } else { 1576 QString a; 1577 for (int i = files.count() - 1; i >= 0; --i) { 1578 if (files[i] == QLatin1String(".") || files[i] == QLatin1String("..")) 1579 continue; 1580 a = dir + files[i]; 1581 sources_out += a; 1582 } 1583 } 1584 } else { 1585 q->logMessage(format("Cannot match %1/%2, as %3 does not exist.") 1586 .arg(real_dir).arg(wildcard).arg(real_dir)); 1587 } 1588 } 1589 } 1590 1591 1592 /* 1593 * Lookup of files are done in this order: 1594 * 1. look in pwd 1595 * 2. look in vpaths 1596 * 3. expand wild card files relative from the profiles folder 1597 **/ 1598 1599 // FIXME: This code supports something that I'd consider a flaw in .pro file syntax 1600 // which is not even documented. So arguably this can be ditched completely... 1601 QStringList ProFileEvaluator::Private::expandPattern(const QString& pattern) 1602 { 1603 if (!currentProFile()) 1604 return QStringList(); 1605 1606 QStringList sources_out; 1607 const QString absName = QDir::cleanPath(QDir::current().absoluteFilePath(pattern)); 1608 1609 expandPatternHelper(pattern, absName, sources_out); 1610 return sources_out; 2429 if (fn.isEmpty()) 2430 return false; 2431 bool cumulative = m_cumulative; 2432 m_cumulative = false; 2433 bool ok = evaluateFile(fn); 2434 m_cumulative = cumulative; 2435 return ok; 1611 2436 } 1612 2437 … … 1642 2467 } 1643 2468 2469 inline QStringList fixEnvVariables(const QStringList &x) 2470 { 2471 QStringList ret; 2472 foreach (const QString &str, x) 2473 ret << Option::fixString(str, Option::FixEnvVars); 2474 return ret; 2475 } 2476 2477 1644 2478 QStringList ProFileEvaluator::values(const QString &variableName) const 1645 2479 { 1646 return d->values(variableName);2480 return fixEnvVariables(d->values(variableName)); 1647 2481 } 1648 2482 1649 2483 QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const 1650 2484 { 1651 return d->values(variableName, pro); 2485 return fixEnvVariables(d->values(variableName, pro)); 2486 } 2487 2488 QStringList ProFileEvaluator::absolutePathValues( 2489 const QString &variable, const QString &baseDirectory) const 2490 { 2491 QStringList result; 2492 foreach (const QString &el, values(variable)) { 2493 const QFileInfo info = QFileInfo(baseDirectory, el); 2494 if (info.isDir()) 2495 result << QDir::cleanPath(info.absoluteFilePath()); 2496 } 2497 return result; 2498 } 2499 2500 QStringList ProFileEvaluator::absoluteFileValues( 2501 const QString &variable, const QString &baseDirectory, const QStringList &searchDirs, 2502 const ProFile *pro) const 2503 { 2504 QStringList result; 2505 foreach (const QString &el, pro ? values(variable, pro) : values(variable)) { 2506 QFileInfo info(el); 2507 if (info.isAbsolute()) { 2508 if (info.exists()) { 2509 result << QDir::cleanPath(el); 2510 goto next; 2511 } 2512 } else { 2513 foreach (const QString &dir, searchDirs) { 2514 QFileInfo info(dir, el); 2515 if (info.isFile()) { 2516 result << QDir::cleanPath(info.filePath()); 2517 goto next; 2518 } 2519 } 2520 if (baseDirectory.isEmpty()) 2521 goto next; 2522 info = QFileInfo(baseDirectory, el); 2523 } 2524 { 2525 QFileInfo baseInfo(info.absolutePath()); 2526 if (baseInfo.exists()) { 2527 QString wildcard = info.fileName(); 2528 if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) { 2529 QDir theDir(QDir::cleanPath(baseInfo.filePath())); 2530 foreach (const QString &fn, theDir.entryList(QStringList(wildcard))) 2531 if (fn != QLatin1String(".") && fn != QLatin1String("..")) 2532 result << theDir.absoluteFilePath(fn); 2533 } 2534 } 2535 } 2536 next: ; 2537 } 2538 return result; 1652 2539 } 1653 2540 … … 1656 2543 QStringList templ = values(QLatin1String("TEMPLATE")); 1657 2544 if (templ.count() >= 1) { 1658 QString t = templ.last().toLower();1659 if ( t == QLatin1String("app"))2545 const QString &t = templ.last(); 2546 if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive)) 1660 2547 return TT_Application; 1661 if ( t == QLatin1String("lib"))2548 if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive)) 1662 2549 return TT_Library; 1663 if (t == QLatin1String("subdirs")) 2550 if (!t.compare(QLatin1String("script"), Qt::CaseInsensitive)) 2551 return TT_Script; 2552 if (!t.compare(QLatin1String("subdirs"), Qt::CaseInsensitive)) 1664 2553 return TT_Subdirs; 1665 2554 } … … 1705 2594 void ProFileEvaluator::logMessage(const QString &message) 1706 2595 { 1707 if (d->m_verbose )2596 if (d->m_verbose && !d->m_skipLevel) 1708 2597 qWarning("%s", qPrintable(message)); 1709 2598 } … … 1711 2600 void ProFileEvaluator::fileMessage(const QString &message) 1712 2601 { 1713 qWarning("%s", qPrintable(message)); 2602 if (!d->m_skipLevel) 2603 qWarning("%s", qPrintable(message)); 1714 2604 } 1715 2605 1716 2606 void ProFileEvaluator::errorMessage(const QString &message) 1717 2607 { 1718 qWarning("%s", qPrintable(message)); 2608 if (!d->m_skipLevel) 2609 qWarning("%s", qPrintable(message)); 1719 2610 } 1720 2611 … … 1724 2615 } 1725 2616 1726 void evaluateProFile(const ProFileEvaluator &visitor, QHash<QByteArray, QStringList> *varMap) 1727 { 1728 QStringList sourceFiles; 1729 QString codecForTr; 1730 QString codecForSource; 1731 QStringList tsFileNames; 1732 1733 // app/lib template 1734 sourceFiles += visitor.values(QLatin1String("SOURCES")); 1735 sourceFiles += visitor.values(QLatin1String("HEADERS")); 1736 tsFileNames = visitor.values(QLatin1String("TRANSLATIONS")); 1737 1738 QStringList trcodec = visitor.values(QLatin1String("CODEC")) 1739 + visitor.values(QLatin1String("DEFAULTCODEC")) 1740 + visitor.values(QLatin1String("CODECFORTR")); 1741 if (!trcodec.isEmpty()) 1742 codecForTr = trcodec.last(); 1743 1744 QStringList srccodec = visitor.values(QLatin1String("CODECFORSRC")); 1745 if (!srccodec.isEmpty()) 1746 codecForSource = srccodec.last(); 1747 1748 QStringList forms = visitor.values(QLatin1String("INTERFACES")) 1749 + visitor.values(QLatin1String("FORMS")) 1750 + visitor.values(QLatin1String("FORMS3")); 1751 sourceFiles << forms; 1752 1753 sourceFiles.sort(); 1754 sourceFiles.removeDuplicates(); 1755 tsFileNames.sort(); 1756 tsFileNames.removeDuplicates(); 1757 1758 varMap->insert("SOURCES", sourceFiles); 1759 varMap->insert("CODECFORTR", QStringList() << codecForTr); 1760 varMap->insert("CODECFORSRC", QStringList() << codecForSource); 1761 varMap->insert("TRANSLATIONS", tsFileNames); 1762 } 1763 1764 bool evaluateProFile(const QString &fileName, bool verbose, QHash<QByteArray, QStringList> *varMap) 1765 { 1766 QFileInfo fi(fileName); 1767 if (!fi.exists()) 1768 return false; 1769 1770 ProFile pro(fi.absoluteFilePath()); 1771 1772 ProFileEvaluator visitor; 1773 visitor.setVerbose(verbose); 1774 1775 if (!visitor.queryProFile(&pro)) 1776 return false; 1777 1778 if (!visitor.accept(&pro)) 1779 return false; 1780 1781 evaluateProFile(visitor, varMap); 1782 1783 return true; 2617 void ProFileEvaluator::setCumulative(bool on) 2618 { 2619 d->m_cumulative = on; 2620 } 2621 2622 void ProFileEvaluator::setOutputDir(const QString &dir) 2623 { 2624 d->m_outputDir = dir; 1784 2625 } 1785 2626 -
trunk/tools/linguist/shared/profileevaluator.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 51 51 #include <QtCore/QStack> 52 52 53 #if (!defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)) && !defined(__SUNPRO_CC) 54 # define HAVE_TEMPLATE_CLASS_FRIENDS 55 #endif 56 53 57 QT_BEGIN_NAMESPACE 54 55 class ProFile;56 class ProFileEvaluator;57 58 void evaluateProFile(const ProFileEvaluator &visitor, QHash<QByteArray, QStringList> *varMap);59 bool evaluateProFile(const QString &fileName, bool verbose, QHash<QByteArray, QStringList> *varMap);60 58 61 59 class ProFileEvaluator 62 60 { 61 #ifdef HAVE_TEMPLATE_CLASS_FRIENDS 62 private: 63 #else 64 public: 65 #endif 66 class Private; 67 63 68 public: 64 69 enum TemplateType { … … 66 71 TT_Application, 67 72 TT_Library, 73 TT_Script, 68 74 TT_Subdirs 69 75 }; … … 74 80 ProFileEvaluator::TemplateType templateType(); 75 81 virtual bool contains(const QString &variableName) const; 76 void setVerbose(bool on); 82 void setVerbose(bool on); // Default is false 83 void setCumulative(bool on); // Default is true! 84 void setOutputDir(const QString &dir); // Default is empty 77 85 78 86 bool queryProFile(ProFile *pro); … … 83 91 QStringList values(const QString &variableName) const; 84 92 QStringList values(const QString &variableName, const ProFile *pro) const; 93 QStringList absolutePathValues(const QString &variable, const QString &baseDirectory) const; 94 QStringList absoluteFileValues( 95 const QString &variable, const QString &baseDirectory, const QStringList &searchDirs, 96 const ProFile *pro) const; 85 97 QString propertyValue(const QString &val) const; 86 98 … … 93 105 94 106 private: 95 class Private;96 107 Private *d; 108 109 #ifdef HAVE_TEMPLATE_CLASS_FRIENDS 110 template<typename T> friend class QTypeInfo; 111 #endif 97 112 }; 98 113 -
trunk/tools/linguist/shared/proitems.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 59 59 60 60 // --------------- ProBlock ---------------- 61 61 62 ProBlock::ProBlock(ProBlock *parent) 62 63 { 63 64 m_blockKind = 0; 64 65 m_parent = parent; 66 m_refCount = 1; 65 67 } 66 68 67 69 ProBlock::~ProBlock() 68 70 { 69 qDeleteAll(m_proitems); 71 foreach (ProItem *itm, m_proitems) 72 if (itm->kind() == BlockKind) 73 static_cast<ProBlock *>(itm)->deref(); 74 else 75 delete itm; 70 76 } 71 77 … … 110 116 } 111 117 112 bool ProBlock::Accept(AbstractProItemVisitor *visitor) 113 { 114 visitor->visitBeginProBlock(this); 115 foreach (ProItem *item, m_proitems) { 116 if (!item->Accept(visitor)) 117 return false; 118 ProItem::ProItemReturn ProBlock::Accept(AbstractProItemVisitor *visitor) 119 { 120 if (visitor->visitBeginProBlock(this) == ReturnSkip) 121 return ReturnTrue; 122 ProItemReturn rt = ReturnTrue; 123 for (int i = 0; i < m_proitems.count(); ++i) { 124 rt = m_proitems.at(i)->Accept(visitor); 125 if (rt != ReturnTrue && rt != ReturnFalse) { 126 if (rt == ReturnLoop) { 127 rt = ReturnTrue; 128 while (visitor->visitProLoopIteration()) 129 for (int j = i; ++j < m_proitems.count(); ) { 130 rt = m_proitems.at(j)->Accept(visitor); 131 if (rt != ReturnTrue && rt != ReturnFalse) { 132 if (rt == ReturnNext) { 133 rt = ReturnTrue; 134 break; 135 } 136 if (rt == ReturnBreak) 137 rt = ReturnTrue; 138 goto do_break; 139 } 140 } 141 do_break: 142 visitor->visitProLoopCleanup(); 143 } 144 break; 145 } 118 146 } 119 return visitor->visitEndProBlock(this); 147 visitor->visitEndProBlock(this); 148 return rt; 120 149 } 121 150 … … 149 178 } 150 179 151 boolProVariable::Accept(AbstractProItemVisitor *visitor)180 ProItem::ProItemReturn ProVariable::Accept(AbstractProItemVisitor *visitor) 152 181 { 153 182 visitor->visitBeginProVariable(this); 154 foreach (ProItem *item, m_proitems) { 155 if (!item->Accept(visitor)) 156 return false; 157 } 158 return visitor->visitEndProVariable(this); 183 foreach (ProItem *item, m_proitems) 184 item->Accept(visitor); // cannot fail 185 visitor->visitEndProVariable(this); 186 return ReturnTrue; 159 187 } 160 188 … … 191 219 } 192 220 193 bool ProValue::Accept(AbstractProItemVisitor *visitor) 194 { 195 return visitor->visitProValue(this); 221 ProItem::ProItemReturn ProValue::Accept(AbstractProItemVisitor *visitor) 222 { 223 visitor->visitProValue(this); 224 return ReturnTrue; 196 225 } 197 226 … … 217 246 } 218 247 219 boolProFunction::Accept(AbstractProItemVisitor *visitor)248 ProItem::ProItemReturn ProFunction::Accept(AbstractProItemVisitor *visitor) 220 249 { 221 250 return visitor->visitProFunction(this); … … 243 272 } 244 273 245 bool ProCondition::Accept(AbstractProItemVisitor *visitor) 246 { 247 return visitor->visitProCondition(this); 274 ProItem::ProItemReturn ProCondition::Accept(AbstractProItemVisitor *visitor) 275 { 276 visitor->visitProCondition(this); 277 return ReturnTrue; 248 278 } 249 279 … … 269 299 } 270 300 271 bool ProOperator::Accept(AbstractProItemVisitor *visitor) 272 { 273 return visitor->visitProOperator(this); 301 ProItem::ProItemReturn ProOperator::Accept(AbstractProItemVisitor *visitor) 302 { 303 visitor->visitProOperator(this); 304 return ReturnTrue; 274 305 } 275 306 … … 316 347 } 317 348 318 bool ProFile::Accept(AbstractProItemVisitor *visitor) 319 { 320 visitor->visitBeginProFile(this); 321 foreach (ProItem *item, m_proitems) { 322 if (!item->Accept(visitor)) 323 return false; 324 } 349 ProItem::ProItemReturn ProFile::Accept(AbstractProItemVisitor *visitor) 350 { 351 ProItemReturn rt; 352 if ((rt = visitor->visitBeginProFile(this)) != ReturnTrue) 353 return rt; 354 ProBlock::Accept(visitor); // cannot fail 325 355 return visitor->visitEndProFile(this); 326 356 } -
trunk/tools/linguist/shared/proitems.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 43 43 #define PROITEMS_H 44 44 45 #include <QtCore/QObject>46 45 #include <QtCore/QString> 47 46 #include <QtCore/QList> … … 62 61 }; 63 62 63 enum ProItemReturn { 64 ReturnFalse, 65 ReturnTrue, 66 ReturnBreak, 67 ReturnNext, 68 ReturnLoop, 69 ReturnSkip, 70 ReturnReturn 71 }; 72 64 73 ProItem() : m_lineNumber(0) {} 65 74 virtual ~ProItem() {} … … 70 79 QString comment() const; 71 80 72 virtual boolAccept(AbstractProItemVisitor *visitor) = 0;81 virtual ProItemReturn Accept(AbstractProItemVisitor *visitor) = 0; 73 82 int lineNumber() const { return m_lineNumber; } 74 83 void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; } … … 88 97 VariableKind = 0x04, 89 98 ProFileKind = 0x08, 90 SingleLine = 0x10 99 FunctionBodyKind = 0x10, 100 SingleLine = 0x80 91 101 }; 92 102 … … 104 114 ProBlock *parent() const; 105 115 106 ProItem::ProItemKind kind() const; 107 108 virtual bool Accept(AbstractProItemVisitor *visitor); 116 void ref() { ++m_refCount; } 117 void deref() { if (!--m_refCount) delete this; } 118 119 ProItem::ProItemKind kind() const; 120 121 virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); 109 122 protected: 110 123 QList<ProItem *> m_proitems; … … 112 125 ProBlock *m_parent; 113 126 int m_blockKind; 127 int m_refCount; 114 128 }; 115 129 … … 133 147 QString variable() const; 134 148 135 virtual boolAccept(AbstractProItemVisitor *visitor);149 virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); 136 150 private: 137 151 VariableOperator m_variableKind; … … 152 166 ProItem::ProItemKind kind() const; 153 167 154 virtual boolAccept(AbstractProItemVisitor *visitor);168 virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); 155 169 private: 156 170 QString m_value; … … 168 182 ProItem::ProItemKind kind() const; 169 183 170 virtual boolAccept(AbstractProItemVisitor *visitor);184 virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); 171 185 private: 172 186 QString m_text; … … 183 197 ProItem::ProItemKind kind() const; 184 198 185 virtual boolAccept(AbstractProItemVisitor *visitor);199 virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); 186 200 private: 187 201 QString m_text; … … 203 217 ProItem::ProItemKind kind() const; 204 218 205 virtual boolAccept(AbstractProItemVisitor *visitor);219 virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); 206 220 private: 207 221 OperatorKind m_operatorKind; 208 222 }; 209 223 210 class ProFile : public QObject, public ProBlock 211 { 212 Q_OBJECT 213 224 class ProFile : public ProBlock 225 { 214 226 public: 215 227 explicit ProFile(const QString &fileName); … … 223 235 bool isModified() const; 224 236 225 virtual boolAccept(AbstractProItemVisitor *visitor);237 virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); 226 238 227 239 private: -
trunk/tools/linguist/shared/proparser.pri
r2 r561 3 3 4 4 HEADERS += \ 5 $$PWD/proreader.h \ 5 6 $$PWD/abstractproitemvisitor.h \ 6 7 $$PWD/proitems.h \ … … 9 10 10 11 SOURCES += \ 12 $$PWD/proreader.cpp \ 11 13 $$PWD/proitems.cpp \ 12 14 $$PWD/profileevaluator.cpp -
trunk/tools/linguist/shared/proparserutils.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 44 44 45 45 #include <QtCore/QDir> 46 #ifndef QT_BOOTSTRAPPED 46 47 #include <QtCore/QLibraryInfo> 48 #endif 47 49 48 50 QT_BEGIN_NAMESPACE 51 52 #ifdef QT_BOOTSTRAPPED 53 // this is a stripped down version of the one found in QtCore 54 class QLibraryInfo 55 { 56 public: 57 enum LibraryLocation 58 { 59 PrefixPath, 60 DocumentationPath, 61 HeadersPath, 62 LibrariesPath, 63 BinariesPath, 64 PluginsPath, 65 DataPath, 66 TranslationsPath, 67 SettingsPath, 68 DemosPath, 69 ExamplesPath 70 }; 71 static QString location(LibraryLocation); 72 }; 73 #endif 49 74 50 75 // Pre- and postcondition macros … … 94 119 Option::field_sep = QLatin1Char(' '); 95 120 } 121 122 enum StringFixFlags { 123 FixNone = 0x00, 124 FixEnvVars = 0x01, 125 FixPathCanonicalize = 0x02, 126 FixPathToLocalSeparators = 0x04, 127 FixPathToTargetSeparators = 0x08 128 }; 129 static QString fixString(QString string, uchar flags); 130 131 inline static QString fixPathToLocalOS(const QString &in, bool fix_env = true, bool canonical = true) 132 { 133 uchar flags = FixPathToLocalSeparators; 134 if (fix_env) 135 flags |= FixEnvVars; 136 if (canonical) 137 flags |= FixPathCanonicalize; 138 return fixString(in, flags); 139 } 96 140 }; 97 141 #if defined(Q_OS_WIN32) … … 111 155 112 156 static void insertUnique(QHash<QString, QStringList> *map, 113 const QString &key, const QStringList &value , bool unique = true)157 const QString &key, const QStringList &value) 114 158 { 115 159 QStringList &sl = (*map)[key]; 116 if (!unique) { 117 sl += value; 118 } else { 119 for (int i = 0; i < value.count(); ++i) { 120 if (!sl.contains(value.at(i))) 121 sl.append(value.at(i)); 122 } 123 } 160 foreach (const QString &str, value) 161 if (!sl.contains(str)) 162 sl.append(str); 163 } 164 165 static void removeEach(QHash<QString, QStringList> *map, 166 const QString &key, const QStringList &value) 167 { 168 QStringList &sl = (*map)[key]; 169 foreach (const QString &str, value) 170 sl.removeAll(str); 124 171 } 125 172 … … 149 196 */ 150 197 151 inline QStringList splitPathList(const QString paths) 198 inline QString fixEnvVariables(const QString &x) 199 { 200 return Option::fixString(x, Option::FixEnvVars); 201 } 202 203 inline QStringList splitPathList(const QString &paths) 152 204 { 153 205 return paths.split(Option::dirlist_sep); … … 256 308 { 257 309 QStringList ret; 258 const QString concat = QDir::separator() + Q String(QLatin1String("mkspecs"));310 const QString concat = QDir::separator() + QLatin1String("mkspecs"); 259 311 QByteArray qmakepath = qgetenv("QMAKEPATH"); 260 312 if (!qmakepath.isEmpty()) { -
trunk/tools/linguist/shared/qm.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 42 42 #include "translator.h" 43 43 44 #ifndef QT_BOOTSTRAPPED 44 45 #include <QtCore/QCoreApplication> 46 #endif 45 47 #include <QtCore/QDebug> 46 48 #include <QtCore/QDir> … … 173 175 bool save(QIODevice *iod); 174 176 175 void insert(const TranslatorMessage &msg, bool forceComment); 177 void insert(const TranslatorMessage &msg, const QStringList &tlns, bool forceComment); 178 void insertIdBased(const TranslatorMessage &message, const QStringList &tlns); 176 179 177 180 void squeeze(TranslatorSaveMode mode); … … 186 189 QByteArray originalBytes(const QString &str, bool isUtf8) const; 187 190 188 void insertInternal(const TranslatorMessage &message, bool forceComment, bool isUtf8); 191 void insertInternal(const TranslatorMessage &message, const QStringList &tlns, 192 bool forceComment, bool isUtf8); 189 193 190 194 static Prefix commonPrefix(const ByteTranslatorMessage &m1, const ByteTranslatorMessage &m2); … … 239 243 TranslatorSaveMode mode, Prefix prefix) const 240 244 { 241 for (int i = 0; i < msg.translations().count(); ++i) { 242 QString str = msg.translations().at(i); 243 str.replace(QChar(Translator::DefaultVariantSeparator), 244 QChar(Translator::InternalVariantSeparator)); 245 stream << quint8(Tag_Translation) << str; 246 } 245 for (int i = 0; i < msg.translations().count(); ++i) 246 stream << quint8(Tag_Translation) << msg.translations().at(i); 247 247 248 248 if (mode == SaveEverything) 249 249 prefix = HashContextSourceTextComment; 250 250 251 // lrelease produces "wrong" .qmfiles for QByteArrays that are .isNull().251 // lrelease produces "wrong" QM files for QByteArrays that are .isNull(). 252 252 switch (prefix) { 253 253 default: … … 417 417 } 418 418 419 void Releaser::insertInternal(const TranslatorMessage &message, bool forceComment, bool isUtf8) 419 void Releaser::insertInternal(const TranslatorMessage &message, const QStringList &tlns, 420 bool forceComment, bool isUtf8) 420 421 { 421 422 ByteTranslatorMessage bmsg(originalBytes(message.context(), isUtf8), 422 423 originalBytes(message.sourceText(), isUtf8), 423 424 originalBytes(message.comment(), isUtf8), 424 message.translations());425 tlns); 425 426 if (!forceComment) { 426 427 ByteTranslatorMessage bmsg2( … … 434 435 } 435 436 436 void Releaser::insert(const TranslatorMessage &message, bool forceComment)437 { 438 insertInternal(message, forceComment, message.isUtf8());437 void Releaser::insert(const TranslatorMessage &message, const QStringList &tlns, bool forceComment) 438 { 439 insertInternal(message, tlns, forceComment, message.isUtf8()); 439 440 if (message.isUtf8() && message.isNonUtf8()) 440 insertInternal(message, forceComment, false); 441 insertInternal(message, tlns, forceComment, false); 442 } 443 444 void Releaser::insertIdBased(const TranslatorMessage &message, const QStringList &tlns) 445 { 446 ByteTranslatorMessage bmsg("", originalBytes(message.id(), false), "", tlns); 447 m_messages.insert(bmsg, 0); 441 448 } 442 449 … … 546 553 //qDebug() << "NUMITEMS: " << numItems; 547 554 548 // FIXME: that's just a guess, the original locale data is lost...549 QTextCodec *codec = QTextCodec::codecForLocale();555 QTextCodec *codec = QTextCodec::codecForName( 556 cd.m_codecForSource.isEmpty() ? QByteArray("Latin1") : cd.m_codecForSource); 550 557 QTextCodec *utf8Codec = 0; 551 558 if (codec->name() != "UTF-8") 552 559 utf8Codec = QTextCodec::codecForName("UTF-8"); 560 561 QString strProN = QLatin1String("%n"); 562 QLocale::Language l; 563 QLocale::Country c; 564 Translator::languageAndCountry(translator.languageCode(), &l, &c); 565 QStringList numerusForms; 566 bool guessPlurals = true; 567 if (getNumerusInfo(l, c, 0, &numerusForms)) 568 guessPlurals = (numerusForms.count() == 1); 553 569 554 570 QString context, contextUtf8; … … 585 601 ((str.at(i).unicode() << 8) & 0xff00)); 586 602 } 587 str.replace(QChar(Translator::InternalVariantSeparator),588 QChar(Translator::DefaultVariantSeparator));589 603 translations << str; 590 604 m += len; … … 636 650 TranslatorMessage msg; 637 651 msg.setType(TranslatorMessage::Finished); 652 if (translations.count() > 1) { 653 // If guessPlurals is not false here, plural form discard messages 654 // will be spewn out later. 655 msg.setPlural(true); 656 } else if (guessPlurals) { 657 // This might cause false positives, so it is a fallback only. 658 if (sourcetext.contains(strProN)) 659 msg.setPlural(true); 660 } 638 661 msg.setTranslations(translations); 639 662 translations.clear(); … … 650 673 if (!(contextIsSystem && sourcetextIsSystem && commentIsSystem)) { 651 674 cd.appendError(QLatin1String( 652 "Cannot read file with current system charactercodec"));675 "Cannot read file with specified input codec")); 653 676 return false; 654 677 } … … 664 687 665 688 689 690 static bool containsStripped(const Translator &translator, const TranslatorMessage &msg) 691 { 692 foreach (const TranslatorMessage &tmsg, translator.messages()) 693 if (tmsg.sourceText() == msg.sourceText() 694 && tmsg.context() == msg.context() 695 && tmsg.comment().isEmpty()) 696 return true; 697 return false; 698 } 666 699 667 700 static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData &cd) … … 679 712 int unfinished = 0; 680 713 int untranslated = 0; 714 int missingIds = 0; 715 int droppedData = 0; 681 716 682 717 for (int i = 0; i != translator.messageCount(); ++i) { … … 684 719 TranslatorMessage::Type typ = msg.type(); 685 720 if (typ != TranslatorMessage::Obsolete) { 721 if (cd.m_idBased && msg.id().isEmpty()) { 722 ++missingIds; 723 continue; 724 } 686 725 if (typ == TranslatorMessage::Unfinished) { 687 if ( msg.translation().isEmpty()) {726 if (!cd.m_idBased && msg.translation().isEmpty()) { 688 727 ++untranslated; 689 728 continue; … … 696 735 ++finished; 697 736 } 698 // Drop the comment in (context, sourceText, comment), 699 // unless the context is empty, 700 // unless (context, sourceText, "") already exists or 701 // unless we already dropped the comment of (context, 702 // sourceText, comment0). 703 bool forceComment = 704 msg.comment().isEmpty() 705 || msg.context().isEmpty() 706 || translator.contains(msg.context(), msg.sourceText(), QString()); 707 releaser.insert(msg, forceComment); 708 } 709 } 737 QStringList tlns = msg.translations(); 738 if (msg.type() == TranslatorMessage::Unfinished 739 && (cd.m_idBased || !cd.m_unTrPrefix.isEmpty())) 740 for (int j = 0; j < tlns.size(); ++j) 741 if (tlns.at(j).isEmpty()) 742 tlns[j] = cd.m_unTrPrefix + msg.sourceText(); 743 if (cd.m_idBased) { 744 if (!msg.context().isEmpty() || !msg.comment().isEmpty()) 745 ++droppedData; 746 releaser.insertIdBased(msg, tlns); 747 } else { 748 // Drop the comment in (context, sourceText, comment), 749 // unless the context is empty, 750 // unless (context, sourceText, "") already exists or 751 // unless we already dropped the comment of (context, 752 // sourceText, comment0). 753 bool forceComment = 754 msg.comment().isEmpty() 755 || msg.context().isEmpty() 756 || containsStripped(translator, msg); 757 releaser.insert(msg, tlns, forceComment); 758 } 759 } 760 } 761 762 if (missingIds) 763 cd.appendError(QCoreApplication::translate("LRelease", 764 "Dropped %n message(s) which had no ID.", 0, 765 QCoreApplication::CodecForTr, missingIds)); 766 if (droppedData) 767 cd.appendError(QCoreApplication::translate("LRelease", 768 "Excess context/disambiguation dropped from %n message(s).", 0, 769 QCoreApplication::CodecForTr, droppedData)); 710 770 711 771 releaser.squeeze(cd.m_saveMode); -
trunk/tools/linguist/shared/qph.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 55 55 { 56 56 public: 57 QPHReader(QIODevice &dev , ConversionData &cd)58 : QXmlStreamReader(&dev) , m_cd(cd)57 QPHReader(QIODevice &dev) 58 : QXmlStreamReader(&dev) 59 59 {} 60 60 … … 63 63 64 64 private: 65 bool elementStarts(const QString &str) const66 {67 return isStartElement() && name() == str;68 }69 70 65 bool isWhiteSpace() const 71 66 { 72 67 return isCharacters() && text().toString().trimmed().isEmpty(); 73 68 } 74 75 // needed to expand <byte ... />76 QString readContents();77 // needed to join <lengthvariant>s78 QString readTransContents();79 80 void handleError();81 82 ConversionData &m_cd;83 69 84 70 enum DataField { NoField, SourceField, TargetField, DefinitionField }; … … 96 82 readNext(); 97 83 if (isStartElement()) { 98 if (name() == QLatin1String("source")) 84 if (name() == QLatin1String("source")) { 99 85 m_currentField = SourceField; 100 else if (name() == QLatin1String("target"))86 } else if (name() == QLatin1String("target")) { 101 87 m_currentField = TargetField; 102 else if (name() == QLatin1String("definition"))88 } else if (name() == QLatin1String("definition")) { 103 89 m_currentField = DefinitionField; 104 else90 } else { 105 91 m_currentField = NoField; 92 if (name() == QLatin1String("QPH")) { 93 QXmlStreamAttributes atts = attributes(); 94 translator.setLanguageCode(atts.value(QLatin1String("language")).toString()); 95 translator.setSourceLanguageCode(atts.value(QLatin1String("sourcelanguage")).toString()); 96 } 97 } 106 98 } else if (isWhiteSpace()) { 107 99 // ignore these … … 114 106 m_currentDefinition += text(); 115 107 } else if (isEndElement() && name() == QLatin1String("phrase")) { 108 m_currentTarget.replace(QChar(Translator::TextVariantSeparator), 109 QChar(Translator::BinaryVariantSeparator)); 116 110 TranslatorMessage msg; 117 111 msg.setSourceText(m_currentSource); 118 112 msg.setTranslation(m_currentTarget); 119 msg.set TranslatorComment(m_currentDefinition);113 msg.setComment(m_currentDefinition); 120 114 translator.append(msg); 121 115 m_currentSource.clear(); … … 127 121 } 128 122 129 static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData & cd)123 static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &) 130 124 { 131 125 translator.setLocationsType(Translator::NoLocations); 132 QPHReader reader(dev , cd);126 QPHReader reader(dev); 133 127 return reader.read(translator); 134 128 } … … 170 164 QTextStream t(&dev); 171 165 t.setCodec(QTextCodec::codecForName("UTF-8")); 172 t << "<!DOCTYPE QPH>\n<QPH>\n"; 166 t << "<!DOCTYPE QPH>\n<QPH"; 167 QString languageCode = translator.languageCode(); 168 if (!languageCode.isEmpty() && languageCode != QLatin1String("C")) 169 t << " language=\"" << languageCode << "\""; 170 languageCode = translator.sourceLanguageCode(); 171 if (!languageCode.isEmpty() && languageCode != QLatin1String("C")) 172 t << " sourcelanguage=\"" << languageCode << "\""; 173 t << ">\n"; 173 174 foreach (const TranslatorMessage &msg, translator.messages()) { 174 175 t << "<phrase>\n"; 175 176 t << " <source>" << protect(msg.sourceText()) << "</source>\n"; 176 t << " <target>" << protect(msg.translations().join(QLatin1String("@"))) 177 QString str = msg.translations().join(QLatin1String("@")); 178 str.replace(QChar(Translator::BinaryVariantSeparator), 179 QChar(Translator::TextVariantSeparator)); 180 t << " <target>" << protect(str) 177 181 << "</target>\n"; 178 if (!msg.context().isEmpty() || !msg.comment().isEmpty()) 179 t << " <definition>" << msg.context() << msg.comment() 180 << "</definition>\n"; 182 if (!msg.comment().isEmpty()) 183 t << " <definition>" << protect(msg.comment()) << "</definition>\n"; 181 184 t << "</phrase>\n"; 182 185 } -
trunk/tools/linguist/shared/simtexth.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/tools/linguist/shared/simtexth.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/tools/linguist/shared/translator.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 46 46 #include <stdio.h> 47 47 48 #include <QtCore/QCoreApplication>49 48 #include <QtCore/QDebug> 50 49 #include <QtCore/QDir> … … 58 57 QT_BEGIN_NAMESPACE 59 58 59 #ifdef QT_BOOTSTRAPPED 60 QString QObject::tr(const char *sourceText, const char *, int n) 61 { 62 QString ret = QString::fromLatin1(sourceText); 63 if (n >= 0) 64 ret.replace(QLatin1String("%n"), QString::number(n)); 65 return ret; 66 } 67 #endif 68 60 69 Translator::Translator() : 61 m_codec Name("ISO-8859-1"),70 m_codec(QTextCodec::codecForName("ISO-8859-1")), 62 71 m_locationsType(AbsoluteLocations) 63 72 { … … 82 91 } 83 92 84 void Translator::replace(const TranslatorMessage &msg)85 {86 int index = m_messages.indexOf(msg);87 if (index == -1)88 m_messages.append(msg);89 else90 m_messages[index] = msg;91 }92 93 93 void Translator::replaceSorted(const TranslatorMessage &msg) 94 94 { 95 int index = m_messages.indexOf(msg);95 int index = find(msg); 96 96 if (index == -1) 97 97 appendSorted(msg); … … 102 102 void Translator::extend(const TranslatorMessage &msg) 103 103 { 104 int index = m_messages.indexOf(msg);104 int index = find(msg); 105 105 if (index == -1) { 106 106 m_messages.append(msg); … … 147 147 int curIdx = 0; 148 148 foreach (const TranslatorMessage &mit, m_messages) { 149 bool sameFile = mit.fileName() == msg.fileName() ;149 bool sameFile = mit.fileName() == msg.fileName() && mit.context() == msg.context(); 150 150 int curLine; 151 151 if (sameFile && (curLine = mit.lineNumber()) >= prevLine) { … … 313 313 } 314 314 315 bool Translator::contains(const QString &context, 316 const QString &sourceText, const QString &comment) const 317 { 318 return m_messages.contains(TranslatorMessage(context, sourceText, comment, 319 QString(), QString(), 0)); 320 } 321 322 TranslatorMessage Translator::find(const QString &context, 323 const QString &sourceText, const QString &comment) const 324 { 325 TranslatorMessage needle(context, sourceText, comment, QString(), QString(), 0); 326 int index = m_messages.indexOf(needle); 327 return index == -1 ? TranslatorMessage() : m_messages.at(index); 315 int Translator::find(const TranslatorMessage &msg) const 316 { 317 for (int i = 0; i < m_messages.count(); ++i) { 318 const TranslatorMessage &tmsg = m_messages.at(i); 319 if (msg.id().isEmpty() || tmsg.id().isEmpty()) { 320 if (msg.context() == tmsg.context() 321 && msg.sourceText() == tmsg.sourceText() 322 && msg.comment() == tmsg.comment()) 323 return i; 324 } else { 325 if (msg.id() == tmsg.id()) 326 return i; 327 } 328 } 329 return -1; 328 330 } 329 331 … … 346 348 { 347 349 foreach (const TranslatorMessage &msg, m_messages) 348 if (msg.context() == context && msg.sourceText().isEmpty() )350 if (msg.context() == context && msg.sourceText().isEmpty() && msg.id().isEmpty()) 349 351 return true; 350 352 return false; … … 354 356 { 355 357 foreach (const TranslatorMessage &msg, m_messages) 356 if (msg.context() == context && msg.sourceText().isEmpty() )358 if (msg.context() == context && msg.sourceText().isEmpty() && msg.id().isEmpty()) 357 359 return msg; 358 360 return TranslatorMessage(); … … 417 419 } 418 420 419 QSet<TranslatorMessagePtr> Translator::resolveDuplicates() 420 { 421 QSet<TranslatorMessagePtr> dups; 422 QHash<TranslatorMessagePtr, int> refs; 421 void Translator::dropUiLines() 422 { 423 QString uiXt = QLatin1String(".ui"); 424 QString juiXt = QLatin1String(".jui"); 425 for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ++it) { 426 QHash<QString, int> have; 427 QList<TranslatorMessage::Reference> refs; 428 foreach (const TranslatorMessage::Reference &itref, it->allReferences()) { 429 const QString &fn = itref.fileName(); 430 if (fn.endsWith(uiXt) || fn.endsWith(juiXt)) { 431 if (++have[fn] == 1) 432 refs.append(TranslatorMessage::Reference(fn, -1)); 433 } else { 434 refs.append(itref); 435 } 436 } 437 it->setReferences(refs); 438 } 439 } 440 441 struct TranslatorMessageIdPtr { 442 explicit TranslatorMessageIdPtr(const TranslatorMessage &tm) 443 { 444 ptr = &tm; 445 } 446 447 inline const TranslatorMessage *operator->() const 448 { 449 return ptr; 450 } 451 452 const TranslatorMessage *ptr; 453 }; 454 455 Q_DECLARE_TYPEINFO(TranslatorMessageIdPtr, Q_MOVABLE_TYPE); 456 457 inline int qHash(TranslatorMessageIdPtr tmp) 458 { 459 return qHash(tmp->id()); 460 } 461 462 inline bool operator==(TranslatorMessageIdPtr tmp1, TranslatorMessageIdPtr tmp2) 463 { 464 return tmp1->id() == tmp2->id(); 465 } 466 467 struct TranslatorMessageContentPtr { 468 explicit TranslatorMessageContentPtr(const TranslatorMessage &tm) 469 { 470 ptr = &tm; 471 } 472 473 inline const TranslatorMessage *operator->() const 474 { 475 return ptr; 476 } 477 478 const TranslatorMessage *ptr; 479 }; 480 481 Q_DECLARE_TYPEINFO(TranslatorMessageContentPtr, Q_MOVABLE_TYPE); 482 483 inline int qHash(TranslatorMessageContentPtr tmp) 484 { 485 int hash = qHash(tmp->context()) ^ qHash(tmp->sourceText()); 486 if (!tmp->sourceText().isEmpty()) 487 // Special treatment for context comments (empty source). 488 hash ^= qHash(tmp->comment()); 489 return hash; 490 } 491 492 inline bool operator==(TranslatorMessageContentPtr tmp1, TranslatorMessageContentPtr tmp2) 493 { 494 if (tmp1->context() != tmp2->context() || tmp1->sourceText() != tmp2->sourceText()) 495 return false; 496 // Special treatment for context comments (empty source). 497 if (tmp1->sourceText().isEmpty()) 498 return true; 499 return tmp1->comment() == tmp2->comment(); 500 } 501 502 Translator::Duplicates Translator::resolveDuplicates() 503 { 504 Duplicates dups; 505 QHash<TranslatorMessageIdPtr, int> idRefs; 506 QHash<TranslatorMessageContentPtr, int> contentRefs; 423 507 for (int i = 0; i < m_messages.count();) { 424 508 const TranslatorMessage &msg = m_messages.at(i); 425 QHash<TranslatorMessagePtr, int>::ConstIterator it = refs.constFind(msg); 426 if (it != refs.constEnd()) { 427 TranslatorMessage &omsg = m_messages[*it]; 428 if (omsg.isUtf8() != msg.isUtf8() && !omsg.isNonUtf8()) { 429 // Dual-encoded message 430 omsg.setUtf8(true); 431 omsg.setNonUtf8(true); 432 } else { 433 // Duplicate 434 dups.insert(omsg); 509 TranslatorMessage *omsg; 510 int oi; 511 QSet<int> *pDup; 512 if (!msg.id().isEmpty()) { 513 QHash<TranslatorMessageIdPtr, int>::ConstIterator it = 514 idRefs.constFind(TranslatorMessageIdPtr(msg)); 515 if (it != idRefs.constEnd()) { 516 oi = *it; 517 omsg = &m_messages[oi]; 518 pDup = &dups.byId; 519 goto gotDupe; 435 520 } 436 if (!omsg.isTranslated() && msg.isTranslated()) 437 omsg.setTranslations(msg.translations()); 438 m_messages.removeAt(i); 521 } 522 { 523 QHash<TranslatorMessageContentPtr, int>::ConstIterator it = 524 contentRefs.constFind(TranslatorMessageContentPtr(msg)); 525 if (it != contentRefs.constEnd()) { 526 oi = *it; 527 omsg = &m_messages[oi]; 528 if (msg.id().isEmpty() || omsg->id().isEmpty()) { 529 if (!msg.id().isEmpty() && omsg->id().isEmpty()) { 530 omsg->setId(msg.id()); 531 idRefs[TranslatorMessageIdPtr(*omsg)] = oi; 532 } 533 pDup = &dups.byContents; 534 goto gotDupe; 535 } 536 // This is really a content dupe, but with two distinct IDs. 537 } 538 } 539 if (!msg.id().isEmpty()) 540 idRefs[TranslatorMessageIdPtr(msg)] = i; 541 contentRefs[TranslatorMessageContentPtr(msg)] = i; 542 ++i; 543 continue; 544 gotDupe: 545 if (omsg->isUtf8() != msg.isUtf8() && !omsg->isNonUtf8()) { 546 // Dual-encoded message 547 omsg->setUtf8(true); 548 omsg->setNonUtf8(true); 439 549 } else { 440 refs[msg] = i; 441 ++i; 442 } 550 // Duplicate 551 pDup->insert(oi); 552 } 553 if (!omsg->isTranslated() && msg.isTranslated()) 554 omsg->setTranslations(msg.translations()); 555 m_messages.removeAt(i); 443 556 } 444 557 return dups; 445 558 } 446 559 447 void Translator::reportDuplicates(const QSet<TranslatorMessagePtr>&dupes,560 void Translator::reportDuplicates(const Duplicates &dupes, 448 561 const QString &fileName, bool verbose) 449 562 { 450 if (!dupes. isEmpty()) {563 if (!dupes.byId.isEmpty() || !dupes.byContents.isEmpty()) { 451 564 if (!verbose) { 452 565 qWarning("Warning: dropping duplicate messages in '%s'\n(try -verbose for more info).", … … 454 567 } else { 455 568 qWarning("Warning: dropping duplicate messages in '%s':", qPrintable(fileName)); 456 foreach (const TranslatorMessagePtr &msg, dupes) { 569 foreach (int i, dupes.byId) 570 qWarning("\n* ID: %s", qPrintable(message(i).id())); 571 foreach (int j, dupes.byContents) { 572 const TranslatorMessage &msg = message(j); 457 573 qWarning("\n* Context: %s\n* Source: %s", 458 qPrintable(msg ->context()),459 qPrintable(msg ->sourceText()));460 if (!msg ->comment().isEmpty())461 qWarning("* Comment: %s", qPrintable(msg ->comment()));574 qPrintable(msg.context()), 575 qPrintable(msg.sourceText())); 576 if (!msg.comment().isEmpty()) 577 qWarning("* Comment: %s", qPrintable(msg.comment())); 462 578 } 463 579 qWarning(); … … 499 615 } 500 616 501 QStringList Translator::normalizedTranslations(const TranslatorMessage &msg, 502 QLocale::Language language, QLocale::Country country) 617 QStringList Translator::normalizedTranslations(const TranslatorMessage &msg, int numPlurals) 503 618 { 504 619 QStringList translations = msg.translations(); 505 int numTranslations = 1; 506 if (msg.isPlural() && language != QLocale::C) { 507 QStringList forms; 508 if (getNumerusInfo(language, country, 0, &forms)) 509 numTranslations = forms.count(); // includes singular 510 } 620 int numTranslations = msg.isPlural() ? numPlurals : 1; 511 621 512 622 // make sure that the stringlist always have the size of the … … 522 632 } 523 633 524 QStringList Translator::normalizedTranslations(const TranslatorMessage &msg, 525 ConversionData &cd, bool *ok) const 526 { 634 void Translator::normalizeTranslations(ConversionData &cd) 635 { 636 bool truncated = false; 527 637 QLocale::Language l; 528 638 QLocale::Country c; 529 639 languageAndCountry(languageCode(), &l, &c); 530 QStringList translns = normalizedTranslations(msg, l, c); 531 if (msg.translations().size() > translns.size() && ok) { 640 int numPlurals = 1; 641 if (l != QLocale::C) { 642 QStringList forms; 643 if (getNumerusInfo(l, c, 0, &forms)) 644 numPlurals = forms.count(); // includes singular 645 } 646 for (int i = 0; i < m_messages.count(); ++i) { 647 const TranslatorMessage &msg = m_messages.at(i); 648 QStringList tlns = msg.translations(); 649 int ccnt = msg.isPlural() ? numPlurals : 1; 650 if (tlns.count() != ccnt) { 651 while (tlns.count() < ccnt) 652 tlns.append(QString()); 653 while (tlns.count() > ccnt) { 654 tlns.removeLast(); 655 truncated = true; 656 } 657 TranslatorMessage msg2(msg); 658 msg2.setTranslations(tlns); 659 m_messages[i] = msg2; 660 } 661 } 662 if (truncated) 532 663 cd.appendError(QLatin1String( 533 664 "Removed plural forms as the target language has less " 534 665 "forms.\nIf this sounds wrong, possibly the target language is " 535 666 "not set or recognized.\n")); 536 *ok = false;537 }538 return translns;539 667 } 540 668 … … 586 714 if (!name.isEmpty()) 587 715 qWarning("No QTextCodec for %s available. Using Latin1\n", name.constData()); 588 m_codec Name = "ISO-8859-1";716 m_codec = QTextCodec::codecForName("ISO-8859-1"); 589 717 } else { 590 m_codecName = codec->name(); 591 } 718 m_codec = codec; 719 } 720 } 721 722 QByteArray Translator::codecName() const 723 { 724 return m_codec->name(); 592 725 } 593 726 -
trunk/tools/linguist/shared/translator.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 48 48 #include <QList> 49 49 #include <QLocale> 50 #include <QMultiHash> 50 51 #include <QString> 52 #include <QSet> 51 53 52 54 53 55 QT_BEGIN_NAMESPACE 56 57 #ifdef QT_BOOTSTRAPPED 58 class QObject { 59 public: 60 static QString tr(const char *sourceText, const char * = 0, int n = -1); 61 }; 62 class QCoreApplication : public QObject { 63 public: 64 enum Encoding { CodecForTr }; 65 static QString translate(const char *, const char *sourceText, const char * = 0, 66 Encoding = CodecForTr, int n = -1) 67 { return tr(sourceText, 0, n); } 68 }; 69 #endif 54 70 55 71 class QIODevice; … … 64 80 m_sortContexts(false), 65 81 m_noUiLines(false), 82 m_idBased(false), 66 83 m_saveMode(SaveEverything) 67 84 {} … … 82 99 public: 83 100 QString m_defaultContext; 84 QByteArray m_codecForSource; // CPP specific 101 QByteArray m_codecForSource; // CPP, PO & QM specific 102 QByteArray m_outputCodec; // CPP & PO specific 103 QString m_unTrPrefix; // QM specific 85 104 QString m_sourceFileName; 86 105 QString m_targetFileName; 87 106 QDir m_sourceDir; 88 QDir m_targetDir; // FIXME: TS spefic 107 QDir m_targetDir; // FIXME: TS specific 108 QSet<QString> m_projectRoots; 109 QMultiHash<QString, QString> m_allCSources; 110 QStringList m_includePath; 89 111 QStringList m_dropTags; // tags to be dropped 90 112 QStringList m_errors; … … 93 115 bool m_sortContexts; 94 116 bool m_noUiLines; 117 bool m_idBased; 95 118 TranslatorSaveMode m_saveMode; 96 119 }; … … 105 128 bool release(QFile *iod, ConversionData &cd) const; 106 129 107 bool contains(const QString &context, const QString &sourceText, 108 const QString &comment) const; 109 TranslatorMessage find(const QString &context, 110 const QString &sourceText, const QString &comment) const; 111 130 int find(const TranslatorMessage &msg) const; 112 131 TranslatorMessage find(const QString &context, 113 132 const QString &comment, const TranslatorMessage::References &refs) const; … … 116 135 TranslatorMessage find(const QString &context) const; 117 136 118 void replace(const TranslatorMessage &msg);119 137 void replaceSorted(const TranslatorMessage &msg); 120 138 void extend(const TranslatorMessage &msg); // Only for single-location messages … … 128 146 void stripIdenticalSourceTranslations(); 129 147 void dropTranslations(); 148 void dropUiLines(); 130 149 void makeFileNamesAbsolute(const QDir &originalPath); 131 QSet<TranslatorMessagePtr> resolveDuplicates(); 132 static void reportDuplicates(const QSet<TranslatorMessagePtr> &dupes, 133 const QString &fileName, bool verbose); 150 151 struct Duplicates { QSet<int> byId, byContents; }; 152 Duplicates resolveDuplicates(); 153 void reportDuplicates(const Duplicates &dupes, const QString &fileName, bool verbose); 134 154 135 155 void setCodecName(const QByteArray &name); 136 QByteArray codecName() const { return m_codecName; } 156 QByteArray codecName() const; 157 QTextCodec *codec() const { return m_codec; } 137 158 138 159 QString languageCode() const { return m_language; } 139 160 QString sourceLanguageCode() const { return m_sourceLanguage; } 140 161 141 enum LocationsType { NoLocations, RelativeLocations, AbsoluteLocations };162 enum LocationsType { DefaultLocations, NoLocations, RelativeLocations, AbsoluteLocations }; 142 163 void setLocationsType(LocationsType lt) { m_locationsType = lt; } 143 164 LocationsType locationsType() const { return m_locationsType; } … … 151 172 QList<TranslatorMessage> messages() const; 152 173 QList<TranslatorMessage> translatedMessages() const; 153 static QStringList normalizedTranslations(const TranslatorMessage &m, 154 QLocale::Language lang, QLocale::Country country);174 static QStringList normalizedTranslations(const TranslatorMessage &m, int numPlurals); 175 void normalizeTranslations(ConversionData &cd); 155 176 QStringList normalizedTranslations(const TranslatorMessage &m, ConversionData &cd, bool *ok) const; 156 177 … … 179 200 LoadFunction loader; 180 201 SaveFunction saver; 181 enum FileType { SourceCode,TranslationSource, TranslationBinary } fileType;202 enum FileType { TranslationSource, TranslationBinary } fileType; 182 203 int priority; // 0 = highest, -1 = invisible 183 204 }; … … 185 206 static QList<FileFormat> ®isteredFileFormats(); 186 207 187 enum VariantSeparators{188 DefaultVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D189 InternalVariantSeparator = 0x9c // unicode "STRING TERMINATOR"208 enum { 209 TextVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D 210 BinaryVariantSeparator = 0x9c // unicode "STRING TERMINATOR" 190 211 }; 191 212 … … 194 215 195 216 TMM m_messages; 196 Q ByteArray m_codecName;217 QTextCodec *m_codec; 197 218 LocationsType m_locationsType; 198 219 -
trunk/tools/linguist/shared/translatormessage.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 144 144 145 145 146 bool TranslatorMessage::operator==(const TranslatorMessage& m) const147 {148 static QString msgIdPlural = QLatin1String("po-msgid_plural");149 150 // Special treatment for context comments (empty source).151 return (m_context == m.m_context)152 && m_sourcetext == m.m_sourcetext153 && m_extra[msgIdPlural] == m.m_extra[msgIdPlural]154 && (m_sourcetext.isEmpty() || m_comment == m.m_comment);155 }156 157 158 bool TranslatorMessage::operator<(const TranslatorMessage& m) const159 {160 if (m_context != m.m_context)161 return m_context < m.m_context;162 if (m_sourcetext != m.m_sourcetext)163 return m_sourcetext < m.m_sourcetext;164 return m_comment < m.m_comment;165 }166 167 int qHash(const TranslatorMessage &msg)168 {169 return170 qHash(msg.context()) ^171 qHash(msg.sourceText()) ^172 qHash(msg.extra(QLatin1String("po-msgid_plural"))) ^173 qHash(msg.comment());174 }175 176 146 bool TranslatorMessage::hasExtra(const QString &key) const 177 147 { -
trunk/tools/linguist/shared/translatormessage.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 110 110 } 111 111 112 bool operator==(const TranslatorMessage& m) const;113 bool operator<(const TranslatorMessage& m) const;114 115 112 QString fileName() const { return m_fileName; } 116 113 void setFileName(const QString &fileName) { m_fileName = fileName; } … … 178 175 Q_DECLARE_TYPEINFO(TranslatorMessage, Q_MOVABLE_TYPE); 179 176 180 int qHash(const TranslatorMessage &msg);181 182 struct TranslatorMessagePtr {183 TranslatorMessagePtr(const TranslatorMessage &tm)184 {185 ptr = &tm;186 }187 188 inline const TranslatorMessage *operator->() const189 {190 return ptr;191 }192 193 const TranslatorMessage *ptr;194 };195 196 Q_DECLARE_TYPEINFO(TranslatorMessagePtr, Q_MOVABLE_TYPE);197 198 inline int qHash(TranslatorMessagePtr tmp)199 {200 return qHash(*tmp.ptr);201 }202 203 inline bool operator==(TranslatorMessagePtr tmp1, TranslatorMessagePtr tmp2)204 {205 return *tmp1.ptr == *tmp2.ptr;206 }207 208 177 QT_END_NAMESPACE 209 178 -
trunk/tools/linguist/shared/ts.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 198 198 } else if (elementStarts(strlengthvariant)) { 199 199 if (!result.isEmpty()) 200 result += QChar(Translator:: DefaultVariantSeparator);200 result += QChar(Translator::BinaryVariantSeparator); 201 201 result += readContents(); 202 202 } else { … … 515 515 { 516 516 int offset; 517 if ((offset = input.indexOf(QChar(Translator:: DefaultVariantSeparator))) >= 0) {517 if ((offset = input.indexOf(QChar(Translator::BinaryVariantSeparator))) >= 0) { 518 518 t << " variants=\"yes\">"; 519 519 int start = 0; … … 525 525 break; 526 526 start = offset + 1; 527 offset = input.indexOf(QChar(Translator:: DefaultVariantSeparator), start);527 offset = input.indexOf(QChar(Translator::BinaryVariantSeparator), start); 528 528 if (offset < 0) 529 529 offset = input.length(); … … 694 694 if (msg.isPlural()) { 695 695 t << ">"; 696 QStringList translns = translator.normalizedTranslations(msg, cd, &result);697 for (int j = 0; j < qMax(1, translns.count()); ++j) {696 const QStringList &translns = msg.translations(); 697 for (int j = 0; j < translns.count(); ++j) { 698 698 t << "\n <numerusform"; 699 699 writeVariants(t, " ", translns[j]); -
trunk/tools/linguist/shared/ts.dtd
r2 r561 35 35 sourcelanguage CDATA #IMPLIED 36 36 language CDATA #IMPLIED> 37 <!-- The encoding to use in the .qmfile by default. Default is ISO-8859-1. -->37 <!-- The encoding to use in the QM file by default. Default is ISO-8859-1. --> 38 38 <!ELEMENT defaultcodec (#PCDATA) > 39 39 <!ELEMENT context (name?, comment?, (context|message)+) > … … 55 55 <!-- 56 56 ! If utf8 is true, the defaultcodec is overridden and the message is encoded 57 ! in UTF-8 in the .qmfile.57 ! in UTF-8 in the QM file. 58 58 --> 59 59 <!ATTLIST message … … 71 71 ! "current" is the filename used for the 1st location of the previous message. 72 72 ! For subsequent locations, it is the filename used for the previous location. 73 ! A single .tsfile has either all absolute or all relative locations.73 ! A single TS file has either all absolute or all relative locations. 74 74 --> 75 75 <!ATTLIST location … … 107 107 ! The translation variants have a priority between 1 ("highest") and 9 ("lowest") 108 108 ! Typically longer translations get a higher priority. 109 ! If omitted, the order of appearance of the variants in the .tsfiles is used.109 ! If omitted, the order of appearance of the variants in the TS files is used. 110 110 --> 111 111 <!ATTLIST lengthvariant -
trunk/tools/linguist/shared/xliff.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the Qt Linguist of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 244 244 } 245 245 246 static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent, 247 const Translator &translator, ConversionData &cd, bool *ok) 246 static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent) 248 247 { 249 248 static int msgid; 250 249 QString msgidstr = !msg.id().isEmpty() ? msg.id() : QString::fromAscii("_msg%1").arg(++msgid); 251 250 252 QStringList translns = translator.normalizedTranslations(msg, cd, ok);251 QStringList translns = msg.translations(); 253 252 QHash<QString, QString>::const_iterator it; 254 253 QString pluralStr; … … 304 303 if (transit != transend) { 305 304 translation = *transit; 305 translation.replace(QChar(Translator::BinaryVariantSeparator), 306 QChar(Translator::TextVariantSeparator)); 306 307 ++transit; 307 308 puttrans = true; … … 348 349 } 349 350 350 static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent, 351 const Translator &translator, ConversionData &cd, bool *ok) 351 static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent) 352 352 { 353 353 if (msg.isPlural()) { … … 363 363 writeComment(ts, msg, drops, indent); 364 364 365 writeTransUnits(ts, msg, drops, indent , translator, cd, ok);365 writeTransUnits(ts, msg, drops, indent); 366 366 --indent; 367 367 writeIndent(ts, indent); 368 368 ts << "</group>\n"; 369 369 } else { 370 writeTransUnits(ts, msg, drops, indent , translator, cd, ok);370 writeTransUnits(ts, msg, drops, indent); 371 371 } 372 372 } … … 501 501 m_fileName = atts.value(QLatin1String("original")); 502 502 m_language = atts.value(QLatin1String("target-language")); 503 m_language.replace(QLatin1Char('-'), QLatin1Char('_')); 503 504 m_sourceLanguage = atts.value(QLatin1String("source-language")); 505 m_sourceLanguage.replace(QLatin1Char('-'), QLatin1Char('_')); 504 506 } else if (localName == QLatin1String("group")) { 505 507 if (atts.value(QLatin1String("restype")) == QLatin1String(restypeContext)) { … … 599 601 } 600 602 } else if (localName == QLatin1String("target")) { 601 if (popContext(XC_restype_translation)) 603 if (popContext(XC_restype_translation)) { 604 accum.replace(QChar(Translator::TextVariantSeparator), 605 QChar(Translator::BinaryVariantSeparator)); 602 606 m_translations.append(accum); 607 } 603 608 } else if (localName == QLatin1String("context-group")) { 604 609 if (popContext(XC_context_group)) { … … 771 776 ++indent; 772 777 writeExtras(ts, indent, translator.extras(), drops); 778 QString sourceLanguageCode = translator.sourceLanguageCode(); 779 if (sourceLanguageCode.isEmpty() || sourceLanguageCode == QLatin1String("C")) 780 sourceLanguageCode = QLatin1String("en"); 781 else 782 sourceLanguageCode.replace(QLatin1Char('_'), QLatin1Char('-')); 783 QString languageCode = translator.languageCode(); 784 languageCode.replace(QLatin1Char('_'), QLatin1Char('-')); 773 785 foreach (const QString &fn, fileOrder) { 774 786 writeIndent(ts, indent); 775 787 ts << "<file original=\"" << fn << "\"" 776 788 << " datatype=\"" << dataType(messageOrder[fn].begin()->first()) << "\"" 777 << " source-language=\"" 778 << (translator.sourceLanguageCode().isEmpty() ? 779 QByteArray("en") : translator.sourceLanguageCode().toLatin1()) << "\"" 780 << " target-language=\"" << translator.languageCode() << "\"" 789 << " source-language=\"" << sourceLanguageCode.toLatin1() << "\"" 790 << " target-language=\"" << languageCode.toLatin1() << "\"" 781 791 << "><body>\n"; 782 792 ++indent; … … 791 801 792 802 foreach (const TranslatorMessage &msg, messageOrder[fn][ctx]) 793 writeMessage(ts, msg, drops, indent , translator, cd, &ok);803 writeMessage(ts, msg, drops, indent); 794 804 795 805 if (!ctx.isEmpty()) {
Note:
See TracChangeset
for help on using the changeset viewer.