diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 18:42:24 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 18:42:24 +0000 |
commit | f508189682b6fba62e08feeb1596f682bad5fff9 (patch) | |
tree | 28aeb0e6c19386c385c1ce5edf8a92c1bca15281 /src/xml_to_data | |
download | piklab-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.am | 7 | ||||
-rw-r--r-- | src/xml_to_data/device_xml_to_data.cpp | 260 | ||||
-rw-r--r-- | src/xml_to_data/device_xml_to_data.h | 88 | ||||
-rw-r--r-- | src/xml_to_data/prog_xml_to_data.h | 218 | ||||
-rw-r--r-- | src/xml_to_data/xml_to_data.cpp | 71 | ||||
-rw-r--r-- | src/xml_to_data/xml_to_data.h | 47 | ||||
-rw-r--r-- | src/xml_to_data/xml_to_data.pro | 6 |
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 |