Files
RedBear-OS/local/recipes/qt/qtbase/source/util/glgen/xmlspecparser.cpp
T
vasilito f31522130f fix: comprehensive boot warnings and exceptions — fixable silenced, unfixable diagnosed
Build system (5 gaps hardened):
- COOKBOOK_OFFLINE defaults to true (fork-mode)
- normalize_patch handles diff -ruN format
- New 'repo validate-patches' command (25/25 relibc patches)
- 14 patched Qt/Wayland/display recipes added to protected list
- relibc archive regenerated with current patch chain

Boot fixes (fixable):
- Full ISO EFI partition: 16 MiB → 1 MiB (matches mini, BIOS hardcoded 2 MiB offset)
- D-Bus system bus: absolute /usr/bin/dbus-daemon path (was skipped)
- redbear-sessiond: absolute /usr/bin/redbear-sessiond path (was skipped)
- daemon framework: silenced spurious INIT_NOTIFY warnings for oneshot_async services (P0-daemon-silence-init-notify.patch)
- udev-shim: demoted INIT_NOTIFY warning to INFO (expected for oneshot_async)
- relibc: comprehensive named semaphores (sem_open/close/unlink) replacing upstream todo!() stubs
- greeterd: Wayland socket timeout 15s → 30s (compositor DRM wait)
- greeter-ui: built and linked (header guard unification, sem_compat stubs removed)
- mc: un-ignored in both configs, fixed glib/libiconv/pcre2 transitive deps
- greeter config: removed stale keymapd dependency from display/greeter services
- prefix toolchain: relibc headers synced, _RELIBC_STDLIB_H guard unified

Unfixable (diagnosed, upstream):
- i2c-hidd: abort on no-I2C-hardware (QEMU) — process::exit → relibc abort
- kded6/greeter-ui: page fault 0x8 — Qt library null deref
- Thread panics fd != -1 — Rust std library on Redox
- DHCP timeout / eth0 MAC — QEMU user-mode networking
- hwrngd/thermald — no hardware RNG/thermal in VM
- live preload allocation — BIOS memory fragmentation, continues on demand
2026-05-05 20:20:37 +01:00

403 lines
12 KiB
C++

// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB)
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#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);
}
}
}