Hi,

a consequence of the merging of the refactor branch is that all Q_WS_XX defines 
other than Q_WS_QPA are no longer defined on any platform.
Any code #ifdefed Q_WS_XX (or Q_OS_SYMBIAN) is now basically dead and should 
be carefully removed; only the code #ifdefed Q_WS_QPA should be left intact 
and no longer be enclosed in #if  (see for example qtbase: I2ac33765: Remove 
Q_WS_ and Q_OS_SYMBIAN which should appear soon after testing/integrating).

I will try to follow that through in qtbase/src and hopefully finally get rid 
of the need build with -qpa.

As for the other modules and the qtbase tests, I would like to ask the 
respective maintainers to step up (priority is entirely up to you, but I think 
any gain in code clarity and speed-up of the compiling/testing cycle 
due to reduced code size is worth the effort).

I am not touching the tests since there a few places where it is not entirely 
trivial; there is code like

#ifdef Q_WS_X11 
 sleep(10) // wait for X11 WM
#endif.

This needs to be done on a case by case base. There is currently no way to 
query the platform name/type from Qt. Should such a need arise, please talk to 
the Lighthouse experts on how best do this.

The process can be semi-automated by running the attached program (a 
bastardized version of a preprocesssor from Qt Creator), which takes file names 
on the command line. It handles some #ifdefs it knows and prompts you for the 
complicated cases  like

#if defined(Q_WS_WIN) && !defined(QT_NO_FREETYPE) || defined(Q_NO_PRINTER)

whether they evaluate to true/false or should be left intact.

Regards,
Friedemann
-- 
Friedemann Kleint
Nokia, Qt Development Frameworks
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-i...@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 <QtCore/QCoreApplication>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QScopedPointer>
#include <QtCore/QFile>
#include <QtCore/QStack>
#include <QtCore/QPair>
#include <QtCore/QRegExp>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QTemporaryFile>

#include <stdio.h>
#include <stdlib.h>
enum  { debug = 0 };

// Preprocessor: Conditional section
enum PreprocessorSection {
    IfSection,
    IfdefSection,
    IfndefSection,
    ElsifSection,
    ElseSection,
    EndifSection,
    OtherSection
};

// Preprocessor: Section stack containing nested '@if' sections
struct PreprocessStackEntry {
    PreprocessStackEntry(PreprocessorSection section = OtherSection,
                         bool parentEnabled = true,
                         bool condition = false,
                         bool anyIfClauseMatched = false,
                         bool wsExpression = false);

    PreprocessorSection section;
    bool parentEnabled;
    bool condition;
    bool anyIfClauseMatched;
    bool wsExpression;
};

PreprocessStackEntry::PreprocessStackEntry(PreprocessorSection s,
                                           bool p, bool c, bool a, bool w) :
    section(s), parentEnabled(p), condition(c), anyIfClauseMatched(a),wsExpression(w)
{
}

class PreprocessContext {
public:
    PreprocessContext();
    unsigned process(QIODevice &in, QIODevice &out, QIODevice *inputLog, QString *errorMessage);

private:
    void reset();
    PreprocessorSection preprocessorLine(const QString & in, QString *ifExpression) const;

    mutable QRegExp m_ifPattern;
    mutable QRegExp m_ifdefPattern;
    mutable QRegExp m_ifndefPattern;
    mutable QRegExp m_elsifPattern;
    const QRegExp m_elsePattern;
    const QRegExp m_endifPattern;

    QStack<PreprocessStackEntry> m_sectionStack;
};

PreprocessContext::PreprocessContext() :
    // Cut out expression for 'if/elsif '
    m_ifPattern(QLatin1String("^\\s*#\\s*if\\s+(.*)$")),
    m_ifdefPattern(QLatin1String("^\\s*#\\s*ifdef\\s+(.*)$")),
    m_ifndefPattern(QLatin1String("^\\s*#\\s*ifndef\\s+(.*)$")),
    m_elsifPattern(QLatin1String("^\\s*#\\s*elif\\s+(.*)$")),
    m_elsePattern(QLatin1String("^\\s*#\\s*else.*$")),
    m_endifPattern(QLatin1String("^\\s*#\\s*endif.*$"))
{
    Q_ASSERT(m_ifPattern.isValid() && m_ifdefPattern.isValid()
             && m_ifndefPattern.isValid() && m_elsifPattern.isValid()
             && m_elsePattern.isValid() && m_endifPattern.isValid());
}

void PreprocessContext::reset()
{
    m_sectionStack.clear();
    m_sectionStack.push(PreprocessStackEntry(OtherSection, true, true));
}

PreprocessorSection PreprocessContext::preprocessorLine(const QString &in,
                                                        QString *ifExpression) const
{
    if (m_ifPattern.exactMatch(in)) {
        *ifExpression = m_ifPattern.cap(1).trimmed();
        return IfSection;
    }
    if (m_ifdefPattern.exactMatch(in)) {
        *ifExpression = m_ifdefPattern.cap(1).trimmed();
        return IfdefSection;
    }
    if (m_ifndefPattern.exactMatch(in)) {
        *ifExpression = m_ifndefPattern.cap(1).trimmed();
        return IfndefSection;
    }

    if (m_elsifPattern.exactMatch(in)) {
        *ifExpression = m_elsifPattern.cap(1).trimmed();
        return ElsifSection;
    }

    ifExpression->clear();

    if (m_elsePattern.exactMatch(in))
        return ElseSection;
    if (m_endifPattern.exactMatch(in))
        return EndifSection;
    return OtherSection;
}

