Files
qt-creator/src/shared/proparser/prowriter.cpp
Oswald Buddenhagen c63453d878 reorganize AST
turn else, for(), defineTest() and defineReplace() into own node
types instead of treating them as magic conditionals/functions.
on top of that, introduce a proper branching node type, so finding
the alternative code paths can be moved into the parser instead of
burdening the evaluator with it.
2010-06-02 11:05:26 +02:00

225 lines
9.3 KiB
C++

/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "proitems.h"
#include "prowriter.h"
#include <QtCore/QDir>
#include <QtCore/QPair>
using namespace Qt4ProjectManager::Internal;
void ProWriter::addFiles(ProFile *profile, QStringList *lines,
const QDir &proFileDir, const QStringList &filePaths,
const QString &var)
{
// Check if variable item exists as child of root item
for (ProItem *item = profile->items(); item; item = item->next()) {
if (item->kind() == ProItem::VariableKind) {
ProVariable *proVar = static_cast<ProVariable*>(item);
if (var == proVar->variable()
&& proVar->variableOperator() != ProVariable::RemoveOperator
&& proVar->variableOperator() != ProVariable::ReplaceOperator) {
int lineNo = proVar->lineNumber() - 1;
for (; lineNo < lines->count(); lineNo++) {
QString line = lines->at(lineNo);
int idx = line.indexOf(QLatin1Char('#'));
if (idx >= 0)
line.truncate(idx);
while (line.endsWith(QLatin1Char(' ')) || line.endsWith(QLatin1Char('\t')))
line.chop(1);
if (line.isEmpty()) {
if (idx >= 0)
continue;
break;
}
if (!line.endsWith(QLatin1Char('\\'))) {
(*lines)[lineNo].insert(line.length(), QLatin1String(" \\"));
lineNo++;
break;
}
}
QString added;
foreach (const QString &filePath, filePaths)
added += QLatin1String(" ") + proFileDir.relativeFilePath(filePath)
+ QLatin1String(" \\\n");
added.chop(3);
lines->insert(lineNo, added);
return;
}
}
}
// Create & append new variable item
QString added = QLatin1Char('\n') + var + QLatin1String(" +=");
foreach (const QString &filePath, filePaths)
added += QLatin1String(" \\\n ") + proFileDir.relativeFilePath(filePath);
*lines << added;
}
static void findProVariables(ProItem *item, const QStringList &vars,
QList<ProVariable *> *proVars)
{
for (; item; item = item->next()) {
if (item->kind() == ProItem::BranchKind) {
findProVariables(static_cast<ProBranch*>(item)->thenItems(), vars, proVars);
findProVariables(static_cast<ProBranch*>(item)->elseItems(), vars, proVars);
} else if (item->kind() == ProItem::VariableKind) {
ProVariable *proVar = static_cast<ProVariable*>(item);
if (vars.contains(proVar->variable()))
*proVars << proVar;
}
}
}
QStringList ProWriter::removeFiles(ProFile *profile, QStringList *lines,
const QDir &proFileDir, const QStringList &filePaths,
const QStringList &vars)
{
QStringList notChanged = filePaths;
QList<ProVariable *> proVars;
findProVariables(profile->items(), vars, &proVars);
// This is a tad stupid - basically, it can remove only entries which
// the above code added.
QStringList relativeFilePaths;
foreach (const QString &absoluteFilePath, filePaths)
relativeFilePaths << proFileDir.relativeFilePath(absoluteFilePath);
// This code expects proVars to be sorted by the variables' appearance in the file.
int delta = 1;
foreach (ProVariable *proVar, proVars) {
if (proVar->variableOperator() != ProVariable::RemoveOperator
&& proVar->variableOperator() != ProVariable::ReplaceOperator) {
bool first = true;
int lineNo = proVar->lineNumber() - delta;
typedef QPair<int, int> ContPos;
QList<ContPos> contPos;
while (lineNo < lines->count()) {
QString &line = (*lines)[lineNo];
int lineLen = line.length();
bool killed = false;
bool saved = false;
int idx = line.indexOf(QLatin1Char('#'));
if (idx >= 0)
lineLen = idx;
QChar *chars = line.data();
forever {
if (!lineLen) {
if (idx >= 0)
goto nextLine;
goto nextVar;
}
QChar c = chars[lineLen - 1];
if (c != QLatin1Char(' ') && c != QLatin1Char('\t'))
break;
lineLen--;
}
{
int contCol = -1;
if (chars[lineLen - 1] == QLatin1Char('\\'))
contCol = --lineLen;
int colNo = 0;
if (first) {
colNo = line.indexOf(QLatin1Char('=')) + 1;
first = false;
saved = true;
}
while (colNo < lineLen) {
QChar c = chars[colNo];
if (c == QLatin1Char(' ') || c == QLatin1Char('\t')) {
colNo++;
continue;
}
int varCol = colNo;
while (colNo < lineLen) {
QChar c = chars[colNo];
if (c == QLatin1Char(' ') || c == QLatin1Char('\t'))
break;
colNo++;
}
QString fn = line.mid(varCol, colNo - varCol);
if (relativeFilePaths.contains(fn)) {
notChanged.removeOne(QDir::cleanPath(proFileDir.absoluteFilePath(fn)));
if (colNo < lineLen)
colNo++;
else if (varCol)
varCol--;
int len = colNo - varCol;
colNo = varCol;
line.remove(varCol, len);
lineLen -= len;
contCol -= len;
idx -= len;
if (idx >= 0)
line.insert(idx, QLatin1String("# ") + fn + QLatin1Char(' '));
killed = true;
} else {
saved = true;
}
}
if (saved) {
// Entries remained
contPos.clear();
} else if (killed) {
// Entries existed, but were all removed
if (contCol < 0) {
// This is the last line, so clear continuations leading to it
foreach (const ContPos &pos, contPos) {
QString &bline = (*lines)[pos.first];
bline.remove(pos.second, 1);
if (pos.second == bline.length())
while (bline.endsWith(QLatin1Char(' '))
|| bline.endsWith(QLatin1Char('\t')))
bline.chop(1);
}
contPos.clear();
}
if (idx < 0) {
// Not even a comment stayed behind, so zap the line
lines->removeAt(lineNo);
delta++;
continue;
}
}
if (contCol >= 0)
contPos.append(qMakePair(lineNo, contCol));
}
nextLine:
lineNo++;
}
nextVar: ;
}
}
return notChanged;
}