summaryrefslogtreecommitdiffstats
path: root/src/xml_to_data
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 18:42:24 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 18:42:24 +0000
commitf508189682b6fba62e08feeb1596f682bad5fff9 (patch)
tree28aeb0e6c19386c385c1ce5edf8a92c1bca15281 /src/xml_to_data
downloadpiklab-f508189682b6fba62e08feeb1596f682bad5fff9.tar.gz
piklab-f508189682b6fba62e08feeb1596f682bad5fff9.zip
Added KDE3 version of PikLab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/piklab@1095639 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/xml_to_data')
-rw-r--r--src/xml_to_data/Makefile.am7
-rw-r--r--src/xml_to_data/device_xml_to_data.cpp260
-rw-r--r--src/xml_to_data/device_xml_to_data.h88
-rw-r--r--src/xml_to_data/prog_xml_to_data.h218
-rw-r--r--src/xml_to_data/xml_to_data.cpp71
-rw-r--r--src/xml_to_data/xml_to_data.h47
-rw-r--r--src/xml_to_data/xml_to_data.pro6
7 files changed, 697 insertions, 0 deletions
diff --git a/src/xml_to_data/Makefile.am b/src/xml_to_data/Makefile.am
new file mode 100644
index 0000000..66985ca
--- /dev/null
+++ b/src/xml_to_data/Makefile.am
@@ -0,0 +1,7 @@
+INCLUDES = -I$(top_srcdir)/src $(all_includes)
+METASOURCES = AUTO
+
+libxmltodata_la_LDFLAGS = $(all_libraries)
+noinst_LTLIBRARIES = libxmltodata.la
+libxmltodata_la_SOURCES = xml_to_data.cpp xml_to_data.cpp device_xml_to_data.cpp
+libxmltodata_la_LIBADD = $(LIB_QT)
diff --git a/src/xml_to_data/device_xml_to_data.cpp b/src/xml_to_data/device_xml_to_data.cpp
new file mode 100644
index 0000000..9ad1940
--- /dev/null
+++ b/src/xml_to_data/device_xml_to_data.cpp
@@ -0,0 +1,260 @@
+/***************************************************************************
+ * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#include "device_xml_to_data.h"
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+
+bool Device::XmlToDataBase::getFrequencyRange(OperatingCondition oc, Special special, QDomElement element)
+{
+ QDomElement range;
+ for (QDomNode child=element.firstChild(); !child.isNull(); child=child.nextSibling()) {
+ if ( child.nodeName()!="frequency_range" ) continue;
+ if ( !child.isElement() ) qFatal("\"frequency_range\" should be an element");
+ if ( child.toElement().attribute("name")!=oc.key() ) continue;
+ Special s = Special::fromKey(child.toElement().attribute("special"));
+ if ( s==Special::Nb_Types ) qFatal("Unrecognized special");
+ if ( special!=s ) continue;
+ if ( !range.isNull() ) qFatal("Duplicated \"frequency_range\"");
+ range = child.toElement();
+ }
+ if ( range.isNull() ) return false;
+ FrequencyRange frange;
+ frange.operatingCondition = oc;
+ frange.special = special;
+ for (QDomNode child=range.firstChild(); !child.isNull(); child=child.nextSibling()) {
+ if ( child.nodeName()=="frequency" ) {
+ if ( !child.isElement() ) qFatal("Frequency is not an element");
+ QDomElement frequency = child.toElement();
+ bool ok1, ok2, ok3, ok4;
+ RangeBox box;
+ box.start.x = frequency.attribute("start").toDouble(&ok1);
+ box.end.x = frequency.attribute("end").toDouble(&ok2);
+ box.start.yMin = frequency.attribute("vdd_min").toDouble(&ok3);
+ box.start.yMax = frequency.attribute("vdd_max").toDouble(&ok4);
+ box.end.yMax = box.start.yMax;
+ if ( !ok1 || !ok2 || !ok3 || !ok4
+ || box.start.x<0.0 || box.start.x>box.end.x
+ || box.start.yMin<0.0 || box.start.yMin>box.start.yMax )
+ qFatal("Malformed frequency element");
+ if ( frequency.attribute("vdd_min_end").isEmpty() ) box.end.yMin = box.start.yMin;
+ else {
+ box.end.yMin = frequency.attribute("vdd_min_end").toDouble(&ok1);
+ if ( !ok1 || box.end.yMin>box.end.yMax ) qFatal("Malformed frequency element");
+ }
+ box.mode = frequency.attribute("mode");
+ box.osc = frequency.attribute("osc");
+ box.special = frequency.attribute("special");
+ for (uint i=0; i<uint(frange.vdds.count()); i++)
+ if ( box.start.x<frange.vdds[i].end.x && box.end.x>frange.vdds[i].start.x ) {
+ if ( box.mode.isEmpty() && box.osc.isEmpty() && box.special.isEmpty() )
+ qFatal("Overlapping frequency ranges");
+ continue; // #### FIXME: ignore additionnal mode
+ }
+// qDebug("add Freq Range: %s %s %f=[%f %f] %f=[%f %f]",
+// Device::FrequencyRange::TYPE_LABELS[type], Device::FrequencyRange::SPECIAL_LABELS[type],
+// box.start.x, box.start.yMin, box.start.yMax,
+// box.end.x, box.end.yMin, box.end.yMax);
+ frange.vdds.append(box);
+ }
+ }
+ if ( frange.vdds.count()==0 ) qFatal("Empty frequency range");
+ _data->_frequencyRanges.append(frange);
+ return true;
+}
+
+bool Device::XmlToDataBase::getMemoryTechnology(QDomElement element)
+{
+ QString s = element.attribute("memory_technology");
+ _data->_memoryTechnology = MemoryTechnology::fromKey(s);
+ if ( _data->_memoryTechnology!=MemoryTechnology::Nb_Types ) return true;
+ if ( !s.isNull() ) qFatal("Unrecognized memory technology");
+ return false;
+}
+
+void Device::XmlToDataBase::processDevice(QDomElement device)
+{
+ QString name = device.attribute("name").upper();
+ if ( name.isEmpty() ) qFatal("Device has no name");
+ if ( _map.contains(name) ) qFatal(QString("Device \"%1\" already defined").arg(name));
+ _data = createData();
+ _map[name] = _data;
+ _data->_name = name;
+ _data->_alternatives = QStringList::split(' ', device.attribute("alternative"));
+ if ( _data->_alternatives.count() ) _alternatives[name] = _data->_alternatives;
+ _data->_status = Status::fromKey(device.attribute("status"));
+ switch (_data->_status.type()) {
+ case Status::Nb_Types:
+ qFatal("Unrecognized or absent device status");
+ break;
+ case Status::Future:
+ if ( _data->_alternatives.count() ) qFatal("Future device has alternative");
+ break;
+ case Status::NotRecommended:
+ case Status::Mature:
+ if ( _data->_alternatives.count()==0 ) warning("Not-recommended/mature device has no alternative");
+ break;
+ case Status::InProduction:
+ case Status::EOL:
+ case Status::Unknown: break;
+ }
+
+ // document
+ _data->_documents.webpage = device.attribute("document"); // ### REMOVE ME
+ QDomElement documents = findUniqueElement(device, "documents", QString::null, QString::null);
+ if ( documents.isNull() ) {
+ if ( _data->_documents.webpage.isEmpty() ) qFatal("Missing \"documents\" element");
+ } else {
+ if ( !_data->_documents.webpage.isEmpty() ) qFatal("document should be removed from root element");
+ _data->_documents.webpage = documents.attribute("webpage");
+ if ( _data->_documents.webpage.isEmpty() ) qFatal("Missing webpage");
+ _data->_documents.datasheet = documents.attribute("datasheet");
+ QRegExp rexp("\\d{5}");
+ if ( _data->_documents.datasheet=="?" ) warning("No datasheet specified");
+ if ( !rexp.exactMatch(_data->_documents.datasheet) ) qFatal(QString("Malformed datasheet \"%1\" (5 digits)").arg(_data->_documents.datasheet));
+ _data->_documents.progsheet = documents.attribute("progsheet");
+ if ( _data->_documents.progsheet=="?" ) warning("No progsheet specified");
+ if ( !rexp.exactMatch(_data->_documents.datasheet) ) qFatal(QString("Malformed progsheet \"%1\" (5 digits)").arg(_data->_documents.progsheet));
+ _data->_documents.erratas = QStringList::split(" ", documents.attribute("erratas"));
+ for (uint i=0; i<uint(_data->_documents.erratas.count()); i++) {
+ QString errata = _data->_documents.erratas[i];
+ if ( !rexp.exactMatch(errata) ) {
+ QRegExp rexp2("\\d{5}e\\d");
+ if ( !rexp2.exactMatch(errata) && !errata.startsWith("er") && errata.mid(2)!=_data->_name.lower() )
+ qFatal(QString("Malformed erratas \"%1\" (5 digits or 5 digits + e + 1 digit or \"er\" + name)").arg(errata));
+ }
+ }
+ }
+ if ( _data->_documents.webpage=="?" ) warning("No webpage specified");
+ else {
+ QRegExp rexp("\\d{6}");
+ if ( !rexp.exactMatch(_data->_documents.webpage) ) qFatal(QString("Malformed webpage \"%1\" (6 digits)").arg(_data->_documents.webpage));
+ if ( _documents.contains(_data->_documents.webpage) )
+ qFatal(QString("webpage duplicated (already used for %1)").arg(_documents[_data->_documents.webpage]));
+ _documents[_data->_documents.webpage] = name;
+ }
+
+ // frequency ranges
+ QStringList names;
+ bool ok = false;
+ FOR_EACH(OperatingCondition, oc) {
+ names += oc.key();
+ FOR_EACH(Special, special)
+ if ( getFrequencyRange(oc, special, device) && special==Special::Normal ) ok = true;
+ }
+ if ( !ok ) qWarning("No normal frequency range defined");
+ checkTagNames(device, "frequency_range", names);
+
+ // memory technology
+ if ( !getMemoryTechnology(device) ) qFatal("Memory technology not defined");
+
+ // packages
+ for (QDomNode child=device.firstChild(); !child.isNull(); child=child.nextSibling()) {
+ if ( !child.isElement() || child.nodeName()!="package" ) continue;
+ Package p = processPackage(child.toElement());
+ QMap<QString, uint> pinLabels;
+ for (uint i=0; i<uint(p.pins.count()); i++) {
+ if ( p.pins[i].isEmpty() || p.pins[i]=="N/C" ) continue;
+ QStringList labels = QStringList::split("/", p.pins[i]);
+ for(uint k=0; k<uint(labels.count()); k++) {
+ if ( pinLabels.contains(labels[k]) ) pinLabels[labels[k]]++;
+ else pinLabels[labels[k]] = 1;
+ }
+ }
+ for (uint k=0; k<uint(_data->_packages.count()); k++)
+ for (uint l=0; l<uint(p.types.count()); l++)
+ for (uint j=0; j<uint(_data->_packages[k].types.count()); j++)
+ if ( _data->_packages[k].types[j]==p.types[l] && _data->_packages[k].pins.count()==p.pins.count() ) qFatal("Duplicated package type");
+ if ( !pinLabels.isEmpty() ) checkPins(pinLabels);
+ _data->_packages.append(p);
+ }
+}
+
+Device::Package Device::XmlToDataBase::processPackage(QDomElement element)
+{
+ Package package;
+ // nb pins
+ bool ok;
+ uint nb = element.attribute("nb_pins").toUInt(&ok);
+ if ( !ok || nb==0 ) qFatal("Malformed \"nb_pins\"");
+ package.pins.resize(nb);
+ // types
+ QStringList types = QStringList::split(" ", element.attribute("types"));
+ if ( types.isEmpty() ) qFatal("No package types specified");
+ for (uint k=0; k<uint(types.count()); k++) {
+ uint i = 0;
+ for (; Package::TYPE_DATA[i].name; i++) {
+ if ( types[k]!=Package::TYPE_DATA[i].name ) continue;
+ for (uint j=0; j<uint(package.types.count()); j++)
+ if ( package.types[j]==i ) qFatal(QString("Duplicated package type %1").arg(types[k]));
+ uint j = 0;
+ for (; j<Package::MAX_NB; j++)
+ if ( nb==Package::TYPE_DATA[i].nbPins[j] ) break;
+ if ( j==Package::MAX_NB ) qFatal(QString("Package %1 does not have the correct number of pins %2 (%3)").arg(types[k]).arg(nb).arg(Package::TYPE_DATA[i].nbPins[0]));
+ package.types.append(i);
+ break;
+ }
+ if ( Package::TYPE_DATA[i].name==0 ) qFatal(QString("Unknown package type \"%1\"").arg(types[k]));
+ }
+ // pins
+ QString name = Package::TYPE_DATA[package.types[0]].name;
+ if ( name=="sot23" ) {
+ if ( package.types.count()!=1 ) qFatal("SOT23 should be a specific package");
+ } else if ( (nb%2)!=0 ) qFatal(QString("\"nb_pins\" should be even for package \"%1\"").arg(name));
+ uint have_pins = false;
+ QMemArray<bool> found(nb);
+ found.fill(false);
+ QDomNode child = element.firstChild();
+ while ( !child.isNull() ) {
+ if ( child.nodeName()=="pin" ) {
+ if ( !child.isElement() ) qFatal("\"pin\" is not an element");
+ QDomElement pin = child.toElement();
+ bool ok;
+ uint i = pin.attribute("index").toUInt(&ok);
+ if ( !ok || i==0 || i>nb ) qFatal("Malformed pin index");
+ if (found[i-1]) qFatal("Duplicated pin index");
+ found[i-1] = true;
+ QString name = pin.attribute("name");
+ if ( !name.isEmpty() && name!="N/C" ) {
+ QStringList labels = QStringList::split("/", name);
+ if ( name.contains(" ") || labels.count()==0 ) qFatal("Malformed pin name");
+ if ( name!=name.upper() ) qFatal("Pin name should be uppercase");
+ }
+ package.pins[i-1] = name;
+ have_pins = true;
+ }
+ child = child.nextSibling();
+ }
+ if ( !have_pins ) ;//warning("Pins not specified"); // #### REMOVE ME !!
+ else for (uint i=0; i<nb; i++) if ( !found[i] ) qFatal(QString("Pin #%1 not specified").arg(i+1));
+ return package;
+}
+
+void Device::XmlToDataBase::parse()
+{
+ // process device files
+ QStringList files = QDir::current().entryList("*.xml");
+ for (uint i=0; i<uint(files.count()); i++) {
+ _data = 0;
+ QDomDocument doc = parseFile(files[i]);
+ QDomElement root = doc.documentElement();
+ if ( root.nodeName()!="device" ) qFatal("root node should be \"device\"");
+ processDevice(root);
+ }
+
+ // check alternatives
+ QMap<QString, QStringList>::const_iterator ait = _alternatives.begin();
+ for (; ait!=_alternatives.end(); ++ait) {
+ QStringList::const_iterator lit = ait.data().begin();
+ for (; lit!=ait.data().end(); ++lit)
+ if ( !_map.contains(*lit) ) qFatal(QString("Unknown alternative %1 for device %2").arg((*lit)).arg(ait.key()));
+ }
+}
diff --git a/src/xml_to_data/device_xml_to_data.h b/src/xml_to_data/device_xml_to_data.h
new file mode 100644
index 0000000..a1d0529
--- /dev/null
+++ b/src/xml_to_data/device_xml_to_data.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#ifndef DEVICE_XML_TO_DATA_H
+#define DEVICE_XML_TO_DATA_H
+
+#include <qmap.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include "common/common/misc.h"
+#include "common/common/streamer.h"
+#include "devices/base/generic_device.h"
+#include "xml_to_data.h"
+
+namespace Device
+{
+class XmlToDataBase : public ::XmlToData
+{
+public:
+ XmlToDataBase() : _data(0) {}
+
+protected:
+ mutable Data *_data;
+ QMap<QString, Data *> _map; // device -> data
+
+ virtual void parse();
+ virtual QString currentDevice() const { return (_data ? _data->name() : QString::null); }
+ virtual QString namespaceName() const = 0;
+ virtual Data *createData() const = 0;
+ virtual void processDevice(QDomElement device);
+ virtual void checkPins(const QMap<QString, uint> &pinLabels) const = 0;
+
+private:
+ QMap<QString, QString> _documents; // document -> device
+ QMap<QString, QStringList> _alternatives; // device -> alternatives
+
+ bool getFrequencyRange(OperatingCondition oc, Special special, QDomElement element);
+ bool getMemoryTechnology(QDomElement element);
+ Device::Package processPackage(QDomElement element);
+};
+
+template <class DataType>
+class XmlToData : public XmlToDataBase, public DataStreamer<DataType>
+{
+public:
+ virtual Device::Data *createData() const { return new DataType; }
+ DataType *data() { return static_cast<DataType *>(_data); }
+ const DataType *data() const { return static_cast<DataType *>(_data); }
+ virtual void output() {
+ QFile dfile("deps.mak");
+ if ( !dfile.open(IO_WriteOnly) ) return;
+ QTextStream dts(&dfile);
+ dts << "noinst_DATA = ";
+ uint i = 0;
+ QMap<QString, Data *>::const_iterator it;
+ for (it=_map.begin(); it!=_map.end(); ++it) {
+ if ( (i%10)==0 ) dts << "\\" << endl << " ";
+ dts << " " << it.key() << ".xml";
+ i++;
+ }
+ dts << endl;
+ dfile.close();
+
+ QFile file(namespaceName().lower() + "_data.cpp");
+ if ( !file.open(IO_WriteOnly) ) return;
+ QTextStream ts(&file);
+ ts << "#include \"devices/" << namespaceName().lower() << "/"
+ << namespaceName().lower() << "/" << namespaceName().lower() << "_group.h\"" << endl << endl;
+ ts << "const char *" << namespaceName() << "::DATA_STREAM =" << endl;
+ QValueList<DataType *> list;
+ for (it=_map.begin(); it!=_map.end(); ++it)
+ list.append(static_cast<const DataType *>(it.data()));
+ uint size = toCppString(list, ts);
+ ts << ";" << endl;
+ ts << "const uint " << namespaceName() << "::DATA_SIZE = " << size << ";" << endl;
+ file.close();
+ }
+};
+
+} // namespace
+
+#endif
diff --git a/src/xml_to_data/prog_xml_to_data.h b/src/xml_to_data/prog_xml_to_data.h
new file mode 100644
index 0000000..f4e820b
--- /dev/null
+++ b/src/xml_to_data/prog_xml_to_data.h
@@ -0,0 +1,218 @@
+/***************************************************************************
+ * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#ifndef PROG_XML_TO_DATA_H
+#define PROG_XML_TO_DATA_H
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qmap.h>
+
+#include "xml_to_data.h"
+#include "devices/list/device_list.h"
+
+//----------------------------------------------------------------------------
+template <class Data>
+class ExtXmlToData : public ::XmlToData
+{
+public:
+ ExtXmlToData(const QString &basename, const QString &namespac)
+ : _basename(basename), _namespace(namespac) {}
+
+protected:
+ QString _basename, _namespace;
+ virtual bool hasFamilies() const { return true; }
+ const QStringList &families() const { return _families; }
+ virtual uint familyIndex(const QString &family) const { return _families.findIndex(family); }
+ virtual void parseData(QDomElement, Data &) = 0;
+ virtual void includes(QTextStream &) const {}
+ virtual void outputData(const Data &, QTextStream &) const {}
+ virtual void outputFunctions(QTextStream &) const {}
+ virtual QString currentDevice() const { return _current; }
+ virtual void parseDevice(QDomElement element);
+ ::Group::Support extractSupport(const QString &s) const;
+ bool hasDevice(const QString &device) const { return _map.contains(device); }
+ virtual void parse();
+
+protected:
+ QString _current;
+ class PData {
+ public:
+ uint family;
+ ::Group::Support support;
+ Data data;
+ };
+ QMap<QString, PData> _map;
+ QStringList _families;
+
+ virtual void output();
+};
+
+template <class Data>
+Group::Support ExtXmlToData<Data>::extractSupport(const QString &s) const
+{
+ if ( s.isEmpty() ) return Group::Support::Untested;
+ Group::Support support = Group::Support::fromKey(s);
+ if ( support==Group::Support::None ) qFatal("Cannot be \"not supported\"");
+ if ( support==Group::Support::Nb_Types ) qFatal("Unknown support type");
+ return support;
+}
+
+template <class Data>
+void ExtXmlToData<Data>::parseDevice(QDomElement element)
+{
+ if ( element.nodeName()!="device" ) qFatal("Root node child should be named \"device\"");
+ _current = element.attribute("name").upper();
+ if ( Device::lister().data(_current)==0 ) qFatal(QString("Device name \"%1\" unknown").arg(_current));
+ if ( _map.contains(_current) ) qFatal(QString("Device \"%1\" already parsed").arg(_current));
+ PData data;
+ if ( hasFamilies() ) {
+ QString family = element.attribute("family");
+ if ( family.isEmpty() ) qFatal(QString("Family is empty").arg(family));
+ if ( _families.find(family)==_families.end() ) _families.append(family);
+ data.family = familyIndex(family);
+ }
+ data.support = extractSupport(element.attribute("support_type"));
+ parseData(element, data.data);
+ _map[_current] = data;
+}
+
+template <class Data>
+void ExtXmlToData<Data>::parse()
+{
+ QDomDocument doc = parseFile(_basename + ".xml");
+ QDomElement root = doc.documentElement();
+ if ( root.nodeName()!="type" ) qFatal("Root node should be \"type\"");
+ if ( root.attribute("name")!=_basename ) qFatal(QString("Root node name is not \"%1\"").arg(_basename));
+ QDomNode child = root.firstChild();
+ while ( !child.isNull() ) {
+ if ( child.isComment() ) qDebug("comment: %s", child.toComment().data().latin1());
+ else {
+ if ( !child.isElement() ) qFatal("Root node child should be an element");
+ parseDevice(child.toElement());
+ }
+ child = child.nextSibling();
+ }
+}
+
+template <class Data>
+void ExtXmlToData<Data>::output()
+{
+ // write .cpp file
+ QFile file(_basename + "_data.cpp");
+ if ( !file.open(IO_WriteOnly) ) qFatal(QString("Cannot open output file \"%1\"").arg(file.name()));
+ QTextStream s(&file);
+ s << "// #### Do not edit: this file is autogenerated !!!" << endl << endl;
+ s << "#include \"devices/list/device_list.h\"" << endl;
+ s << "#include \"" + _basename + ".h\"" << endl;
+ s << "#include \"" + _basename + "_data.h\"" << endl;
+ includes(s);
+ s << endl;
+ s << "namespace " << _namespace << endl;
+ s << "{" << endl;
+ s << "struct CData {" << endl;
+ s << " const char *name;" << endl;
+ if ( hasFamilies() ) s << " uint family;" << endl;
+ s << " uint support;" << endl;
+ s << " Data data;" << endl;
+ s << "};" << endl;
+ s << endl;
+
+ // data list
+ typename QMap<QString, PData>::const_iterator it = _map.begin();
+ for (; it!=_map.end(); ++it) {
+ s << "const CData PIC" << it.key() << "_DATA = {";
+ s << " \"" << it.key() << "\", ";
+ if ( hasFamilies() ) s << it.data().family << ", ";
+ s << it.data().support.type() << ", ";
+ s << "{ ";
+ outputData(it.data().data, s);
+ s << " }";
+ s << " };" << endl;
+ }
+ s << endl;
+ s << "const CData *DATA_LIST[] = {" << endl;
+ uint i = 0;
+ it = _map.begin();
+ for (; it!=_map.end(); ++it) {
+ s << "&PIC" << it.key() << "_DATA,";
+ i++;
+ if ( (i%10)==0 ) s << endl;
+ }
+ s << "0 " << endl;
+ s << "};" << endl;
+
+ // functions
+ s << endl;
+ s << "const CData *cdata(const QString &device)" << endl;
+ s << "{" << endl;
+ s << " for(uint i=0; DATA_LIST[i]; i++)" << endl;
+ s << " if ( device==DATA_LIST[i]->name ) return DATA_LIST[i];" << endl;
+ s << " return 0;" << endl;
+ s << "}" << endl;
+ s << "bool isSupported(const QString &device)" << endl;
+ s << "{" << endl;
+ s << " return cdata(device);" << endl;
+ s << "}" << endl;
+ if ( hasFamilies() ) {
+ s << "uint family(const QString &device)" << endl;
+ s << "{" << endl;
+ s << " return cdata(device)->family;" << endl;
+ s << "}" << endl;
+ }
+ s << "::Group::Support support(const QString &device)" << endl;
+ s << "{" << endl;
+ s << " return ::Group::Support::Type(cdata(device)->support);" << endl;
+ s << "}" << endl;
+ s << "const Data &data(const QString &device)" << endl;
+ s << "{" << endl;
+ s << " return cdata(device)->data;" << endl;
+ s << "}" << endl;
+ s << endl;
+ outputFunctions(s);
+ s << endl;
+ s << "}" << endl;
+}
+
+//----------------------------------------------------------------------------
+namespace Programmer
+{
+template <class Data>
+class XmlToData : public ExtXmlToData<Data>
+{
+public:
+ XmlToData(const QString &basename, const QString &namespac)
+ : ExtXmlToData<Data>(basename, namespac) {}
+
+protected:
+ virtual void outputFunctions(QTextStream &s) const;
+ virtual void includes(QTextStream &) const;
+};
+
+template <class Data>
+void Programmer::XmlToData<Data>::outputFunctions(QTextStream &s) const
+{
+ s << "void Group::initSupported()" << endl;
+ s << "{" << endl;
+ s << " for (uint i=0; DATA_LIST[i]; i++) {" << endl;
+ s << " const Device::Data *data = Device::lister().data(DATA_LIST[i]->name);" << endl;
+ s << " addDevice(data->name(), data, ::Group::Support::Type(DATA_LIST[i]->support));" << endl;
+ s << " }" << endl;
+ s << "}" << endl;
+ s << endl;
+}
+
+template <class Data>
+void Programmer::XmlToData<Data>::includes(QTextStream &s) const
+{
+ s << "#include \"" << ExtXmlToData<Data>::_basename << "_prog.h\"" << endl;
+}
+
+} // namespace
+
+#endif
diff --git a/src/xml_to_data/xml_to_data.cpp b/src/xml_to_data/xml_to_data.cpp
new file mode 100644
index 0000000..d31ded0
--- /dev/null
+++ b/src/xml_to_data/xml_to_data.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#include "xml_to_data.h"
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+QDomElement XmlToData::findUniqueElement(QDomElement parent, const QString &tag,
+ const QString &attribute, const QString &value) const
+{
+ QDomElement element;
+ QDomNode child = parent.firstChild();
+ while ( !child.isNull() ) {
+ if ( child.nodeName()==tag && child.isElement()
+ && (attribute.isEmpty() || child.toElement().attribute(attribute)==value) ) {
+ if ( !element.isNull() ) qFatal(QString("Duplicated element \"%1/%2\"").arg(tag).arg(value));
+ element = child.toElement();
+ }
+ child = child.nextSibling();
+ }
+ return element;
+}
+
+void XmlToData::checkTagNames(QDomElement element, const QString &tag,
+ const QStringList &names) const
+{
+ QDomNodeList list = element.elementsByTagName(tag);
+ for (uint i=0; i<uint(list.count()); i++) {
+ if ( !list.item(i).isElement() ) continue;
+ QString name = list.item(i).toElement().attribute("name");
+ if ( names.find(name)==names.end() ) qFatal(QString("Illegal name %1 for %2 element").arg(name).arg(tag));
+ }
+}
+
+QDomDocument XmlToData::parseFile(const QString &filename) const
+{
+ qDebug("Parsing XML file \"%s\"...", filename.latin1());
+ QFile file(filename);
+ if ( !file.open(IO_ReadOnly) ) qFatal("Cannot open file!");
+ QDomDocument doc;
+ QString error;
+ int errorLine, errorColumn;
+ if ( !doc.setContent(&file, false, &error, &errorLine, &errorColumn) )
+ qFatal(QString("Error parsing XML file (%1 at line %2, column %3)").arg(error).arg(errorLine).arg(errorColumn));
+ return doc;
+}
+
+void XmlToData::warning(const QString &message) const
+{
+ if ( currentDevice().isEmpty() ) ::qWarning("Warning: %s", message.latin1());
+ else ::qWarning("Warning [%s]: %s", currentDevice().latin1(), message.latin1());
+}
+void XmlToData::qFatal(const QString &message) const
+{
+ if ( currentDevice().isEmpty() ) ::qFatal("Fatal: %s", message.latin1());
+ else ::qFatal("Fatal [%s]: %s", currentDevice().latin1(), message.latin1());
+}
+
+void XmlToData::process()
+{
+ parse();
+ qDebug("Parsing XML successful.");
+ output();
+ qDebug("Output written.");
+}
diff --git a/src/xml_to_data/xml_to_data.h b/src/xml_to_data/xml_to_data.h
new file mode 100644
index 0000000..bd7e166
--- /dev/null
+++ b/src/xml_to_data/xml_to_data.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#ifndef XML_TO_DATA_H
+#define XML_TO_DATA_H
+
+#include "common/global/global.h"
+#if QT_VERSION<0x040000
+# include <qdom.h>
+#else
+# include <QtXml/QDomDocument>
+#endif
+#include <qstringlist.h>
+
+class XmlToData
+{
+public:
+ XmlToData() {}
+ virtual ~XmlToData() {}
+ void process();
+
+protected:
+ virtual void parse() = 0;
+ virtual void output() = 0;
+ virtual QString currentDevice() const = 0;
+ virtual void warning(const QString &message) const;
+ virtual void qFatal(const QString &message) const;
+ QDomElement findUniqueElement(QDomElement parent, const QString &nodeName,
+ const QString &attribute, const QString &value) const;
+ void checkTagNames(QDomElement element, const QString &tag, const QStringList &names) const;
+ QDomDocument parseFile(const QString &filename) const;
+};
+
+#define XML_MAIN(_type) \
+ int main(int, char **) \
+ { \
+ _type dx; \
+ dx.process(); \
+ return 0; \
+ }
+
+#endif
diff --git a/src/xml_to_data/xml_to_data.pro b/src/xml_to_data/xml_to_data.pro
new file mode 100644
index 0000000..0f6e151
--- /dev/null
+++ b/src/xml_to_data/xml_to_data.pro
@@ -0,0 +1,6 @@
+STOPDIR = ../..
+include($${STOPDIR}/lib.pro)
+
+TARGET = xmltodata
+HEADERS += xml_to_data.h device_xml_to_data.h prog_xml_to_data.h
+SOURCES += xml_to_data.cpp device_xml_to_data.cpp