summaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/glgen/glgen.pro5
-rw-r--r--util/glgen/legacyspecparser.cpp (renamed from util/glgen/specparser.cpp)57
-rw-r--r--util/glgen/legacyspecparser.h78
-rw-r--r--util/glgen/main.cpp33
-rw-r--r--util/glgen/specparser.h90
-rw-r--r--util/glgen/xmlspecparser.cpp440
-rw-r--r--util/glgen/xmlspecparser.h83
7 files changed, 730 insertions, 56 deletions
diff --git a/util/glgen/glgen.pro b/util/glgen/glgen.pro
index 9208ba9e8e..11018e942d 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
index 45726230de..6856a8f022 100644
--- a/util/glgen/specparser.cpp
+++ b/util/glgen/legacyspecparser.cpp
@@ -31,7 +31,7 @@
**
****************************************************************************/
-#include "specparser.h"
+#include "legacyspecparser.h"
#include <QDebug>
#include <QFile>
@@ -40,39 +40,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;
}
@@ -95,18 +92,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+)");
@@ -160,8 +157,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
@@ -179,7 +180,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
@@ -211,7 +212,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) {
@@ -222,13 +223,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";
@@ -251,7 +252,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
@@ -267,7 +268,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;
@@ -282,7 +283,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;
@@ -298,7 +299,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 0000000000..63d9a9f170
--- /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 7552b9f465..3cc1212a69 100644
--- a/util/glgen/main.cpp
+++ b/util/glgen/main.cpp
@@ -32,22 +32,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 99e33b66e9..4fedc84d9c 100644
--- a/util/glgen/specparser.h
+++ b/util/glgen/specparser.h
@@ -38,6 +38,7 @@
#include <QVariant>
class QTextStream;
+class QXmlStreamReader;
struct Version {
int major;
@@ -49,6 +50,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)
@@ -65,6 +71,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);
@@ -94,6 +111,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)
@@ -132,13 +154,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
{
@@ -150,22 +206,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)
@@ -178,25 +240,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 0000000000..c2be6d292d
--- /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 0000000000..3049e911cc
--- /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