enum EvalResult {    
    EvalFalse,
    EvalTrue,
    EvalIrrelevant
};

static EvalResult evaluateExpressionI(PreprocessorSection ps,
                                      QIODevice *inputLog,
                                      const QString &expression)
{
    static  QSet<QString> otherWS;
    if (otherWS.isEmpty()) {
        otherWS.insert("Q_WS_X11");
        otherWS.insert("Q_WS_WIN");
        otherWS.insert("Q_WS_S60");
        otherWS.insert("Q_WS_QWS");
        otherWS.insert("Q_WS_MAC");
        otherWS.insert("Q_OS_SYMBIAN");
        otherWS.insert("Q_WS_WINCE");
        otherWS.insert("Q_WS_MAC64");
        otherWS.insert("Q_WS_MAC32");
    }
    if (!(expression.contains("Q_WS_") || expression.contains("Q_OS_SYMBIAN")))
        return EvalIrrelevant;
    switch (ps) {
    case IfdefSection:
    case IfndefSection:
        if (expression == "Q_WS_QPA")
            return ps == IfdefSection ? EvalTrue : EvalFalse;
        if (otherWS.contains(expression))
            return ps == IfdefSection ? EvalFalse : EvalTrue;
        break;
     case IfSection:
    case ElsifSection: {
        if (expression == "defined(Q_WS_QPA)" || expression == "defined(Q_WS_QWS) || defined(Q_WS_QPA)")
            return EvalTrue;
        if (expression == "!defined(Q_WS_QPA)")
            return EvalFalse;
        static QRegExp definedRE("defined *\\(*([^\\s())]+)\\)*");
        static QRegExp notDefinedRE("!defined *\\(*([^\\s())]+)\\)*");
        Q_ASSERT(definedRE.isValid() && notDefinedRE.isValid());
        if (definedRE.exactMatch(expression)) {
            if (definedRE.cap(1) == "Q_WS_QPA")
                return EvalTrue;
            if (otherWS.contains(definedRE.cap(1)))
                return EvalFalse;
        } else if (notDefinedRE.exactMatch(expression)) {
            if (definedRE.cap(1) == "Q_WS_QPA")
                return EvalFalse;
            if (otherWS.contains(notDefinedRE.cap(1)))
                return EvalTrue;
        }
    }
        break;

    default:
        break;
    }
    // Ask user to enter
    int er = -1;
    static QMap<QString, EvalResult > cache;
    if (cache.contains(expression))
        return cache.value(expression);

    while (true) {
        printf("\nPlease enter for expression '%s'\n"
               "0 : Evaluates to false\n"
               "1 : Evaluates to true\n"
               "2 : Irrelevant to the WS change, leave code as is\n",
               qPrintable(expression));
        int input = 0;
        do {
            input = getc(stdin);
        } while (input == '\n' || input == '\r');
        er = input - '0';
        if (er >= 0 &&  er <= EvalIrrelevant) {
            cache.insert(expression, (EvalResult)er);
            if (inputLog) {
                inputLog->putChar(char(er) + '0');
                inputLog->putChar('\n');
            }
            break;
        }
    }
    return (EvalResult)er;
}

static EvalResult evaluateExpression(PreprocessorSection ps, QIODevice *inputLog, const QString &expression)
{
    const EvalResult er = evaluateExpressionI(ps,inputLog, expression);
    printf("Using: %d for '%s' of type %d\n", er, qPrintable(expression), ps);
    return er;
}

