From c22d9e8afe54f62772ee49659eb86d0658fa8476 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 29 May 2013 20:18:51 +0200 Subject: [PATCH] implement simple VFS to support caching during project parsing sync up with qt creator. this counts as a bugfix, because it makes write_file() and cache() do something remotely useful. Change-Id: I833253f81c3159056fab2ff888f293b36cc2ef56 Reviewed-by: Daniel Teske Reviewed-by: Joerg Bornemann (cherry picked from qtbase/b215176da34661969015e4950815fe8297885163) (cherry picked from qtcreator/66802ef8bf7989dc025e34bf91d93576189c483c) --- src/linguist/lrelease/main.cpp | 6 +- src/linguist/lupdate/main.cpp | 26 +++-- src/linguist/shared/profileevaluator.cpp | 4 +- src/linguist/shared/profileevaluator.h | 4 +- src/linguist/shared/proparser.pri | 2 + src/linguist/shared/qmakebuiltins.cpp | 43 +------ src/linguist/shared/qmakeevaluator.cpp | 19 +-- src/linguist/shared/qmakeevaluator.h | 3 +- src/linguist/shared/qmakeparser.cpp | 24 ++-- src/linguist/shared/qmakeparser.h | 4 +- src/linguist/shared/qmakevfs.cpp | 192 +++++++++++++++++++++++++++++++ src/linguist/shared/qmakevfs.h | 85 ++++++++++++++ 12 files changed, 331 insertions(+), 81 deletions(-) create mode 100644 src/linguist/shared/qmakevfs.cpp create mode 100644 src/linguist/shared/qmakevfs.h diff --git a/src/linguist/lrelease/main.cpp b/src/linguist/lrelease/main.cpp index 2d6b60a..8116616 100644 --- a/src/linguist/lrelease/main.cpp +++ b/src/linguist/lrelease/main.cpp @@ -41,6 +41,7 @@ #include "translator.h" +#include #include #include @@ -318,8 +319,9 @@ int main(int argc, char **argv) option.qmake_abslocation = app.applicationDirPath() + QLatin1String("/qmake"); #endif option.initProperties(); - QMakeParser parser(0, &evalHandler); - ProFileEvaluator visitor(&option, &parser, &evalHandler); + QMakeVfs vfs; + QMakeParser parser(0, &vfs, &evalHandler); + ProFileEvaluator visitor(&option, &parser, &vfs, &evalHandler); visitor.setCumulative(true); visitor.setOutputDir(QDir::currentPath()); diff --git a/src/linguist/lupdate/main.cpp b/src/linguist/lupdate/main.cpp index ec2be57..bf98c8d 100644 --- a/src/linguist/lupdate/main.cpp +++ b/src/linguist/lupdate/main.cpp @@ -42,6 +42,7 @@ #include "lupdate.h" #include +#include #include #include @@ -374,14 +375,15 @@ static void processSources(Translator &fetchedTor, } static void processProjects(bool topLevel, bool nestComplain, const QStringList &proFiles, - const QHash &outDirMap, ProFileGlobals *option, QMakeParser *parser, + const QHash &outDirMap, + ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, UpdateOptions options, const QString &targetLanguage, const QString &sourceLanguage, Translator *parentTor, bool *fail); static void processProject( bool nestComplain, const QString &proFile, - ProFileGlobals *option, QMakeParser *parser, ProFileEvaluator &visitor, + ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, ProFileEvaluator &visitor, UpdateOptions options, const QString &targetLanguage, const QString &sourceLanguage, Translator *fetchedTor, bool *fail) @@ -421,7 +423,7 @@ static void processProject( subProFiles << subPro; } processProjects(false, nestComplain, subProFiles, QHash(), - option, parser, options, + option, vfs, parser, options, targetLanguage, sourceLanguage, fetchedTor, fail); } else { ConversionData cd; @@ -447,7 +449,8 @@ static void processProject( } static void processProjects(bool topLevel, bool nestComplain, const QStringList &proFiles, - const QHash &outDirMap, ProFileGlobals *option, QMakeParser *parser, + const QHash &outDirMap, + ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, UpdateOptions options, const QString &targetLanguage, const QString &sourceLanguage, Translator *parentTor, bool *fail) @@ -457,7 +460,7 @@ static void processProjects(bool topLevel, bool nestComplain, const QStringList if (!outDirMap.isEmpty()) option->setDirectories(QFileInfo(proFile).path(), outDirMap[proFile]); - ProFileEvaluator visitor(option, parser, &evalHandler); + ProFileEvaluator visitor(option, parser, vfs, &evalHandler); visitor.setCumulative(true); visitor.setOutputDir(option->shadowedPath(proFile)); ProFile *pro; @@ -499,7 +502,7 @@ static void processProjects(bool topLevel, bool nestComplain, const QStringList continue; } Translator tor; - processProject(false, proFile, option, parser, visitor, options, + processProject(false, proFile, option, vfs, parser, visitor, options, targetLanguage, sourceLanguage, &tor, fail); updateTsFiles(tor, tsFiles, QStringList(), sourceLanguage, targetLanguage, options, fail); @@ -512,10 +515,10 @@ static void processProjects(bool topLevel, bool nestComplain, const QStringList printErr(LU::tr("lupdate warning: no TS files specified. Only diagnostics " "will be produced for '%1'.\n").arg(proFile)); Translator tor; - processProject(nestComplain, proFile, option, parser, visitor, options, + processProject(nestComplain, proFile, option, vfs, parser, visitor, options, targetLanguage, sourceLanguage, &tor, fail); } else { - processProject(nestComplain, proFile, option, parser, visitor, options, + processProject(nestComplain, proFile, option, vfs, parser, visitor, options, targetLanguage, sourceLanguage, parentTor, fail); } pro->deref(); @@ -854,16 +857,17 @@ int main(int argc, char **argv) option.initProperties(); option.setCommandLineArguments(QDir::currentPath(), QStringList() << QLatin1String("CONFIG+=lupdate_run")); - QMakeParser parser(0, &evalHandler); + QMakeVfs vfs; + QMakeParser parser(0, &vfs, &evalHandler); if (!tsFileNames.isEmpty()) { Translator fetchedTor; - processProjects(true, true, proFiles, outDirMap, &option, &parser, options, + processProjects(true, true, proFiles, outDirMap, &option, &vfs, &parser, options, targetLanguage, sourceLanguage, &fetchedTor, &fail); updateTsFiles(fetchedTor, tsFileNames, alienFiles, sourceLanguage, targetLanguage, options, &fail); } else { - processProjects(true, false, proFiles, outDirMap, &option, &parser, options, + processProjects(true, false, proFiles, outDirMap, &option, &vfs, &parser, options, targetLanguage, sourceLanguage, 0, &fail); } } diff --git a/src/linguist/shared/profileevaluator.cpp b/src/linguist/shared/profileevaluator.cpp index f22b3f4..58ad162 100644 --- a/src/linguist/shared/profileevaluator.cpp +++ b/src/linguist/shared/profileevaluator.cpp @@ -55,9 +55,9 @@ void ProFileEvaluator::initialize() QMakeEvaluator::initStatics(); } -ProFileEvaluator::ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser, +ProFileEvaluator::ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser, QMakeVfs *vfs, QMakeHandler *handler) - : d(new QMakeEvaluator(option, parser, handler)) + : d(new QMakeEvaluator(option, parser, vfs, handler)) { } diff --git a/src/linguist/shared/profileevaluator.h b/src/linguist/shared/profileevaluator.h index 6046b1b..8a7c5c8 100644 --- a/src/linguist/shared/profileevaluator.h +++ b/src/linguist/shared/profileevaluator.h @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE +class QMakeVfs; class QMakeParser; class QMakeEvaluator; class QMakeHandler; @@ -77,7 +78,8 @@ public: // Call this from a concurrency-free context static void initialize(); - ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser, QMakeHandler *handler); + ProFileEvaluator(ProFileGlobals *option, QMakeParser *parser, QMakeVfs *vfs, + QMakeHandler *handler); ~ProFileEvaluator(); ProFileEvaluator::TemplateType templateType() const; diff --git a/src/linguist/shared/proparser.pri b/src/linguist/shared/proparser.pri index 69e09c8..124227b 100644 --- a/src/linguist/shared/proparser.pri +++ b/src/linguist/shared/proparser.pri @@ -6,6 +6,7 @@ DEFINES += PROEVALUATOR_CUMULATIVE PROEVALUATOR_INIT_PROPS HEADERS += \ $$PWD/qmake_global.h \ $$PWD/ioutils.h \ + $$PWD/qmakevfs.h \ $$PWD/proitems.h \ $$PWD/qmakeglobals.h \ $$PWD/qmakeparser.h \ @@ -15,6 +16,7 @@ HEADERS += \ SOURCES += \ $$PWD/ioutils.cpp \ + $$PWD/qmakevfs.cpp \ $$PWD/proitems.cpp \ $$PWD/qmakeglobals.cpp \ $$PWD/qmakeparser.cpp \ diff --git a/src/linguist/shared/qmakebuiltins.cpp b/src/linguist/shared/qmakebuiltins.cpp index 2ccce26..b4694cf 100644 --- a/src/linguist/shared/qmakebuiltins.cpp +++ b/src/linguist/shared/qmakebuiltins.cpp @@ -44,6 +44,7 @@ #include "qmakeevaluator_p.h" #include "qmakeglobals.h" #include "qmakeparser.h" +#include "qmakevfs.h" #include "ioutils.h" #include @@ -281,41 +282,12 @@ quoteValue(const ProString &val) return ret; } -static bool -doWriteFile(const QString &name, QIODevice::OpenMode mode, const QString &contents, QString *errStr) -{ - QByteArray bytes = contents.toLocal8Bit(); - QFile cfile(name); - if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) { - if (cfile.readAll() == bytes) - return true; - cfile.close(); - } - if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) { - *errStr = cfile.errorString(); - return false; - } - cfile.write(bytes); - cfile.close(); - if (cfile.error() != QFile::NoError) { - *errStr = cfile.errorString(); - return false; - } - return true; -} - QMakeEvaluator::VisitReturn QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, const QString &contents) { - QFileInfo qfi(fn); - if (!QDir::current().mkpath(qfi.path())) { - evalError(fL1S("Cannot create %1directory %2.") - .arg(ctx, QDir::toNativeSeparators(qfi.path()))); - return ReturnFalse; - } QString errStr; - if (!doWriteFile(fn, mode, contents, &errStr)) { + if (!m_vfs->writeFile(fn, mode, contents, &errStr)) { evalError(fL1S("Cannot write %1file %2: %3.") .arg(ctx, QDir::toNativeSeparators(fn), errStr)); return ReturnFalse; @@ -1427,6 +1399,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } const QString &file = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1))); + // Don't use VFS here: + // - it supports neither listing nor even directories + // - it's unlikely that somebody would test for files they created themselves if (IoUtils::exists(file)) return ReturnTrue; int slsh = file.lastIndexOf(QLatin1Char('/')); @@ -1458,7 +1433,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( evalError(fL1S("write_file(name, [content var, [append]]) requires one to three arguments.")); return ReturnFalse; } -#ifdef PROEVALUATOR_FULL QIODevice::OpenMode mode = QIODevice::Truncate; QString contents; if (args.count() >= 2) { @@ -1470,9 +1444,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( mode = QIODevice::Append; } return writeFile(QString(), resolvePath(args.at(0).toQString(m_tmp1)), mode, contents); -#else - return ReturnTrue; -#endif } case T_TOUCH: { if (args.count() != 2) { @@ -1524,7 +1495,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( evalError(fL1S("cache(var, [set|add|sub] [transient] [super], [srcvar]) requires one to three arguments.")); return ReturnFalse; } -#ifdef PROEVALUATOR_FULL bool persist = true; bool super = false; enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet; @@ -1650,9 +1620,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( fn = m_cachefile; } return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr); -#else - return ReturnTrue; -#endif } default: evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1))); diff --git a/src/linguist/shared/qmakeevaluator.cpp b/src/linguist/shared/qmakeevaluator.cpp index 9c7bf45..4bf1ea2 100644 --- a/src/linguist/shared/qmakeevaluator.cpp +++ b/src/linguist/shared/qmakeevaluator.cpp @@ -44,6 +44,7 @@ #include "qmakeglobals.h" #include "qmakeparser.h" +#include "qmakevfs.h" #include "ioutils.h" #include @@ -174,13 +175,13 @@ const ProKey &QMakeEvaluator::map(const ProKey &var) } -QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, - QMakeParser *parser, QMakeHandler *handler) +QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs, + QMakeHandler *handler) : #ifdef PROEVALUATOR_DEBUG m_debugLevel(option->debugLevel), #endif - m_option(option), m_parser(parser), m_handler(handler) + m_option(option), m_parser(parser), m_handler(handler), m_vfs(vfs) { // So that single-threaded apps don't have to call initialize() for now. initStatics(); @@ -1066,7 +1067,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) superdir = m_outputDir; forever { QString superfile = superdir + QLatin1String("/.qmake.super"); - if (IoUtils::exists(superfile)) { + if (m_vfs->exists(superfile)) { m_superfile = QDir::cleanPath(superfile); break; } @@ -1081,10 +1082,10 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) QString dir = m_outputDir; forever { conffile = sdir + QLatin1String("/.qmake.conf"); - if (!IoUtils::exists(conffile)) + if (!m_vfs->exists(conffile)) conffile.clear(); cachefile = dir + QLatin1String("/.qmake.cache"); - if (!IoUtils::exists(cachefile)) + if (!m_vfs->exists(cachefile)) cachefile.clear(); if (!conffile.isEmpty() || !cachefile.isEmpty()) { if (dir != sdir) @@ -1175,7 +1176,7 @@ bool QMakeEvaluator::loadSpec() m_hostBuild ? m_option->qmakespec : m_option->xqmakespec); { - QMakeEvaluator evaluator(m_option, m_parser, m_handler); + QMakeEvaluator evaluator(m_option, m_parser, m_vfs, m_handler); if (!m_superfile.isEmpty()) { valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile); if (evaluator.evaluateFile( @@ -1332,7 +1333,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile( locker.unlock(); #endif - QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_handler); + QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_vfs, m_handler); baseEnv->evaluator = baseEval; baseEval->m_superfile = m_superfile; baseEval->m_conffile = m_conffile; @@ -1910,7 +1911,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile( QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileInto( const QString &fileName, ProValueMap *values, LoadFlags flags) { - QMakeEvaluator visitor(m_option, m_parser, m_handler); + QMakeEvaluator visitor(m_option, m_parser, m_vfs, m_handler); visitor.m_caller = this; visitor.m_outputDir = m_outputDir; visitor.m_featureRoots = m_featureRoots; diff --git a/src/linguist/shared/qmakeevaluator.h b/src/linguist/shared/qmakeevaluator.h index 21f487a..f4e65e3 100644 --- a/src/linguist/shared/qmakeevaluator.h +++ b/src/linguist/shared/qmakeevaluator.h @@ -108,7 +108,7 @@ public: static void initStatics(); static void initFunctionStatics(); - QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, + QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs, QMakeHandler *handler); ~QMakeEvaluator(); @@ -294,6 +294,7 @@ public: QMakeGlobals *m_option; QMakeParser *m_parser; QMakeHandler *m_handler; + QMakeVfs *m_vfs; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags) diff --git a/src/linguist/shared/qmakeparser.cpp b/src/linguist/shared/qmakeparser.cpp index c61375b..34e99a8 100644 --- a/src/linguist/shared/qmakeparser.cpp +++ b/src/linguist/shared/qmakeparser.cpp @@ -41,6 +41,7 @@ #include "qmakeparser.h" +#include "qmakevfs.h" #include "ioutils.h" using namespace QMakeInternal; @@ -142,9 +143,10 @@ void QMakeParser::initialize() statics.strLITERAL_WHITESPACE = QLatin1String("LITERAL_WHITESPACE"); } -QMakeParser::QMakeParser(ProFileCache *cache, QMakeParserHandler *handler) +QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler *handler) : m_cache(cache) , m_handler(handler) + , m_vfs(vfs) { // So that single-threaded apps don't have to call initialize() for now. initialize(); @@ -230,24 +232,14 @@ void QMakeParser::discardFileFromCache(const QString &fileName) bool QMakeParser::read(ProFile *pro, ParseFlags flags) { - QFile file(pro->fileName()); - if (!file.open(QIODevice::ReadOnly)) { - if (m_handler && ((flags & ParseReportMissing) || IoUtils::exists(pro->fileName()))) + QString content; + QString errStr; + if (!m_vfs->readFile(pro->fileName(), &content, &errStr)) { + if (m_handler && ((flags & ParseReportMissing) || m_vfs->exists(pro->fileName()))) m_handler->message(QMakeParserHandler::ParserIoError, - fL1S("Cannot read %1: %2").arg(pro->fileName(), file.errorString())); + fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr)); return false; } - - QByteArray bcont = file.readAll(); - if (bcont.startsWith("\xef\xbb\xbf")) { - // UTF-8 BOM will cause subtle errors - m_handler->message(QMakeParserHandler::ParserIoError, - fL1S("Unexpected UTF-8 BOM in %1").arg(pro->fileName())); - return false; - } - QString content(QString::fromLocal8Bit(bcont)); - bcont.clear(); - file.close(); return read(pro, content, 1, FullGrammar); } diff --git a/src/linguist/shared/qmakeparser.h b/src/linguist/shared/qmakeparser.h index e1dd090..dd55659 100644 --- a/src/linguist/shared/qmakeparser.h +++ b/src/linguist/shared/qmakeparser.h @@ -79,6 +79,7 @@ public: }; class ProFileCache; +class QMakeVfs; class QMAKE_EXPORT QMakeParser { @@ -93,7 +94,7 @@ public: }; Q_DECLARE_FLAGS(ParseFlags, ParseFlag) - QMakeParser(ProFileCache *cache, QMakeParserHandler *handler); + QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler *handler); enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; // fileName is expected to be absolute and cleanPath()ed. @@ -182,6 +183,7 @@ private: ProFileCache *m_cache; QMakeParserHandler *m_handler; + QMakeVfs *m_vfs; // This doesn't help gcc 3.3 ... template friend class QTypeInfo; diff --git a/src/linguist/shared/qmakevfs.cpp b/src/linguist/shared/qmakevfs.cpp new file mode 100644 index 0000000..cfa5f29 --- /dev/null +++ b/src/linguist/shared/qmakevfs.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmakevfs.h" + +#include "ioutils.h" +using namespace QMakeInternal; + +#include +#include +#include + +#define fL1S(s) QString::fromLatin1(s) + +QT_BEGIN_NAMESPACE + +QMakeVfs::QMakeVfs() +#ifndef PROEVALUATOR_FULL + : m_magicMissing(fL1S("missing")) + , m_magicExisting(fL1S("existing")) +#endif +{ +} + +bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents, + QString *errStr) +{ +#ifndef PROEVALUATOR_FULL +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + QString *cont = &m_files[fn]; + if (mode & QIODevice::Append) + *cont += contents; + else + *cont = contents; + Q_UNUSED(errStr) + return true; +#else + QFileInfo qfi(fn); + if (!QDir::current().mkpath(qfi.path())) { + *errStr = fL1S("Cannot create parent directory"); + return false; + } + QByteArray bytes = contents.toLocal8Bit(); + QFile cfile(fn); + if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) { + if (cfile.readAll() == bytes) + return true; + cfile.close(); + } + if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) { + *errStr = cfile.errorString(); + return false; + } + cfile.write(bytes); + cfile.close(); + if (cfile.error() != QFile::NoError) { + *errStr = cfile.errorString(); + return false; + } + return true; +#endif +} + +bool QMakeVfs::readFile(const QString &fn, QString *contents, QString *errStr) +{ +#ifndef PROEVALUATOR_FULL +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + QHash::ConstIterator it = m_files.constFind(fn); + if (it != m_files.constEnd()) { + if (it->constData() == m_magicMissing.constData()) { + *errStr = fL1S("No such file or directory"); + return false; + } + if (it->constData() != m_magicExisting.constData()) { + *contents = *it; + return true; + } + } +#endif + + QFile file(fn); + if (!file.open(QIODevice::ReadOnly)) { +#ifndef PROEVALUATOR_FULL + if (!IoUtils::exists(fn)) { + m_files[fn] = m_magicMissing; + *errStr = fL1S("No such file or directory"); + } else +#endif + *errStr = file.errorString(); + return false; + } +#ifndef PROEVALUATOR_FULL + m_files[fn] = m_magicExisting; +#endif + + QByteArray bcont = file.readAll(); + if (bcont.startsWith("\xef\xbb\xbf")) { + // UTF-8 BOM will cause subtle errors + *errStr = fL1S("Unexpected UTF-8 BOM"); + return false; + } + *contents = QString::fromLocal8Bit(bcont); + return true; +} + +bool QMakeVfs::exists(const QString &fn) +{ +#ifndef PROEVALUATOR_FULL +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + QHash::ConstIterator it = m_files.constFind(fn); + if (it != m_files.constEnd()) + return it->constData() != m_magicMissing.constData(); +#endif + bool ex = IoUtils::exists(fn); +#ifndef PROEVALUATOR_FULL + m_files[fn] = ex ? m_magicExisting : m_magicMissing; +#endif + return ex; +} + +#ifndef PROEVALUATOR_FULL +// This should be called when the sources may have changed (e.g., VCS update). +void QMakeVfs::invalidateCache() +{ +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + QHash::Iterator it = m_files.begin(), eit = m_files.end(); + while (it != eit) { + if (it->constData() == m_magicMissing.constData() + ||it->constData() == m_magicExisting.constData()) + it = m_files.erase(it); + else + ++it; + } +} + +// This should be called when generated files may have changed (e.g., actual build). +void QMakeVfs::invalidateContents() +{ +# ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&m_mutex); +# endif + m_files.clear(); +} +#endif + +QT_END_NAMESPACE diff --git a/src/linguist/shared/qmakevfs.h b/src/linguist/shared/qmakevfs.h new file mode 100644 index 0000000..c5e77ed --- /dev/null +++ b/src/linguist/shared/qmakevfs.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMAKEVFS_H +#define QMAKEVFS_H + +#include "qmake_global.h" + +# include +#ifndef PROEVALUATOR_FULL +# include +# include +# ifdef PROEVALUATOR_THREAD_SAFE +# include +# endif +#endif + +QT_BEGIN_NAMESPACE + +class QMAKE_EXPORT QMakeVfs +{ +public: + QMakeVfs(); + + bool writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents, QString *errStr); + bool readFile(const QString &fn, QString *contents, QString *errStr); + bool exists(const QString &fn); + +#ifndef PROEVALUATOR_FULL + void invalidateCache(); + void invalidateContents(); +#endif + +private: +#ifndef PROEVALUATOR_FULL +# ifdef PROEVALUATOR_THREAD_SAFE + QMutex m_mutex; +# endif + QHash m_files; + QString m_magicMissing; + QString m_magicExisting; +#endif +}; + +QT_END_NAMESPACE + +#endif // QMAKEVFS_H -- 2.7.4