diff --git a/util/glgen/glgen.pro b/util/glgen/glgen.pro index 9208ba9e8e63e4f5cba285659c01761c6a09d204..11018e942d4162ee5cf4ec85181bd6266d4c0156 100644 --- a/util/glgen/glgen.pro +++ b/util/glgen/glgen.pro @@ -9,11 +9,14 @@ TEMPLATE = app TARGET = glgen SOURCES += main.cpp \ - specparser.cpp \ + xmlspecparser.cpp \ + legacyspecparser.cpp \ codegenerator.cpp HEADERS += \ specparser.h \ + xmlspecparser.h \ + legacyspecparser.h \ codegenerator.h OTHER_FILES += \ diff --git a/util/glgen/specparser.cpp b/util/glgen/legacyspecparser.cpp similarity index 88% rename from util/glgen/specparser.cpp rename to util/glgen/legacyspecparser.cpp index 91a906bca9c09fcb558feeea20f32a82fd6d8512..84dcd0b2001369f2380f06d3cee4f4913bf9ccf2 100644 --- a/util/glgen/specparser.cpp +++ b/util/glgen/legacyspecparser.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "specparser.h" +#include "legacyspecparser.h" #include <QDebug> #include <QFile> @@ -48,39 +48,36 @@ #include <QTextStream> #ifdef SPECPARSER_DEBUG -#define qSpecParserDebug qDebug +#define qLegacySpecParserDebug qDebug #else -#define qSpecParserDebug QT_NO_QDEBUG_MACRO +#define qLegacySpecParserDebug QT_NO_QDEBUG_MACRO #endif -SpecParser::SpecParser() -{ -} - -void SpecParser::parse() +bool LegacySpecParser::parse() { // Get the mapping form generic types to specific types suitable for use in C-headers if (!parseTypeMap()) - return; + return false; // Open up a stream on the actual OpenGL function spec file - QFile file(m_specFileName); + QFile file(specFileName()); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning() << "Failed to open spec file:" << m_specFileName << "Aborting"; - return; + qWarning() << "Failed to open spec file:" << specFileName() << "Aborting"; + return false; } QTextStream stream(&file); // Extract the info that we need parseFunctions(stream); + return true; } -bool SpecParser::parseTypeMap() +bool LegacySpecParser::parseTypeMap() { - QFile file(m_typeMapFileName); + QFile file(typeMapFileName()); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning() << "Failed to open spec file:" << m_specFileName << "Aborting"; + qWarning() << "Failed to open type file:" << typeMapFileName() << "Aborting"; return false; } @@ -103,18 +100,18 @@ bool SpecParser::parseTypeMap() value = QStringLiteral("void"); m_typeMap.insert(key, value); - qSpecParserDebug() << "Found type mapping from" << key << "=>" << value; + qLegacySpecParserDebug() << "Found type mapping from" << key << "=>" << value; } } return true; } -void SpecParser::parseEnums() +void LegacySpecParser::parseEnums() { } -void SpecParser::parseFunctions(QTextStream &stream) +void LegacySpecParser::parseFunctions(QTextStream &stream) { static QRegExp functionRegExp("^(\\w+)\\(.*\\)"); static QRegExp returnRegExp("^\\treturn\\s+(\\S+)"); @@ -168,8 +165,12 @@ void SpecParser::parseFunctions(QTextStream &stream) versions.insert(currentVersionProfile.version); } - if (acceptCurrentFunctionInExtension) - m_extensionFunctions.insert(currentCategory, currentFunction); + if (acceptCurrentFunctionInExtension) { + FunctionProfile fp; + fp.profile = currentVersionProfile.profile; + fp.function = currentFunction; + m_extensionFunctions.insert(currentCategory, fp); + } } // Start a new function @@ -187,7 +188,7 @@ void SpecParser::parseFunctions(QTextStream &stream) // Extract the function name QString functionName = functionRegExp.cap(1); currentFunction.name = functionName; - qSpecParserDebug() << "Found function:" << functionName; + qLegacySpecParserDebug() << "Found function:" << functionName; } else if (argumentRegExp.indexIn(line) != -1) { // Extract info about this function argument @@ -219,7 +220,7 @@ void SpecParser::parseFunctions(QTextStream &stream) acceptCurrentFunctionInCore = false; } - qSpecParserDebug() << " argument:" << arg.type << arg.name; + qLegacySpecParserDebug() << " argument:" << arg.type << arg.name; currentFunction.arguments.append(arg); } else if (returnRegExp.indexIn(line) != -1) { @@ -230,13 +231,13 @@ void SpecParser::parseFunctions(QTextStream &stream) acceptCurrentFunctionInCore = false; } QString returnType = m_typeMap.value(returnTypeKey); - qSpecParserDebug() << " return type:" << returnType; + qLegacySpecParserDebug() << " return type:" << returnType; currentFunction.returnType = returnType; } else if (versionRegExp.indexIn(line) != -1 && !haveVersionInfo) { // Only use version line if no other source // Extract the OpenGL version in which this function was introduced QString version = versionRegExp.cap(1); - qSpecParserDebug() << " version:" << version; + qLegacySpecParserDebug() << " version:" << version; QStringList parts = version.split(QLatin1Char('.')); if (parts.size() != 2) { qWarning() << "Found invalid version number"; @@ -259,7 +260,7 @@ void SpecParser::parseFunctions(QTextStream &stream) } else if (categoryRegExp.indexIn(line) != -1) { // Extract the category for this function QString category = categoryRegExp.cap(1).simplified(); - qSpecParserDebug() << " category:" << category; + qLegacySpecParserDebug() << " category:" << category; if (categoryVersionRegExp.indexIn(category) != -1) { // Use the version info in the category in preference to the version @@ -275,7 +276,7 @@ void SpecParser::parseFunctions(QTextStream &stream) } else { // Make a note of the extension name and tag this function as being part of an extension - qSpecParserDebug() << "Found category =" << category; + qLegacySpecParserDebug() << "Found category =" << category; currentCategory = category; acceptCurrentFunctionInExtension = true; @@ -290,7 +291,7 @@ void SpecParser::parseFunctions(QTextStream &stream) } } else if (extToCoreVersionRegExp.indexIn(line) != -1) { - qSpecParserDebug() << line; + qLegacySpecParserDebug() << line; int majorVersion = extToCoreVersionRegExp.cap(1).toInt(); int minorVersion = extToCoreVersionRegExp.cap(2).toInt(); extToCoreCurrentVersion.major = majorVersion; @@ -306,7 +307,7 @@ void SpecParser::parseFunctions(QTextStream &stream) qSort(m_versions); } -bool SpecParser::inDeprecationException(const QString &functionName) const +bool LegacySpecParser::inDeprecationException(const QString &functionName) const { return (functionName == QStringLiteral("TexImage3D")); } diff --git a/util/glgen/legacyspecparser.h b/util/glgen/legacyspecparser.h new file mode 100644 index 0000000000000000000000000000000000000000..63d9a9f1704e27a58a67bb4ff6e5c8dc5496ed5a --- /dev/null +++ b/util/glgen/legacyspecparser.h @@ -0,0 +1,78 @@ +/*************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) +** Contact: http://www.qt-project.org/legal +** +** This file is part of the utilities 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 LEGACYSPECPARSER_H +#define LEGACYSPECPARSER_H + +#include "specparser.h" + +#include <QStringList> +#include <QVariant> + +class QTextStream; + +class LegacySpecParser : public SpecParser +{ +public: + virtual QList<Version> versions() const {return m_versions;} + + virtual bool parse(); + +protected: + const QMultiHash<VersionProfile, Function> &versionFunctions() const { return m_functions; } + const QMultiMap<QString, FunctionProfile> &extensionFunctions() const { return m_extensionFunctions; } + +private: + QMap<QString, QString> m_typeMap; + QMultiHash<VersionProfile, Function> m_functions; + + QList<Version> m_versions; + + // Extension support + QMultiMap<QString, FunctionProfile> m_extensionFunctions; + + bool parseTypeMap(); + void parseEnums(); + void parseFunctions(QTextStream &stream); + bool inDeprecationException(const QString &functionName) const; +}; + +#endif // LEGACYSPECPARSER_H diff --git a/util/glgen/main.cpp b/util/glgen/main.cpp index 15c311caf36a30237f9498c6810ca17c911696b2..41d97a6c850818b1de1adb2d4fc45f7d48c768e4 100644 --- a/util/glgen/main.cpp +++ b/util/glgen/main.cpp @@ -40,22 +40,39 @@ ****************************************************************************/ #include "codegenerator.h" -#include "specparser.h" +#include "legacyspecparser.h" +#include "xmlspecparser.h" + +#include <QCommandLineParser> int main(int argc, char *argv[]) { - Q_UNUSED(argc); - Q_UNUSED(argv); + QCoreApplication app(argc, argv); + QCommandLineParser cmdParser; + + // flag whether to use legacy or not + QCommandLineOption legacyOption(QStringList() << "l" << "legacy", "Use legacy parser."); + cmdParser.addOption(legacyOption); + cmdParser.process(app); + + SpecParser *parser; + + if (cmdParser.isSet(legacyOption)) { + parser = new LegacySpecParser(); + parser->setTypeMapFileName(QStringLiteral("gl.tm")); + parser->setSpecFileName(QStringLiteral("gl.spec")); + } else { + parser = new XmlSpecParser(); + parser->setSpecFileName(QStringLiteral("gl.xml")); + } - SpecParser parser; - parser.setTypeMapFileName(QStringLiteral("gl.tm")); - parser.setSpecFileName(QStringLiteral("gl.spec")); - parser.parse(); + parser->parse(); CodeGenerator generator; - generator.setParser(&parser); + generator.setParser(parser); generator.generateCoreClasses(QStringLiteral("qopenglversionfunctions")); generator.generateExtensionClasses(QStringLiteral("qopenglextensions")); + delete parser; return 0; } diff --git a/util/glgen/specparser.h b/util/glgen/specparser.h index 19357841ca3cdaaadc970c935047293a9803f0bf..0ba36ef8d84e616cdec1cd21366961d6f158d946 100644 --- a/util/glgen/specparser.h +++ b/util/glgen/specparser.h @@ -46,6 +46,7 @@ #include <QVariant> class QTextStream; +class QXmlStreamReader; struct Version { int major; @@ -57,6 +58,11 @@ inline bool operator == (const Version &lhs, const Version &rhs) return (lhs.major == rhs.major && lhs.minor == rhs.minor); } +inline bool operator != (const Version &lhs, const Version &rhs) +{ + return !(lhs == rhs); +} + inline bool operator < (const Version &lhs, const Version &rhs) { if (lhs.major != rhs.major) @@ -73,6 +79,17 @@ inline bool operator > (const Version &lhs, const Version &rhs) return (lhs.minor > rhs.minor); } +inline bool operator >= (const Version &lhs, const Version &rhs) +{ + return !(lhs < rhs); +} + + +inline bool operator <= (const Version &lhs, const Version &rhs) +{ + return !(lhs > rhs); +} + inline uint qHash(const Version &v) { return qHash(v.major * 100 + v.minor * 10); @@ -102,6 +119,11 @@ inline bool operator == (const VersionProfile &lhs, const VersionProfile &rhs) return lhs.version == rhs.version; } +inline bool operator != (const VersionProfile &lhs, const VersionProfile &rhs) +{ + return !(lhs == rhs); +} + inline bool operator < (const VersionProfile &lhs, const VersionProfile &rhs) { if (lhs.profile != rhs.profile) @@ -140,13 +162,47 @@ struct Function QList<Argument> arguments; }; +inline bool operator== (const Argument &lhs, const Argument &rhs) +{ + if ((lhs.type != rhs.type) || (lhs.name != rhs.name) || (lhs.direction != rhs.direction)) { + return false; + } + + return (lhs.mode != rhs.mode); +} + +inline bool operator!= (const Argument &lhs, const Argument &rhs) +{ + return !(lhs == rhs); +} + +inline bool operator== (const Function &lhs, const Function &rhs) +{ + if ((lhs.returnType != rhs.returnType) || (lhs.name != rhs.name)) { + return false; + } + + return (lhs.arguments == rhs.arguments); +} + +inline bool operator!= (const Function &lhs, const Function &rhs) +{ + return !(lhs == rhs); +} + typedef QList<Function> FunctionList; typedef QMap<VersionProfile, FunctionList> FunctionCollection; +struct FunctionProfile +{ + VersionProfile::OpenGLProfile profile; + Function function; +}; + class SpecParser { public: - explicit SpecParser(); + virtual ~SpecParser() {} QString specFileName() const { @@ -158,22 +214,28 @@ public: return m_typeMapFileName; } - QList<Version> versions() const {return m_versions;} - QList<VersionProfile> versionProfiles() const {return m_functions.uniqueKeys();} + virtual QList<Version> versions() const = 0; + + QList<VersionProfile> versionProfiles() const {return versionFunctions().uniqueKeys();} QList<Function> functionsForVersion(const VersionProfile &v) const { - return m_functions.values(v); + return versionFunctions().values(v); } QStringList extensions() const { - return QStringList(m_extensionFunctions.uniqueKeys()); + return QStringList(extensionFunctions().uniqueKeys()); } QList<Function> functionsForExtension(const QString &extension) { - return m_extensionFunctions.values(extension); + QList<Function> func; + + Q_FOREACH (const FunctionProfile &f, extensionFunctions().values(extension)) + func.append(f.function); + + return func; } void setSpecFileName(QString arg) @@ -186,25 +248,15 @@ public: m_typeMapFileName = arg; } - void parse(); + virtual bool parse() = 0; protected: - bool parseTypeMap(); - void parseEnums(); - void parseFunctions(QTextStream &stream); - bool inDeprecationException(const QString &functionName) const; + virtual const QMultiHash<VersionProfile, Function> &versionFunctions() const = 0; + virtual const QMultiMap<QString, FunctionProfile> &extensionFunctions() const = 0; private: QString m_specFileName; QString m_typeMapFileName; - - QMap<QString, QString> m_typeMap; - QMultiMap<VersionProfile, Function> m_functions; - - QList<Version> m_versions; - - // Extension support - QMultiMap<QString, Function> m_extensionFunctions; }; #endif // SPECPARSER_H diff --git a/util/glgen/xmlspecparser.cpp b/util/glgen/xmlspecparser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2be6d292d0352f49034b32968067ebd39e71ea1 --- /dev/null +++ b/util/glgen/xmlspecparser.cpp @@ -0,0 +1,440 @@ +/*************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB) +** Contact: http://www.qt-project.org/legal +** +** This file is part of the utilities 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 "xmlspecparser.h" + +#include <QDebug> +#include <QFile> +#include <QRegularExpression> +#include <QStringList> +#include <QTextStream> +#include <QXmlStreamReader> + +#ifdef SPECPARSER_DEBUG +#define qXmlSpecParserDebug qDebug +#else +#define qXmlSpecParserDebug QT_NO_QDEBUG_MACRO +#endif + +bool XmlSpecParser::parse() +{ + // Open up a stream on the actual OpenGL function spec file + QFile file(specFileName()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "Failed to open spec file:" << specFileName() << "Aborting"; + return false; + } + + QXmlStreamReader stream(&file); + + // Extract the info that we need + parseFunctions(stream); + return true; +} + +void XmlSpecParser::parseParam(QXmlStreamReader &stream, Function &func) +{ + Argument arg; + arg.type = QString(); + + while (!stream.isEndDocument()) { + stream.readNext(); + + if (stream.isStartElement()) { + QString tag = stream.name().toString(); + + if (tag == "ptype") { + if (stream.readNext() == QXmlStreamReader::Characters) + arg.type.append(stream.text().toString()); + } + + else if (tag == "name") { + if (stream.readNext() == QXmlStreamReader::Characters) + arg.name = stream.text().toString().trimmed(); + } + } else if (stream.isCharacters()) { + arg.type.append(stream.text().toString()); + } else if (stream.isEndElement()) { + QString tag = stream.name().toString(); + + if (tag == "param") { + // compatibility with old spec + QRegularExpression typeRegExp("(const )?(.+)(?<!\\*)((?:(?!\\*$)\\*)*)(\\*)?"); + + // remove extra whitespace + arg.type = arg.type.trimmed(); + + // set default + arg.direction = Argument::In; + arg.mode = Argument::Value; + + QRegularExpressionMatch exp = typeRegExp.match(arg.type); + if (exp.hasMatch()) { + if (!exp.captured(4).isEmpty()) { + arg.mode = Argument::Reference; + + if (exp.captured(1).isEmpty()) + arg.direction = Argument::Out; + } + + arg.type = exp.captured(2) + exp.captured(3); + } + + break; + } + } + } + + // remove any excess whitespace + arg.type = arg.type.trimmed(); + arg.name = arg.name.trimmed(); + + // maybe some checks? + func.arguments.append(arg); +} + +void XmlSpecParser::parseCommand(QXmlStreamReader &stream) +{ + Function func; + + while (!stream.isEndDocument()) { + stream.readNext(); + + if (stream.isStartElement()) { + QString tag = stream.name().toString(); + + if (tag == "proto") { + while (!stream.isEndDocument()) { + stream.readNext(); + if (stream.isStartElement() && (stream.name().toString() == "name")) { + if (stream.readNext() == QXmlStreamReader::Characters) + func.name = stream.text().toString(); + } else if (stream.isCharacters()) { + func.returnType.append(stream.text().toString()); + } else if (stream.isEndElement() && (stream.name().toString() == "proto")) { + break; + } + } + } + + if (tag == "param") + parseParam(stream, func); + } + + else if (stream.isEndElement()) { + QString tag = stream.name().toString(); + + if (tag == "command") + break; + } + } + + // maybe checks? + func.returnType = func.returnType.trimmed(); + + // for compatibility with old spec + if (func.name.startsWith("gl")) + func.name.remove(0, 2); + + m_functionList.insert(func.name, func); +} + +void XmlSpecParser::parseCommands(QXmlStreamReader &stream) +{ + while (!stream.isEndDocument()) { + stream.readNext(); + + if (stream.isStartElement()) { + QString tag = stream.name().toString(); + + if (tag == "command") + parseCommand(stream); + } + + else if (stream.isEndElement()) { + QString tag = stream.name().toString(); + + if (tag == "commands") + break; + } + } +} + +void XmlSpecParser::parseRequire(QXmlStreamReader &stream, FunctionList &funcs) +{ + while (!stream.isEndDocument()) { + stream.readNext(); + + if (stream.isStartElement()) { + QString tag = stream.name().toString(); + + if (tag == "command") { + QString func = stream.attributes().value("name").toString(); + + // for compatibility with old spec + if (func.startsWith("gl")) + func.remove(0, 2); + + funcs.append(m_functionList[func]); + } + } else if (stream.isEndElement()) { + QString tag = stream.name().toString(); + + if (tag == "require") + break; + } + } +} + +void XmlSpecParser::parseRemoveCore(QXmlStreamReader &stream) +{ + while (!stream.isEndDocument()) { + stream.readNext(); + + if (stream.isStartElement()) { + QString tag = stream.name().toString(); + + if (tag == "command") { + QString func = stream.attributes().value("name").toString(); + + // for compatibility with old spec + if (func.startsWith("gl")) + func.remove(0, 2); + + // go through list of version and mark as incompatible + Q_FOREACH (const Version& v, m_versions) { + // Combine version and profile for this subset of functions + VersionProfile version; + version.version = v; + version.profile = VersionProfile::CoreProfile; + + // Fetch the functions and add to collection for this class + Q_FOREACH (const Function& f, m_functions.values(version)) { + if (f.name == func) { + VersionProfile newVersion; + newVersion.version = v; + newVersion.profile = VersionProfile::CompatibilityProfile; + + m_functions.insert(newVersion, f); + m_functions.remove(version, f); + } + } + } + } + } else if (stream.isEndElement()) { + QString tag = stream.name().toString(); + + if (tag == "remove") + break; + } + } +} + +void XmlSpecParser::parseFeature(QXmlStreamReader &stream) +{ + QRegularExpression versionRegExp("(\\d).(\\d)"); + QXmlStreamAttributes attributes = stream.attributes(); + + QRegularExpressionMatch match = versionRegExp.match(attributes.value("number").toString()); + + if (!match.hasMatch()) { + qWarning() << "Malformed version indicator"; + return; + } + + if (attributes.value("api").toString() != "gl") + return; + + int majorVersion = match.captured(1).toInt(); + int minorVersion = match.captured(2).toInt(); + + Version v; + VersionProfile core, compat; + + v.major = majorVersion; + v.minor = minorVersion; + core.version = compat.version = v; + core.profile = VersionProfile::CoreProfile; + compat.profile = VersionProfile::CompatibilityProfile; + + while (!stream.isEndDocument()) { + stream.readNext(); + + if (stream.isStartElement()) { + QString tag = stream.name().toString(); + + if (tag == "require") { + FunctionList funcs; + + if (stream.attributes().value("profile").toString() == "compatibility") { + parseRequire(stream, funcs); + Q_FOREACH (const Function& f, funcs) { + m_functions.insert(compat, f); + } + } else { + parseRequire(stream, funcs); + Q_FOREACH (const Function& f, funcs) { + m_functions.insert(core, f); + } + } + } else if (tag == "remove") { + if (stream.attributes().value("profile").toString() == "core") + parseRemoveCore(stream); + } + } else if (stream.isEndElement()) { + QString tag = stream.name().toString(); + + if (tag == "feature") + break; + } + } + + m_versions.append(v); +} + +void XmlSpecParser::parseExtension(QXmlStreamReader &stream) +{ + QXmlStreamAttributes attributes = stream.attributes(); + QString name = attributes.value("name").toString(); + + while (!stream.isEndDocument()) { + stream.readNext(); + + if (stream.isStartElement()) { + QString tag = stream.name().toString(); + + if (tag == "require") { + if (stream.attributes().value("profile").toString() == "compatibility") { + FunctionList funcs; + parseRequire(stream, funcs); + + Q_FOREACH (const Function& f, funcs) { + FunctionProfile fp; + fp.function = f; + fp.profile = VersionProfile::CompatibilityProfile; + m_extensionFunctions.insert(name, fp); + } + } else { + FunctionList funcs; + parseRequire(stream, funcs); + Q_FOREACH (const Function& f, funcs) { + FunctionProfile fp; + fp.function = f; + fp.profile = VersionProfile::CoreProfile; + m_extensionFunctions.insert(name, fp); + } + } + + + } + } else if (stream.isEndElement()) { + QString tag = stream.name().toString(); + + if (tag == "extension") + break; + } + } +} + +void XmlSpecParser::parseFunctions(QXmlStreamReader &stream) +{ + while (!stream.isEndDocument()) { + stream.readNext(); + + if (stream.isStartElement()) { + QString tag = stream.name().toString(); + + if (tag == "feature") { + parseFeature(stream); + } else if (tag == "commands") { + parseCommands(stream); + } else if (tag == "extension") { + parseExtension(stream); + } + } else if (stream.isEndElement()) { + stream.readNext(); + } + } + + // hack - add GL_ARB_imaging to every version after 1.2 inclusive + Version versionThreshold; + versionThreshold.major = 1; + versionThreshold.minor = 2; + QList<FunctionProfile> funcs = m_extensionFunctions.values("GL_ARB_imaging"); + + VersionProfile vp; + vp.version = versionThreshold; + + Q_FOREACH (const FunctionProfile& fp, funcs) { + vp.profile = fp.profile; + m_functions.insert(vp, fp.function); + } + + // now we will prune any duplicates + QSet<QString> funcset; + + Q_FOREACH (const Version& v, m_versions) { + // check compatibility first + VersionProfile vp; + vp.version = v; + + vp.profile = VersionProfile::CompatibilityProfile; + + Q_FOREACH (const Function& f, m_functions.values(vp)) { + // remove duplicate + if (funcset.contains(f.name)) + m_functions.remove(vp, f); + + funcset.insert(f.name); + } + + vp.profile = VersionProfile::CoreProfile; + + Q_FOREACH (const Function& f, m_functions.values(vp)) { + + // remove duplicate + if (funcset.contains(f.name)) + m_functions.remove(vp, f); + + funcset.insert(f.name); + } + } +} diff --git a/util/glgen/xmlspecparser.h b/util/glgen/xmlspecparser.h new file mode 100644 index 0000000000000000000000000000000000000000..3049e911cc56473120d11e5b242bc6fd8a5b406f --- /dev/null +++ b/util/glgen/xmlspecparser.h @@ -0,0 +1,83 @@ +/*************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) +** Contact: http://www.qt-project.org/legal +** +** This file is part of the utilities 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 XMLSPECPARSER_H +#define XMLSPECPARSER_H + +#include "specparser.h" + +#include <QStringList> +#include <QVariant> + +class QXmlStreamReader; + +class XmlSpecParser : public SpecParser +{ +public: + virtual QList<Version> versions() const { return m_versions; } + + virtual bool parse(); + +protected: + const QMultiHash<VersionProfile, Function> &versionFunctions() const { return m_functions; } + const QMultiMap<QString, FunctionProfile> &extensionFunctions() const { return m_extensionFunctions; } + +private: + void parseFunctions(QXmlStreamReader &stream); + void parseCommands(QXmlStreamReader &stream); + void parseCommand(QXmlStreamReader &stream); + void parseParam(QXmlStreamReader &stream, Function &func); + void parseFeature(QXmlStreamReader &stream); + void parseExtension(QXmlStreamReader &stream); + void parseRequire(QXmlStreamReader &stream, FunctionList& profile); + void parseRemoveCore(QXmlStreamReader &stream); + + QMultiHash<VersionProfile, Function> m_functions; + + QList<Version> m_versions; + + // Extension support + QMultiMap<QString, FunctionProfile> m_extensionFunctions; + + QMap<QString, Function> m_functionList; +}; + +#endif // XMLSPECPARSER_H