tools/linguist/lupdate/main.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
child 30 5dc02b23752f
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the Qt Linguist of the Qt Toolkit.
     7 ** This file is part of the Qt Linguist of the Qt Toolkit.
     8 **
     8 **
    41 
    41 
    42 #include "lupdate.h"
    42 #include "lupdate.h"
    43 
    43 
    44 #include <translator.h>
    44 #include <translator.h>
    45 #include <profileevaluator.h>
    45 #include <profileevaluator.h>
    46 #include <proreader.h>
       
    47 
    46 
    48 #include <QtCore/QCoreApplication>
    47 #include <QtCore/QCoreApplication>
    49 #include <QtCore/QDebug>
    48 #include <QtCore/QDebug>
    50 #include <QtCore/QDir>
    49 #include <QtCore/QDir>
    51 #include <QtCore/QFile>
    50 #include <QtCore/QFile>
   116         "    -no-ui-lines\n"
   115         "    -no-ui-lines\n"
   117         "           Do not record line numbers in references to UI files.\n"
   116         "           Do not record line numbers in references to UI files.\n"
   118         "    -disable-heuristic {sametext|similartext|number}\n"
   117         "    -disable-heuristic {sametext|similartext|number}\n"
   119         "           Disable the named merge heuristic. Can be specified multiple times.\n"
   118         "           Disable the named merge heuristic. Can be specified multiple times.\n"
   120         "    -pro <filename>\n"
   119         "    -pro <filename>\n"
   121         "           Name of a .pro file. Useful for files with .pro\n"
   120         "           Name of a .pro file. Useful for files with .pro file syntax but\n"
   122         "           file syntax but different file suffix\n"
   121         "           different file suffix. Projects are recursed into and merged.\n"
   123         "    -source-language <language>[_<region>]\n"
   122         "    -source-language <language>[_<region>]\n"
   124         "           Specify the language of the source strings for new files.\n"
   123         "           Specify the language of the source strings for new files.\n"
   125         "           Defaults to POSIX if not specified.\n"
   124         "           Defaults to POSIX if not specified.\n"
   126         "    -target-language <language>[_<region>]\n"
   125         "    -target-language <language>[_<region>]\n"
   127         "           Specify the language of the translations for new files.\n"
   126         "           Specify the language of the translations for new files.\n"
   128         "           Guessed from the file name if not specified.\n"
   127         "           Guessed from the file name if not specified.\n"
       
   128         "    -ts <ts-file>...\n"
       
   129         "           Specify the output file(s). This will override the TRANSLATIONS\n"
       
   130         "           and nullify the CODECFORTR from possibly specified project files.\n"
       
   131         "    -codecfortr <codec>\n"
       
   132         "           Specify the codec assumed for tr() calls. Effective only with -ts.\n"
   129         "    -version\n"
   133         "    -version\n"
   130         "           Display the version of lupdate and exit.\n"
   134         "           Display the version of lupdate and exit.\n"
   131     ).arg(m_defaultExtensions));
   135     ).arg(m_defaultExtensions));
   132 }
   136 }
   133 
   137 
   134 static void updateTsFiles(const Translator &fetchedTor, const QStringList &tsFileNames,
   138 static void updateTsFiles(const Translator &fetchedTor, const QStringList &tsFileNames,
   135     const QByteArray &codecForTr, const QString &sourceLanguage, const QString &targetLanguage,
   139     bool setCodec, const QString &sourceLanguage, const QString &targetLanguage,
   136     UpdateOptions options, bool *fail)
   140     UpdateOptions options, bool *fail)
   137 {
   141 {
   138     QDir dir;
   142     QDir dir;
   139     QString err;
   143     QString err;
   140     foreach (const QString &fileName, tsFileNames) {
   144     foreach (const QString &fileName, tsFileNames) {
   148                 *fail = true;
   152                 *fail = true;
   149                 continue;
   153                 continue;
   150             }
   154             }
   151             tor.resolveDuplicates();
   155             tor.resolveDuplicates();
   152             cd.clearErrors();
   156             cd.clearErrors();
   153             if (!codecForTr.isEmpty() && codecForTr != tor.codecName())
   157             if (setCodec && fetchedTor.codec() != tor.codec())
   154                 qWarning("lupdate warning: Codec for tr() '%s' disagrees with "
   158                 qWarning("lupdate warning: Codec for tr() '%s' disagrees with "
   155                          "existing file's codec '%s'. Expect trouble.",
   159                          "existing file's codec '%s'. Expect trouble.",
   156                          codecForTr.constData(), tor.codecName().constData());
   160                          fetchedTor.codecName().constData(), tor.codecName().constData());
   157             if (!targetLanguage.isEmpty() && targetLanguage != tor.languageCode())
   161             if (!targetLanguage.isEmpty() && targetLanguage != tor.languageCode())
   158                 qWarning("lupdate warning: Specified target language '%s' disagrees with "
   162                 qWarning("lupdate warning: Specified target language '%s' disagrees with "
   159                          "existing file's language '%s'. Ignoring.",
   163                          "existing file's language '%s'. Ignoring.",
   160                          qPrintable(targetLanguage), qPrintable(tor.languageCode()));
   164                          qPrintable(targetLanguage), qPrintable(tor.languageCode()));
   161             if (!sourceLanguage.isEmpty() && sourceLanguage != tor.sourceLanguageCode())
   165             if (!sourceLanguage.isEmpty() && sourceLanguage != tor.sourceLanguageCode())
   162                 qWarning("lupdate warning: Specified source language '%s' disagrees with "
   166                 qWarning("lupdate warning: Specified source language '%s' disagrees with "
   163                          "existing file's language '%s'. Ignoring.",
   167                          "existing file's language '%s'. Ignoring.",
   164                          qPrintable(sourceLanguage), qPrintable(tor.sourceLanguageCode()));
   168                          qPrintable(sourceLanguage), qPrintable(tor.sourceLanguageCode()));
   165         } else {
   169         } else {
   166             if (!codecForTr.isEmpty())
   170             if (setCodec)
   167                 tor.setCodecName(codecForTr);
   171                 tor.setCodec(fetchedTor.codec());
   168             if (!targetLanguage.isEmpty())
   172             if (!targetLanguage.isEmpty())
   169                 tor.setLanguageCode(targetLanguage);
   173                 tor.setLanguageCode(targetLanguage);
   170             else
   174             else
   171                 tor.setLanguageCode(Translator::guessLanguageCodeFromFileName(fileName));
   175                 tor.setLanguageCode(Translator::guessLanguageCodeFromFileName(fileName));
   172             if (!sourceLanguage.isEmpty())
   176             if (!sourceLanguage.isEmpty())
   184 
   188 
   185         UpdateOptions theseOptions = options;
   189         UpdateOptions theseOptions = options;
   186         if (tor.locationsType() == Translator::NoLocations) // Could be set from file
   190         if (tor.locationsType() == Translator::NoLocations) // Could be set from file
   187             theseOptions |= NoLocations;
   191             theseOptions |= NoLocations;
   188         Translator out = merge(tor, fetchedTor, theseOptions, err);
   192         Translator out = merge(tor, fetchedTor, theseOptions, err);
   189         if (!codecForTr.isEmpty())
   193         if (setCodec)
   190             out.setCodecName(codecForTr);
   194             out.setCodec(fetchedTor.codec());
   191 
   195 
   192         if ((options & Verbose) && !err.isEmpty()) {
   196         if ((options & Verbose) && !err.isEmpty()) {
   193             printOut(err);
   197             printOut(err);
   194             err.clear();
   198             err.clear();
   195         }
   199         }
   212             *fail = true;
   216             *fail = true;
   213         }
   217         }
   214     }
   218     }
   215 }
   219 }
   216 
   220 
       
   221 static QStringList getSources(const char *var, const char *vvar, const QStringList &baseVPaths,
       
   222                               const QString &projectDir, const ProFileEvaluator &visitor)
       
   223 {
       
   224     QStringList vPaths = visitor.absolutePathValues(QLatin1String(vvar), projectDir);
       
   225     vPaths += baseVPaths;
       
   226     vPaths.removeDuplicates();
       
   227     return visitor.absoluteFileValues(QLatin1String(var), projectDir, vPaths, 0);
       
   228 }
       
   229 
       
   230 static QStringList getSources(const ProFileEvaluator &visitor, const QString &projectDir)
       
   231 {
       
   232     QStringList baseVPaths;
       
   233     baseVPaths += visitor.absolutePathValues(QLatin1String("VPATH"), projectDir);
       
   234     baseVPaths << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH
       
   235     baseVPaths += visitor.absolutePathValues(QLatin1String("DEPENDPATH"), projectDir);
       
   236     baseVPaths.removeDuplicates();
       
   237 
       
   238     QStringList sourceFiles;
       
   239 
       
   240     // app/lib template
       
   241     sourceFiles += getSources("SOURCES", "VPATH_SOURCES", baseVPaths, projectDir, visitor);
       
   242 
       
   243     sourceFiles += getSources("FORMS", "VPATH_FORMS", baseVPaths, projectDir, visitor);
       
   244     sourceFiles += getSources("FORMS3", "VPATH_FORMS3", baseVPaths, projectDir, visitor);
       
   245 
       
   246     QStringList vPathsInc = baseVPaths;
       
   247     vPathsInc += visitor.absolutePathValues(QLatin1String("INCLUDEPATH"), projectDir);
       
   248     vPathsInc.removeDuplicates();
       
   249     sourceFiles += visitor.absoluteFileValues(QLatin1String("HEADERS"), projectDir, vPathsInc, 0);
       
   250 
       
   251     sourceFiles.removeDuplicates();
       
   252     sourceFiles.sort();
       
   253 
       
   254     return sourceFiles;
       
   255 }
       
   256 
       
   257 static void processSources(Translator &fetchedTor,
       
   258                            const QStringList &sourceFiles, ConversionData &cd)
       
   259 {
       
   260     QStringList sourceFilesCpp;
       
   261     for (QStringList::const_iterator it = sourceFiles.begin(); it != sourceFiles.end(); ++it) {
       
   262         if (it->endsWith(QLatin1String(".java"), Qt::CaseInsensitive))
       
   263             loadJava(fetchedTor, *it, cd);
       
   264         else if (it->endsWith(QLatin1String(".ui"), Qt::CaseInsensitive)
       
   265                  || it->endsWith(QLatin1String(".jui"), Qt::CaseInsensitive))
       
   266             loadUI(fetchedTor, *it, cd);
       
   267         else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive)
       
   268                  || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive))
       
   269             loadQScript(fetchedTor, *it, cd);
       
   270         else
       
   271             sourceFilesCpp << *it;
       
   272     }
       
   273     loadCPP(fetchedTor, sourceFilesCpp, cd);
       
   274     if (!cd.error().isEmpty())
       
   275         printOut(cd.error());
       
   276 }
       
   277 
       
   278 static void processProjects(
       
   279         bool topLevel, bool nestComplain, const QStringList &proFiles,
       
   280         UpdateOptions options, const QByteArray &codecForSource,
       
   281         const QString &targetLanguage, const QString &sourceLanguage,
       
   282         Translator *parentTor, bool *fail);
       
   283 
       
   284 static void processProject(
       
   285         bool nestComplain, const QFileInfo &pfi, ProFileEvaluator &visitor,
       
   286         UpdateOptions options, const QByteArray &_codecForSource,
       
   287         const QString &targetLanguage, const QString &sourceLanguage,
       
   288         Translator *fetchedTor, bool *fail)
       
   289 {
       
   290     QByteArray codecForSource = _codecForSource;
       
   291     QStringList tmp = visitor.values(QLatin1String("CODECFORSRC"));
       
   292     if (!tmp.isEmpty()) {
       
   293         codecForSource = tmp.last().toLatin1();
       
   294         if (!QTextCodec::codecForName(codecForSource)) {
       
   295             qWarning("lupdate warning: Codec for source '%s' is invalid. "
       
   296                      "Falling back to codec for tr().", codecForSource.constData());
       
   297             codecForSource.clear();
       
   298         }
       
   299     }
       
   300     if (visitor.templateType() == ProFileEvaluator::TT_Subdirs) {
       
   301         QStringList subProFiles;
       
   302         QDir proDir(pfi.absoluteDir());
       
   303         foreach (const QString &subdir, visitor.values(QLatin1String("SUBDIRS"))) {
       
   304             QString subPro = QDir::cleanPath(proDir.absoluteFilePath(subdir));
       
   305             QFileInfo subInfo(subPro);
       
   306             if (subInfo.isDir())
       
   307                 subProFiles << (subPro + QLatin1Char('/')
       
   308                                 + subInfo.fileName() + QLatin1String(".pro"));
       
   309             else
       
   310                 subProFiles << subPro;
       
   311         }
       
   312         processProjects(false, nestComplain, subProFiles, options, codecForSource,
       
   313                         targetLanguage, sourceLanguage, fetchedTor, fail);
       
   314     } else {
       
   315         ConversionData cd;
       
   316         cd.m_noUiLines = options & NoUiLines;
       
   317         cd.m_codecForSource = codecForSource;
       
   318         cd.m_includePath = visitor.values(QLatin1String("INCLUDEPATH"));
       
   319         QStringList sourceFiles = getSources(visitor, pfi.absolutePath());
       
   320         QSet<QString> sourceDirs;
       
   321         sourceDirs.insert(QDir::cleanPath(pfi.absolutePath()) + QLatin1Char('/'));
       
   322         foreach (const QString &sf, sourceFiles)
       
   323             sourceDirs.insert(sf.left(sf.lastIndexOf(QLatin1Char('/')) + 1));
       
   324         QStringList rootList = sourceDirs.toList();
       
   325         rootList.sort();
       
   326         for (int prev = 0, curr = 1; curr < rootList.length(); )
       
   327             if (rootList.at(curr).startsWith(rootList.at(prev)))
       
   328                 rootList.removeAt(curr);
       
   329             else
       
   330                 prev = curr++;
       
   331         cd.m_projectRoots = QSet<QString>::fromList(rootList);
       
   332         processSources(*fetchedTor, sourceFiles, cd);
       
   333     }
       
   334 }
       
   335 
       
   336 static void processProjects(
       
   337         bool topLevel, bool nestComplain, const QStringList &proFiles,
       
   338         UpdateOptions options, const QByteArray &codecForSource,
       
   339         const QString &targetLanguage, const QString &sourceLanguage,
       
   340         Translator *parentTor, bool *fail)
       
   341 {
       
   342     foreach (const QString &proFile, proFiles) {
       
   343         ProFileEvaluator visitor;
       
   344         visitor.setVerbose(options & Verbose);
       
   345 
       
   346         QFileInfo pfi(proFile);
       
   347         ProFile pro(pfi.absoluteFilePath());
       
   348         if (!visitor.queryProFile(&pro) || !visitor.accept(&pro)) {
       
   349             if (topLevel)
       
   350                 *fail = true;
       
   351             continue;
       
   352         }
       
   353 
       
   354         if (visitor.contains(QLatin1String("TRANSLATIONS"))) {
       
   355             if (parentTor) {
       
   356                 if (topLevel) {
       
   357                     std::cerr << "lupdate warning: TS files from command line "
       
   358                             "will override TRANSLATIONS in " << qPrintable(proFile) << ".\n";
       
   359                     goto noTrans;
       
   360                 } else if (nestComplain) {
       
   361                     std::cerr << "lupdate warning: TS files from command line "
       
   362                             "prevent recursing into " << qPrintable(proFile) << ".\n";
       
   363                     continue;
       
   364                 }
       
   365             }
       
   366             QStringList tsFiles;
       
   367             QDir proDir(pfi.absolutePath());
       
   368             foreach (const QString &tsFile, visitor.values(QLatin1String("TRANSLATIONS")))
       
   369                 tsFiles << QFileInfo(proDir, tsFile).filePath();
       
   370             if (tsFiles.isEmpty()) {
       
   371                 // This might mean either a buggy PRO file or an intentional detach -
       
   372                 // we can't know without seeing the actual RHS of the assignment ...
       
   373                 // Just assume correctness and be silent.
       
   374                 continue;
       
   375             }
       
   376             Translator tor;
       
   377             bool setCodec = false;
       
   378             QStringList tmp = visitor.values(QLatin1String("CODEC"))
       
   379                               + visitor.values(QLatin1String("DEFAULTCODEC"))
       
   380                               + visitor.values(QLatin1String("CODECFORTR"));
       
   381             if (!tmp.isEmpty()) {
       
   382                 tor.setCodecName(tmp.last().toLatin1());
       
   383                 setCodec = true;
       
   384             }
       
   385             processProject(false, pfi, visitor, options, codecForSource,
       
   386                            targetLanguage, sourceLanguage, &tor, fail);
       
   387             updateTsFiles(tor, tsFiles, setCodec, sourceLanguage, targetLanguage, options, fail);
       
   388             continue;
       
   389         }
       
   390       noTrans:
       
   391         if (!parentTor) {
       
   392             if (topLevel)
       
   393                 std::cerr << "lupdate warning: no TS files specified. Only diagnostics "
       
   394                         "will be produced for '" << qPrintable(proFile) << "'.\n";
       
   395             Translator tor;
       
   396             processProject(nestComplain, pfi, visitor, options, codecForSource,
       
   397                            targetLanguage, sourceLanguage, &tor, fail);
       
   398         } else {
       
   399             processProject(nestComplain, pfi, visitor, options, codecForSource,
       
   400                            targetLanguage, sourceLanguage, parentTor, fail);
       
   401         }
       
   402     }
       
   403 }
       
   404 
   217 int main(int argc, char **argv)
   405 int main(int argc, char **argv)
   218 {
   406 {
   219     QCoreApplication app(argc, argv);
   407     QCoreApplication app(argc, argv);
   220     m_defaultExtensions = QLatin1String("ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx");
   408     m_defaultExtensions = QLatin1String("ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx");
   221 
   409 
   222     QStringList args = app.arguments();
   410     QStringList args = app.arguments();
   223     QString defaultContext; // This was QLatin1String("@default") before.
       
   224     Translator fetchedTor;
       
   225     QByteArray codecForTr;
       
   226     QByteArray codecForSource;
       
   227     QStringList tsFileNames;
   411     QStringList tsFileNames;
   228     QStringList proFiles;
   412     QStringList proFiles;
   229     QMultiHash<QString, QString> allCSources;
   413     QMultiHash<QString, QString> allCSources;
   230     QSet<QString> projectRoots;
   414     QSet<QString> projectRoots;
   231     QStringList sourceFiles;
   415     QStringList sourceFiles;
   232     QStringList includePath;
   416     QStringList includePath;
   233     QString targetLanguage;
   417     QString targetLanguage;
   234     QString sourceLanguage;
   418     QString sourceLanguage;
       
   419     QByteArray codecForTr;
   235 
   420 
   236     UpdateOptions options =
   421     UpdateOptions options =
   237         Verbose | // verbose is on by default starting with Qt 4.2
   422         Verbose | // verbose is on by default starting with Qt 4.2
   238         HeuristicSameText | HeuristicSimilarText | HeuristicNumber;
   423         HeuristicSameText | HeuristicSimilarText | HeuristicNumber;
   239     int numFiles = 0;
   424     int numFiles = 0;
   240     bool standardSyntax = true;
       
   241     bool metTsFlag = false;
   425     bool metTsFlag = false;
   242     bool recursiveScan = true;
   426     bool recursiveScan = true;
   243 
   427 
   244     QString extensions = m_defaultExtensions;
   428     QString extensions = m_defaultExtensions;
   245     QSet<QString> extensionsNameFilters;
   429     QSet<QString> extensionsNameFilters;
   246 
       
   247     for (int  i = 1; i < argc; ++i) {
       
   248         if (args.at(i) == QLatin1String("-ts"))
       
   249             standardSyntax = false;
       
   250     }
       
   251 
   430 
   252     for (int i = 1; i < argc; ++i) {
   431     for (int i = 1; i < argc; ++i) {
   253         QString arg = args.at(i);
   432         QString arg = args.at(i);
   254         if (arg == QLatin1String("-help")
   433         if (arg == QLatin1String("-help")
   255                 || arg == QLatin1String("--help")
   434                 || arg == QLatin1String("--help")
   334             options |= NoSort;
   513             options |= NoSort;
   335             continue;
   514             continue;
   336         } else if (arg == QLatin1String("-version")) {
   515         } else if (arg == QLatin1String("-version")) {
   337             printOut(QObject::tr("lupdate version %1\n").arg(QLatin1String(QT_VERSION_STR)));
   516             printOut(QObject::tr("lupdate version %1\n").arg(QLatin1String(QT_VERSION_STR)));
   338             return 0;
   517             return 0;
       
   518         } else if (arg == QLatin1String("-codecfortr")) {
       
   519             ++i;
       
   520             if (i == argc) {
       
   521                 qWarning("The -codecfortr option should be followed by a codec name.");
       
   522                 return 1;
       
   523             }
       
   524             codecForTr = args[i].toLatin1();
       
   525             continue;
   339         } else if (arg == QLatin1String("-ts")) {
   526         } else if (arg == QLatin1String("-ts")) {
   340             metTsFlag = true;
   527             metTsFlag = true;
   341             continue;
   528             continue;
   342         } else if (arg == QLatin1String("-extensions")) {
   529         } else if (arg == QLatin1String("-extensions")) {
   343             ++i;
   530             ++i;
   370             continue;
   557             continue;
   371         } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) {
   558         } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) {
   372             qWarning("Unrecognized option '%s'", qPrintable(arg));
   559             qWarning("Unrecognized option '%s'", qPrintable(arg));
   373             return 1;
   560             return 1;
   374         }
   561         }
   375 
       
   376         numFiles++;
       
   377 
       
   378         QString fullText;
       
   379 
       
   380         codecForTr.clear();
       
   381         codecForSource.clear();
       
   382 
   562 
   383         if (metTsFlag) {
   563         if (metTsFlag) {
   384             bool found = false;
   564             bool found = false;
   385             foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) {
   565             foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) {
   386                 if (arg.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) {
   566                 if (arg.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) {
   401                 return 1;
   581                 return 1;
   402             }
   582             }
   403         } else if (arg.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
   583         } else if (arg.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
   404                 || arg.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
   584                 || arg.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
   405             proFiles << arg;
   585             proFiles << arg;
       
   586             numFiles++;
   406         } else {
   587         } else {
   407             QFileInfo fi(arg);
   588             QFileInfo fi(arg);
   408             if (!fi.exists()) {
   589             if (!fi.exists()) {
   409                 qWarning("lupdate error: File '%s' does not exists\n", qPrintable(arg));
   590                 qWarning("lupdate error: File '%s' does not exists\n", qPrintable(arg));
   410                 return 1;
   591                 return 1;
   445                     }
   626                     }
   446                 }
   627                 }
   447             } else {
   628             } else {
   448                 sourceFiles << QDir::cleanPath(fi.absoluteFilePath());;
   629                 sourceFiles << QDir::cleanPath(fi.absoluteFilePath());;
   449             }
   630             }
       
   631             numFiles++;
   450         }
   632         }
   451     } // for args
   633     } // for args
   452 
   634 
   453     foreach (const QString &proFile, proFiles)
   635     if (numFiles == 0) {
   454         projectRoots.insert(QDir::cleanPath(QFileInfo(proFile).absolutePath()) + QLatin1Char('/'));
   636         printUsage();
   455 
   637         return 1;
   456     bool firstPass = true;
   638     }
       
   639 
       
   640     if (!targetLanguage.isEmpty() && tsFileNames.count() != 1)
       
   641         std::cerr << "lupdate warning: -target-language usually only "
       
   642                      "makes sense with exactly one TS file.\n";
       
   643     if (!codecForTr.isEmpty() && tsFileNames.isEmpty())
       
   644         std::cerr << "lupdate warning: -codecfortr has no effect without -ts.\n";
       
   645 
   457     bool fail = false;
   646     bool fail = false;
   458     while (firstPass || !proFiles.isEmpty()) {
   647     if (proFiles.isEmpty()) {
       
   648         if (tsFileNames.isEmpty())
       
   649             std::cerr << "lupdate warning: no TS files specified. "
       
   650                          "Only diagnostics will be produced.\n";
       
   651 
       
   652         Translator fetchedTor;
   459         ConversionData cd;
   653         ConversionData cd;
   460         cd.m_defaultContext = defaultContext;
       
   461         cd.m_noUiLines = options & NoUiLines;
   654         cd.m_noUiLines = options & NoUiLines;
   462         cd.m_projectRoots = projectRoots;
   655         cd.m_projectRoots = projectRoots;
   463         cd.m_includePath = includePath;
   656         cd.m_includePath = includePath;
   464         cd.m_allCSources = allCSources;
   657         cd.m_allCSources = allCSources;
   465 
   658         fetchedTor.setCodecName(codecForTr);
   466         QStringList tsFiles = tsFileNames;
   659         processSources(fetchedTor, sourceFiles, cd);
   467         if (proFiles.count() > 0) {
   660         updateTsFiles(fetchedTor, tsFileNames, !codecForTr.isEmpty(),
   468             QFileInfo pfi(proFiles.takeFirst());
   661                       sourceLanguage, targetLanguage, options, &fail);
   469             QHash<QByteArray, QStringList> variables;
   662     } else {
   470 
   663         if (!sourceFiles.isEmpty() || !includePath.isEmpty()) {
   471             ProFileEvaluator visitor;
   664             qWarning("lupdate error: Both project and source files / include paths specified.\n");
   472             visitor.setVerbose(options & Verbose);
   665             return 1;
   473 
   666         }
   474             ProFile pro(pfi.absoluteFilePath());
   667         if (!tsFileNames.isEmpty()) {
   475             if (!visitor.queryProFile(&pro))
   668             Translator fetchedTor;
   476                 return 2;
   669             fetchedTor.setCodecName(codecForTr);
   477             if (!visitor.accept(&pro))
   670             processProjects(true, true, proFiles, options, QByteArray(),
   478                 return 2;
   671                             targetLanguage, sourceLanguage, &fetchedTor, &fail);
   479 
   672             updateTsFiles(fetchedTor, tsFileNames, !codecForTr.isEmpty(),
   480             if (visitor.templateType() == ProFileEvaluator::TT_Subdirs) {
   673                           sourceLanguage, targetLanguage, options, &fail);
   481                 QDir proDir(pfi.absoluteDir());
   674         } else {
   482                 foreach (const QString &subdir, visitor.values(QLatin1String("SUBDIRS"))) {
   675             processProjects(true, false, proFiles, options, QByteArray(),
   483                     QString subPro = QDir::cleanPath(proDir.absoluteFilePath(subdir));
   676                             targetLanguage, sourceLanguage, 0, &fail);
   484                     QFileInfo subInfo(subPro);
   677         }
   485                     if (subInfo.isDir())
       
   486                         proFiles << (subPro + QLatin1Char('/')
       
   487                                      + subInfo.fileName() + QLatin1String(".pro"));
       
   488                     else
       
   489                         proFiles << subPro;
       
   490                 }
       
   491                 continue;
       
   492             }
       
   493 
       
   494             cd.m_includePath += visitor.values(QLatin1String("INCLUDEPATH"));
       
   495 
       
   496             evaluateProFile(visitor, &variables, pfi.absolutePath());
       
   497 
       
   498             sourceFiles = variables.value("SOURCES");
       
   499 
       
   500             QStringList tmp = variables.value("CODECFORTR");
       
   501             if (!tmp.isEmpty() && !tmp.first().isEmpty()) {
       
   502                 codecForTr = tmp.first().toLatin1();
       
   503                 fetchedTor.setCodecName(codecForTr);
       
   504                 cd.m_outputCodec = codecForTr;
       
   505             }
       
   506             tmp = variables.value("CODECFORSRC");
       
   507             if (!tmp.isEmpty() && !tmp.first().isEmpty()) {
       
   508                 codecForSource = tmp.first().toLatin1();
       
   509                 if (!QTextCodec::codecForName(codecForSource))
       
   510                     qWarning("lupdate warning: Codec for source '%s' is invalid. Falling back to codec for tr().",
       
   511                              codecForSource.constData());
       
   512                 else
       
   513                     cd.m_codecForSource = codecForSource;
       
   514             }
       
   515 
       
   516             tsFiles += variables.value("TRANSLATIONS");
       
   517         }
       
   518 
       
   519         QStringList sourceFilesCpp;
       
   520         for (QStringList::iterator it = sourceFiles.begin(); it != sourceFiles.end(); ++it) {
       
   521             if (it->endsWith(QLatin1String(".java"), Qt::CaseInsensitive))
       
   522                 loadJava(fetchedTor, *it, cd);
       
   523             else if (it->endsWith(QLatin1String(".ui"), Qt::CaseInsensitive)
       
   524                      || it->endsWith(QLatin1String(".jui"), Qt::CaseInsensitive))
       
   525                 loadUI(fetchedTor, *it, cd);
       
   526             else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive)
       
   527                      || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive))
       
   528                 loadQScript(fetchedTor, *it, cd);
       
   529             else
       
   530                 sourceFilesCpp << *it;
       
   531         }
       
   532         loadCPP(fetchedTor, sourceFilesCpp, cd);
       
   533         if (!cd.error().isEmpty())
       
   534             printOut(cd.error());
       
   535 
       
   536         tsFiles.sort();
       
   537         tsFiles.removeDuplicates();
       
   538 
       
   539         if (!tsFiles.isEmpty())
       
   540             updateTsFiles(fetchedTor, tsFiles, codecForTr, sourceLanguage, targetLanguage, options, &fail);
       
   541 
       
   542         firstPass = false;
       
   543     }
   678     }
   544 
       
   545     if (numFiles == 0) {
       
   546         printUsage();
       
   547         return 1;
       
   548     }
       
   549 
       
   550     return fail ? 1 : 0;
   679     return fail ? 1 : 0;
   551 }
   680 }