File indexing completed on 2024-09-15 04:12:30
0001 /* 0002 SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "qmakefile.h" 0008 0009 #include <QDir> 0010 #include <QFileInfo> 0011 0012 #include <debug.h> 0013 #include "parser/ast.h" 0014 #include "qmakedriver.h" 0015 0016 #define ifDebug(x) 0017 0018 //@TODO: Make the globbing stuff work with drives on win32 0019 0020 void resolveShellGlobbingInternal(QStringList& entries, const QStringList& segments, const QFileInfo& match, QDir& dir, 0021 int offset); 0022 0023 QStringList resolveShellGlobbingInternal(const QStringList& segments, QDir& dir, int offset = 0) 0024 { 0025 if (offset >= segments.size()) { 0026 return QStringList(); 0027 } 0028 0029 const QString& pathPattern = segments.at(offset); 0030 0031 QStringList entries; 0032 if (pathPattern.contains(QLatin1Char('*')) || 0033 pathPattern.contains(QLatin1Char('?')) || 0034 pathPattern.contains(QLatin1Char('['))) { 0035 // pattern contains globbing chars 0036 const auto dirEntries = 0037 dir.entryInfoList(QStringList() << pathPattern, QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Unsorted); 0038 for (const auto& match : dirEntries) { 0039 resolveShellGlobbingInternal(entries, segments, match, dir, offset); 0040 } 0041 } else { 0042 // pattern is "simple" hence be fast, but make sure the file exists 0043 QFileInfo info(dir.filePath(pathPattern)); 0044 if (info.exists()) { 0045 resolveShellGlobbingInternal(entries, segments, info, dir, offset); 0046 } 0047 } 0048 0049 return entries; 0050 } 0051 0052 void resolveShellGlobbingInternal(QStringList& entries, const QStringList& segments, const QFileInfo& match, QDir& dir, 0053 int offset) 0054 { 0055 if (match.isDir() && offset + 1 < segments.size()) { 0056 dir.cd(match.fileName()); 0057 entries += resolveShellGlobbingInternal(segments, dir, offset + 1); 0058 dir.cdUp(); 0059 } else { 0060 entries << match.canonicalFilePath(); 0061 } 0062 } 0063 0064 QStringList resolveShellGlobbingInternal(const QString& pattern, const QString& dir) 0065 { 0066 if (pattern.isEmpty()) { 0067 return QStringList(); 0068 } 0069 0070 QDir dir_(pattern.startsWith(QLatin1Char('/')) ? QStringLiteral("/") : dir); 0071 0072 // break up pattern into path segments 0073 return resolveShellGlobbingInternal(pattern.split(QLatin1Char('/'), Qt::SkipEmptyParts), dir_); 0074 } 0075 0076 QMakeFile::QMakeFile(QString file) 0077 : m_ast(nullptr) 0078 , m_projectFile(std::move(file)) 0079 , m_project(nullptr) 0080 { 0081 Q_ASSERT(!m_projectFile.isEmpty()); 0082 } 0083 0084 bool QMakeFile::read() 0085 { 0086 Q_ASSERT(!m_projectFile.isEmpty()); 0087 QFileInfo fi(m_projectFile); 0088 ifDebug(qCDebug(KDEV_QMAKE) << "Is" << m_projectFile << "a dir?" << fi.isDir();) if (fi.isDir()) 0089 { 0090 QDir dir(m_projectFile); 0091 QStringList l = dir.entryList(QStringList() << QStringLiteral("*.pro")); 0092 0093 QString projectfile; 0094 0095 if (!l.count() || (l.count() && l.indexOf(fi.baseName() + QLatin1String(".pro")) != -1)) { 0096 projectfile = fi.baseName() + QLatin1String(".pro"); 0097 } else { 0098 projectfile = l.first(); 0099 } 0100 m_projectFile += QLatin1Char('/') + projectfile; 0101 } 0102 QMake::Driver d; 0103 d.readFile(m_projectFile); 0104 0105 if (!d.parse(&m_ast)) { 0106 qCWarning(KDEV_QMAKE) << "Couldn't parse project:" << m_projectFile; 0107 delete m_ast; 0108 m_ast = nullptr; 0109 m_projectFile = QString(); 0110 return false; 0111 } else { 0112 ifDebug(qCDebug(KDEV_QMAKE) << "found ast:" << m_ast->statements.count();) QMakeFileVisitor visitor(this, this); 0113 /// TODO: cleanup, re-use m_variableValues directly in the visitor 0114 visitor.setVariables(m_variableValues); 0115 m_variableValues = visitor.visitFile(m_ast); 0116 ifDebug(qCDebug(KDEV_QMAKE) << "Variables found:" << m_variableValues;) 0117 } 0118 return true; 0119 } 0120 0121 QMakeFile::~QMakeFile() 0122 { 0123 delete m_ast; 0124 m_ast = nullptr; 0125 } 0126 0127 QString QMakeFile::absoluteDir() const 0128 { 0129 return QFileInfo(m_projectFile).absoluteDir().canonicalPath(); 0130 } 0131 0132 QString QMakeFile::absoluteFile() const 0133 { 0134 return m_projectFile; 0135 } 0136 0137 QMake::ProjectAST* QMakeFile::ast() const 0138 { 0139 return m_ast; 0140 } 0141 0142 QStringList QMakeFile::variables() const 0143 { 0144 return m_variableValues.keys(); 0145 } 0146 0147 QStringList QMakeFile::variableValues(const QString& variable) const 0148 { 0149 return m_variableValues.value(variable, QStringList()); 0150 } 0151 0152 bool QMakeFile::containsVariable(const QString& variable) const 0153 { 0154 return m_variableValues.contains(variable); 0155 } 0156 0157 QMakeFile::VariableMap QMakeFile::variableMap() const 0158 { 0159 return m_variableValues; 0160 } 0161 0162 QStringList QMakeFile::resolveVariable(const QString& variable, VariableInfo::VariableType type) const 0163 { 0164 if (type == VariableInfo::QMakeVariable) { 0165 const auto variableValueIt = m_variableValues.find(variable); 0166 if (variableValueIt != m_variableValues.end()) { 0167 return *variableValueIt; 0168 } 0169 } 0170 0171 qCWarning(KDEV_QMAKE) << "unresolved variable:" << variable << "type:" << type; 0172 return QStringList(); 0173 } 0174 0175 QStringList QMakeFile::resolveShellGlobbing(const QString& pattern, const QString& base) const 0176 { 0177 return resolveShellGlobbingInternal(pattern, base.isEmpty() ? absoluteDir() : base); 0178 } 0179 0180 QString QMakeFile::resolveToSingleFileName(const QString& file, const QString& base) const 0181 { 0182 QStringList l = resolveFileName(file, base); 0183 if (l.isEmpty()) 0184 return QString(); 0185 else 0186 return l.first(); 0187 } 0188 0189 QStringList QMakeFile::resolveFileName(const QString& file, const QString& base) const 0190 { 0191 return resolveShellGlobbing(file, base); 0192 } 0193 0194 void QMakeFile::setProject(KDevelop::IProject* project) 0195 { 0196 m_project = project; 0197 } 0198 0199 KDevelop::IProject* QMakeFile::project() const 0200 { 0201 return m_project; 0202 }