unsigned PreprocessContext::process(QIODevice &in, QIODevice &out,
                                    QIODevice *inputLog,
                                    QString *errorMessage)
{

    unsigned removedLines = 0;
    reset();

    const QChar newLine = QLatin1Char('\n');

    while (true) {
        const QByteArray lineBA = in.readLine();
        if (lineBA.isEmpty())
            break;
        // Needs an element of the stack (be it dummy, else something is wrong).
        if (m_sectionStack.isEmpty()) {
            *errorMessage = "Empty stack";
            return false;
        }
        QString expression;
        bool expressionValue = false;
        bool printLine = true;

        QString line = QLatin1String(lineBA);
        const int nlPos = line.lastIndexOf(newLine);
        if (nlPos != -1)
            line.truncate(nlPos);
        const PreprocessorSection section = preprocessorLine(line, &expression);
        PreprocessStackEntry &top = m_sectionStack.back();
        switch (section) {
        case IfSection:
        case IfdefSection:
        case IfndefSection: {
            EvalResult er = EvalIrrelevant; // evaluateExpression(section ,expression);
            bool parentEnabled = top.parentEnabled && top.condition;
            if (parentEnabled) {
                er = evaluateExpression(section, inputLog, expression);
                expressionValue = er == EvalIrrelevant || er == EvalTrue;
            }
            if (debug)
                qDebug() << "IF t=" << section << "ex=" << expression << "er=" << er << "v=" << expressionValue;
            printLine = parentEnabled && er == EvalIrrelevant;
            PreprocessStackEntry pe(section, parentEnabled, expressionValue, expressionValue, er != EvalIrrelevant);
            m_sectionStack.push(pe);
        }
            break;
        case ElsifSection:
            top.section = ElsifSection;
            // ignore consecutive '@elsifs' once something matched
            if (top.parentEnabled) {
                if (top.wsExpression) {
                    printLine = false;
                    if (top.anyIfClauseMatched) {
                        top.condition = false;
                    } else {
                        EvalResult er = evaluateExpression(section, inputLog, expression);
                        top.condition = er == EvalIrrelevant || er == EvalTrue;
                        if (top.condition)
                            top.anyIfClauseMatched = true;
                    }
                }
            } else {
                printLine = false;
            }
            break;
        case ElseSection:
            if (top.parentEnabled) {
                if (top.wsExpression) {
                    top.condition = !top.anyIfClauseMatched;
                    printLine = false;
                }
            } else {
                printLine = false;
            }
            top.section = ElseSection;
            if (debug)
                qDebug() << "ELSE tope=" << top.parentEnabled << "v=" << expressionValue << "ws=" << top.wsExpression
                            << "any if=" << top.anyIfClauseMatched;
            break;
        case EndifSection:
            if (top.wsExpression || !top.parentEnabled)
                printLine = false;
            m_sectionStack.pop();
            break;
        case OtherSection: // Rest: Append according to current condition.
            printLine = top.condition;
            break;
        } // switch section
        if (printLine) {
            out.write(lineBA);
        } else {
            removedLines++;
        }
    } // for lines
    return removedLines;
}

int processFiles(const QStringList &files, QFile *inputLog = 0)
{
    PreprocessContext ctx;
    QString errorMessage;

    foreach (const QString &file, files) {
        if (file.isEmpty()) {
            qWarning("Empty file specified");
            continue;
        }

        printf("#### Processing: '%s'\n", qPrintable(file));
        QFile inFile(file);
        if (!inFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
            qWarning("Cannot open %s:  %s", qPrintable(file), qPrintable(inFile.errorString()));
            continue;
        }
        QTemporaryFile outFile;
        if (!outFile.open()) {
            qWarning("Cannot open %s:  %s", qPrintable(outFile.fileName()), qPrintable(outFile.errorString()));
            return -2;
        }
        if (const unsigned removedLines = ctx.process(inFile, outFile, inputLog, &errorMessage)) {
            printf("#### %u modifications in '%s'\n", removedLines, qPrintable(file));
        } else {
            printf("#### '%s' not modified\n", qPrintable(file));
            continue;
        }
        inFile.close();
        outFile.close();
        if (!inFile.remove()) {
            qWarning("Cannot remove %s: %s", qPrintable(file), qPrintable(inFile.errorString()));
            continue;
        }
        if (!QFile::copy(outFile.fileName(), file)) {
            qWarning("Cannot copy %s to %s",
                     qPrintable(outFile.fileName()),
                     qPrintable(file));
            continue;
        }
        if (!outFile.remove()) {
            qWarning("Cannot remove %s %s", qPrintable(outFile.fileName()), qPrintable(outFile.errorString()));
        }
    }
    return 0;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    if (argc < 2)
        return -1;
    QStringList arguments = a.arguments();
    arguments.pop_front();

    QScopedPointer<QFile> inputLog;
    if (arguments.size() >= 2 && arguments.at(0) == "-l") {
        inputLog.reset(new QFile(arguments.at(1)));
        if (!inputLog->open(QIODevice::WriteOnly|QIODevice::Text)) {
            qWarning("Cannot open %s:  %s",
                     qPrintable(inputLog->fileName()),
                     qPrintable(inputLog->errorString()));
            return -1;
        }
        printf("Logging to %s\n", qPrintable(inputLog->fileName()));
        arguments.pop_front();
        arguments.pop_front();
    }
    // List of files with -f
    QStringList files;    
    if (arguments.size() == 2 && arguments.at(0) == "-f") {
        QFile filesListFile(arguments.at(1));
        if (!filesListFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
            qWarning("Cannot open %s:  %s",
                     qPrintable(filesListFile.fileName()),
                     qPrintable(filesListFile.errorString()));
            return -1;
        }
        while (true) {
            const QByteArray fNameBA = filesListFile.readLine();
            const QString fName = QString::fromLocal8Bit(fNameBA).trimmed();
            if (fName.isEmpty())
                break;
            files.push_back(fName);
        }
        printf("%d files from %s\n", files.size(), qPrintable(filesListFile.fileName()));
    } else {
        files = arguments;
    }
    return processFiles(files, inputLog.data());
}

_______________________________________________
Qt5-feedback mailing list
Qt5-feedback@qt.nokia.com
http://lists.qt.nokia.com/mailman/listinfo/qt5-feedback

Reply via email to