Commit 43f75f38 authored by dt's avatar dt
Browse files

Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline

parents 2ce90697 4deb3668
......@@ -199,7 +199,7 @@ HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0
HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \
"<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \
"<td width=\"30%\" align=\"left\">Copyright &copy; 2008 Nokia</td>\n" \
"<td width=\"30%\" align=\"left\">Copyright &copy; 2009 Nokia</td>\n" \
"<td width=\"40%\" align=\"center\">&nbsp;</td>\n" \
"<td width=\"30%\" align=\"right\"><div align=\"right\">Qt Creator 1.0.0</div></td>\n" \
"</tr></table></div></address>"
......@@ -694,8 +694,6 @@ void Preprocessor::preprocess(const QByteArray &fileName, const QByteArray &sour
_result->append("\\\n");
else if (_dot->whitespace) {
TokenIterator begin = _tokens.constBegin();
const unsigned endOfPreviousToken = (_dot - 1)->end();
const unsigned beginOfToken = _dot->begin();
......@@ -728,122 +726,145 @@ void Preprocessor::preprocess(const QByteArray &fileName, const QByteArray &sour
const QByteArray spell = tokenSpell(*identifierToken);
if (env->isBuiltinMacro(spell)) {
const Macro trivial;
if (env->isBuiltinMacro(spell))
expandBuiltinMacro(identifierToken, spell);
if (client)
client->startExpandingMacro(identifierToken->offset,
trivial, spell);
else {
if (Macro *m = env->resolve(spell)) {
if (! m->isFunctionLike()) {
if (0 == (m = processObjectLikeMacro(identifierToken, spell, m)))
continue;
expand(spell, _result);
// the macro expansion generated something that looks like
// a function-like macro.
}
if (client)
client->stopExpandingMacro(_dot->offset, trivial);
// `m' is function-like macro.
if (_dot->is(T_LPAREN)) {
skipActualArguments();
continue;
if (_dot->is(T_RPAREN)) {
expandFunctionLikeMacro(identifierToken, m);
continue;
}
}
}
// it's not a function or object-like macro.
_result->append(spell);
}
}
}
}
Macro *m = env->resolve(spell);
popState();
if (! m)
_result->append(spell);
env->currentFile = previousFileName;
env->currentLine = previousCurrentLine;
_result = previousResult;
}
else {
if (! m->isFunctionLike()) {
void Preprocessor::skipActualArguments()
{
int count = 0;
if (client)
client->startExpandingMacro(identifierToken->offset,
*m, spell);
while (_dot->isNot(T_EOF_SYMBOL)) {
if (_dot->is(T_LPAREN))
++count;
m->setHidden(true);
const QByteArray tmp = expand(m->definition());
m->setHidden(false);
else if (_dot->is(T_RPAREN)) {
if (! --count)
break;
}
if (client)
client->stopExpandingMacro(_dot->offset, *m);
++_dot;
}
}
Macro *Preprocessor::processObjectLikeMacro(TokenIterator identifierToken,
const QByteArray &spell,
Macro *m)
{
QByteArray tmp;
expandObjectLikeMacro(identifierToken, spell, m, &tmp);
if (_dot->isNot(T_LPAREN)) {
_result->append(tmp);
continue;
if (_dot->is(T_LPAREN)) {
// check if the expension generated a function-like macro.
} else {
m = 0; // reset the active the macro
m = 0; // reset the active the macro
pushState(createStateFromSource(tmp));
pushState(createStateFromSource(tmp));
if (_dot->is(T_IDENTIFIER)) {
const QByteArray id = tokenSpell(*_dot);
if (_dot->is(T_IDENTIFIER)) {
const QByteArray id = tokenSpell(*_dot);
if (Macro *macro = env->resolve(id)) {
if (macro->isFunctionLike())
m = macro;
}
}
if (Macro *macro = env->resolve(id)) {
if (macro->isFunctionLike())
m = macro;
}
}
popState();
popState();
if (! m) {
_result->append(tmp);
continue;
}
}
}
if (m != 0)
return m;
}
// `m' is function-like macro.
_result->append(tmp);
return 0;
}
// collect the actual arguments
if (_dot->isNot(T_LPAREN)) {
// ### warnng expected T_LPAREN
_result->append(m->name());
continue;
}
void Preprocessor::expandBuiltinMacro(TokenIterator identifierToken,
const QByteArray &spell)
{
const Macro trivial;
int count = 0;
while (_dot->isNot(T_EOF_SYMBOL)) {
if (_dot->is(T_LPAREN))
++count;
if (client)
client->startExpandingMacro(identifierToken->offset,
trivial, spell);
else if (_dot->is(T_RPAREN)) {
if (! --count)
break;
}
expand(spell, _result);
++_dot;
}
if (client)
client->stopExpandingMacro(_dot->offset, trivial);
}
if (_dot->isNot(T_RPAREN)) {
// ### warning expected T_RPAREN
void Preprocessor::expandObjectLikeMacro(TokenIterator identifierToken,
const QByteArray &spell,
Macro *m,
QByteArray *result)
{
if (client)
client->startExpandingMacro(identifierToken->offset,
*m, spell);
} else {
const char *beginOfText = startOfToken(*identifierToken);
const char *endOfText = endOfToken(*_dot);
++_dot; // skip T_RPAREN
m->setHidden(true);
expand(m->definition(), result);
m->setHidden(false);
if (client) {
const QByteArray text =
QByteArray::fromRawData(beginOfText,
endOfText - beginOfText);
if (client)
client->stopExpandingMacro(_dot->offset, *m);
}
client->startExpandingMacro(identifierToken->offset,
*m, text);
}
void Preprocessor::expandFunctionLikeMacro(TokenIterator identifierToken, Macro *m)
{
const char *beginOfText = startOfToken(*identifierToken);
const char *endOfText = endOfToken(*_dot);
++_dot; // skip T_RPAREN
expand(beginOfText, endOfText, _result);
if (client) {
const QByteArray text =
QByteArray::fromRawData(beginOfText,
endOfText - beginOfText);
if (client)
client->stopExpandingMacro(_dot->offset, *m);
}
}
}
}
client->startExpandingMacro(identifierToken->offset,
*m, text);
}
popState();
expand(beginOfText, endOfText, _result);
env->currentFile = previousFileName;
env->currentLine = previousCurrentLine;
_result = previousResult;
if (client)
client->stopExpandingMacro(_dot->offset, *m);
}
const char *Preprocessor::startOfToken(const Token &token) const
......
......@@ -104,6 +104,12 @@ private:
QByteArray expand(const QByteArray &source);
void expand(const QByteArray &source, QByteArray *result);
void expand(const char *first, const char *last, QByteArray *result);
void expandBuiltinMacro(TokenIterator identifierToken,
const QByteArray &spell);
void expandObjectLikeMacro(TokenIterator identifierToken,
const QByteArray &spell,
Macro *m, QByteArray *result);
void expandFunctionLikeMacro(TokenIterator identifierToken, Macro *m);
void resetIfLevel();
bool testIfLevel();
......@@ -123,10 +129,17 @@ private:
QByteArray tokenSpell(const CPlusPlus::Token &token) const;
QByteArray tokenText(const CPlusPlus::Token &token) const; // does a deep copy
void skipActualArguments();
void processNewline();
void processSkippingBlocks(bool skippingBlocks,
TokenIterator dot, TokenIterator lastToken);
Macro *processObjectLikeMacro(TokenIterator identifierToken,
const QByteArray &spell,
Macro *m);
void processDirective(TokenIterator dot, TokenIterator lastToken);
void processInclude(bool skipCurrentPath,
TokenIterator dot, TokenIterator lastToken,
......
......@@ -59,6 +59,16 @@ public:
//signals:
virtual void processError(const QString &error) = 0;
#ifdef Q_WS_WIN
// Add PATH and SystemRoot environment variables in case they are missing
static QStringList fixWinEnvironment(const QStringList &env);
// Quote a Windows command line correctly for the "CreateProcess" API
static QString createWinCommandline(const QString &program, const QStringList &args);
// Create a bytearray suitable to be passed on as environment
// to the "CreateProcess" API (0-terminated UTF 16 strings).
static QByteArray createWinEnvironment(const QStringList &env);
#endif
private:
QString m_workingDir;
QStringList m_environment;
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (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 qt-sales@nokia.com.
**
**************************************************************************/
#include "abstractprocess.h"
#include <windows.h>
namespace Core {
namespace Utils {
QStringList AbstractProcess::fixWinEnvironment(const QStringList &env)
{
QStringList envStrings = env;
// add PATH if necessary (for DLL loading)
if (envStrings.filter(QRegExp(QLatin1String("^PATH="),Qt::CaseInsensitive)).isEmpty()) {
QByteArray path = qgetenv("PATH");
if (!path.isEmpty())
envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path)));
}
// add systemroot if needed
if (envStrings.filter(QRegExp(QLatin1String("^SystemRoot="),Qt::CaseInsensitive)).isEmpty()) {
QByteArray systemRoot = qgetenv("SystemRoot");
if (!systemRoot.isEmpty())
envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot)));
}
return envStrings;
}
QString AbstractProcess::createWinCommandline(const QString &program, const QStringList &args)
{
const QChar doubleQuote = QLatin1Char('"');
const QChar blank = QLatin1Char(' ');
const QChar backSlash = QLatin1Char('\\');
QString programName = program;
if (!programName.startsWith(doubleQuote) && !programName.endsWith(doubleQuote) && programName.contains(blank)) {
programName.insert(0, doubleQuote);
programName.append(doubleQuote);
}
// add the prgram as the first arrg ... it works better
programName.replace(QLatin1Char('/'), backSlash);
QString cmdLine = programName;
if (args.empty())
return cmdLine;
cmdLine += blank;
for (int i = 0; i < args.size(); ++i) {
QString tmp = args.at(i);
// in the case of \" already being in the string the \ must also be escaped
tmp.replace(QLatin1String("\\\""), QLatin1String("\\\\\""));
// escape a single " because the arguments will be parsed
tmp.replace(QString(doubleQuote), QLatin1String("\\\""));
if (tmp.isEmpty() || tmp.contains(blank) || tmp.contains('\t')) {
// The argument must not end with a \ since this would be interpreted
// as escaping the quote -- rather put the \ behind the quote: e.g.
// rather use "foo"\ than "foo\"
QString endQuote(doubleQuote);
int i = tmp.length();
while (i > 0 && tmp.at(i - 1) == backSlash) {
--i;
endQuote += backSlash;
}
cmdLine += QLatin1String(" \"");
cmdLine += tmp.left(i);
cmdLine += endQuote;
} else {
cmdLine += blank;
cmdLine += tmp;
}
}
return cmdLine;
}
QByteArray AbstractProcess::createWinEnvironment(const QStringList &env)
{
QByteArray envlist;
int pos = 0;
foreach (const QString &tmp, env) {
const uint tmpSize = sizeof(TCHAR) * (tmp.length() + 1);
envlist.resize(envlist.size() + tmpSize);
memcpy(envlist.data() + pos, tmp.utf16(), tmpSize);
pos += tmpSize;
}
envlist.resize(envlist.size() + 2);
envlist[pos++] = 0;
envlist[pos++] = 0;
return envlist;
}
} //namespace Utils
} //namespace Core
......@@ -67,12 +67,6 @@ public:
int exitCode() const { return m_appCode; } // This will be the signal number if exitStatus == CrashExit
QProcess::ExitStatus exitStatus() const { return m_appStatus; }
#ifdef Q_OS_WIN
// These are public for WinGuiProcess. Should be in AbstractProcess, but it has no .cpp so far.
static QString createCommandline(const QString &program, const QStringList &args);
static QStringList fixEnvironment(const QStringList &env);
#endif
signals:
void processError(const QString &error);
// These reflect the state of the actual client process
......
......@@ -85,7 +85,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
QTextStream out(m_tempFile);
out.setCodec("UTF-16LE");
out.setGenerateByteOrderMark(false);
foreach (const QString &var, fixEnvironment(environment()))
foreach (const QString &var, fixWinEnvironment(environment()))
out << var << QChar(0);
out << QChar(0);
}
......@@ -106,10 +106,10 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
<< m_stubServer.fullServerName()
<< workDir
<< (m_tempFile ? m_tempFile->fileName() : 0)
<< createCommandline(program, args)
<< createWinCommandline(program, args)
<< tr("Press <RETURN> to close this window...");
QString cmdLine = createCommandline(
QString cmdLine = createWinCommandline(
QCoreApplication::applicationDirPath() + "/qtcreator_process_stub.exe", stubArgs);
bool success = CreateProcessW(0, (WCHAR*)cmdLine.utf16(),
......@@ -262,54 +262,3 @@ void ConsoleProcess::stubExited()
emit wrapperStopped();
}
QStringList ConsoleProcess::fixEnvironment(const QStringList &env)
{
QStringList envStrings = env;
// add PATH if necessary (for DLL loading)
if (envStrings.filter(QRegExp("^PATH=",Qt::CaseInsensitive)).isEmpty()) {
QByteArray path = qgetenv("PATH");
if (!path.isEmpty())
envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path)));
}
// add systemroot if needed
if (envStrings.filter(QRegExp("^SystemRoot=",Qt::CaseInsensitive)).isEmpty()) {
QByteArray systemRoot = qgetenv("SystemRoot");
if (!systemRoot.isEmpty())
envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot)));
}
return envStrings;
}
QString ConsoleProcess::createCommandline(const QString &program, const QStringList &args)
{
QString programName = program;
if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(" "))
programName = "\"" + programName + "\"";
programName.replace("/", "\\");
QString cmdLine;
// add the prgram as the first arrg ... it works better
cmdLine = programName + " ";
for (int i = 0; i < args.size(); ++i) {
QString tmp = args.at(i);
// in the case of \" already being in the string the \ must also be escaped
tmp.replace( "\\\"", "\\\\\"" );
// escape a single " because the arguments will be parsed
tmp.replace( "\"", "\\\"" );
if (tmp.isEmpty() || tmp.contains(' ') || tmp.contains('\t')) {
// The argument must not end with a \ since this would be interpreted
// as escaping the quote -- rather put the \ behind the quote: e.g.
// rather use "foo"\ than "foo\"
QString endQuote("\"");
int i = tmp.length();
while (i > 0 && tmp.at(i - 1) == '\\') {
--i;
endQuote += "\\";
}
cmdLine += QString(" \"") + tmp.left(i) + endQuote;
} else {
cmdLine += ' ' + tmp;
}
}
return cmdLine;
}
......@@ -27,7 +27,8 @@ SOURCES += \
synchronousprocess.cpp
win32 {
SOURCES += consoleprocess_win.cpp \
SOURCES += abstractprocess_win.cpp \
consoleprocess_win.cpp \
winutils.cpp
HEADERS += winutils.h
} else {
......
......@@ -612,6 +612,7 @@ void MainWindow::registerDefaultActions()
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDefaultText(tr("&Undo"));
medit->addAction(cmd, Constants::G_EDIT_UNDOREDO);
tmpaction->setEnabled(false);
// Redo Action
tmpaction = new QAction(QIcon(Constants::ICON_REDO), tr("&Redo"), this);
......@@ -620,36 +621,42 @@ void MainWindow::registerDefaultActions()
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDefaultText(tr("&Redo"));
medit->addAction(cmd, Constants::G_EDIT_UNDOREDO);
tmpaction->setEnabled(false);
// Cut Action
tmpaction = new QAction(QIcon(Constants::ICON_CUT), tr("Cu&t"), this);
cmd = am->registerAction(tmpaction, Constants::CUT, m_globalContext);
cmd->setDefaultKeySequence(QKeySequence::Cut);
medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
tmpaction->setEnabled(false);
// Copy Action
tmpaction = new QAction(QIcon(Constants::ICON_COPY), tr("&Copy"), this);
cmd = am->registerAction(tmpaction, Constants::COPY, m_globalContext);
cmd->setDefaultKeySequence(QKeySequence::Copy);
medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
tmpaction->setEnabled(false);
// Paste Action
tmpaction = new QAction(QIcon(Constants::ICON_PASTE), tr("&Paste"), this);
cmd = am->registerAction(tmpaction, Constants::PASTE, m_globalContext);
cmd->setDefaultKeySequence(QKeySequence::Paste);
medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
tmpaction->setEnabled(false);
// Select All
tmpaction = new QAction(tr("&Select All"), this);
cmd = am->registerAction(tmpaction, Constants::SELECTALL, m_globalContext);
cmd->setDefaultKeySequence(QKeySequence::SelectAll);
medit->addAction(cmd, Constants::G_EDIT_SELECTALL);
tmpaction->setEnabled(false);
// Goto Action
tmpaction = new QAction(tr("&Go To Line..."), this);
cmd = am->registerAction(tmpaction, Constants::GOTO, m_globalContext);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+L")));
medit->addAction(cmd, Constants::G_EDIT_OTHER);
tmpaction->setEnabled(false);
// Options Action
m_optionsAction = new QAction(tr("&Options..."), this);
......@@ -993,23 +1000,26 @@ void MainWindow::updateFocusWidget(QWidget *old, QWidget *now)
{
Q_UNUSED(old)
Q_UNUSED(now)
IContext *newContext = 0;
if (focusWidget()) {
IContext *context = 0;
QWidget *p = focusWidget();
while (p) {
context = m_contextWidgets.value(p);
if (context) {
if (m_activeContext != context)
updateContextObject(context);
newContext = context;
break;
}
p = p->parentWidget();
}
}
updateContextObject(newContext);
}
void MainWindow::updateContextObject(IContext *context)
{
if (context == m_activeContext)
return;
IContext *oldContext = m_activeContext;
m_activeContext = context;
if (!context || oldContext != m_activeContext) {
......@@ -1101,10 +1111,6 @@ void MainWindow::updateContext()
if (m_activeContext)