/* Copyright (C) 2010 George Kiagiadakis Copyright (C) 2010 Collabora Ltd. @author George Kiagiadakis This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "generator.h" #include #include #include #include extern int yylineno; int yyparse(CodeGen *codegen); void yyrestart(FILE *file); QHash > CodeGen::s_wrapperDefinitions; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTextStream outStream(stdout); outStream << "// Autogenerated by the QtGStreamer helper code generator - DO NOT EDIT" << endl << "/*" << endl << " Copyright (C) 2010 George Kiagiadakis " << endl << " Copyright (C) 2010 Collabora Ltd." << endl << " @author George Kiagiadakis " << endl << endl << " This library is free software; you can redistribute it and/or modify" << endl << " it under the terms of the GNU Lesser General Public License as published" << endl << " by the Free Software Foundation; either version 2.1 of the License, or" << endl << " (at your option) any later version." << endl << endl << " This program is distributed in the hope that it will be useful," << endl << " but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl << " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << endl << " GNU Lesser General Public License for more details." << endl << endl << " You should have received a copy of the GNU Lesser General Public License" << endl << " along with this program. If not, see ." << endl << "*/" << endl << endl << "#define INCLUDED_FROM_CODEGEN" << endl << "#include " << endl << endl << "#define REGISTER_TYPE_IMPLEMENTATION(T, GTYPE) \\" << endl << " namespace QGlib { \\" << endl << " GetTypeImpl::operator Type() { return (GTYPE); } \\" << endl << " }" << endl << endl; for (int i=1; i" << endl; } else if (fileName.endsWith(".h") && QFile::exists(fileName)) { CodeGen::parse(fileName, outStream); } else { QTextStream(stderr) << "Skipping " << fileName << ": Not an existing header" << endl; } } CodeGen::printGlobalWrapperDefinitions(outStream); return 0; } void CodeGen::parse(const QString & fileName, QTextStream & outStream) { CodeGen codegen(fileName); FILE *fp = std::fopen(QFile::encodeName(fileName), "r"); if (!fp) { std::perror("fopen"); QTextStream(stderr) << "Could not open " << fileName << endl; return; } yylineno = 1; yyrestart(fp); yyparse(&codegen); std::fclose(fp); codegen.generateOutput(outStream); } void CodeGen::generateOutput(QTextStream & outStream) { outStream << "#include \"" << m_fileName << "\"" << endl << endl; foreach(const QByteArrayHash & typeReg, m_typeRegistrations) { printTypeRegistration(outStream, typeReg); outStream << endl; } foreach(const QByteArrayHash & def, m_wrapperDefinitions) { printWrapperDefinition(outStream, def); outStream << endl; } foreach(const Enum & enumDef, m_enums) { if (!enumDef.options.contains("skip")) { printEnumAssertions(outStream, enumDef); } outStream << endl; } } void CodeGen::printTypeRegistration(QTextStream & outStream, const QByteArrayHash & typeReg) { outStream << "REGISTER_TYPE_IMPLEMENTATION("; outStream << typeReg["namespace"] << "::" << typeReg["class"]; if (!typeReg["enum"].isEmpty()) { outStream << "::" << typeReg["enum"]; } outStream << ','; if (typeReg.contains("GType")) { outStream << typeReg["GType"]; } else { outStream << namespaceToGstStyle(typeReg["namespace"]) << "_TYPE_"; outStream << toGstStyle(typeReg["enum"].isEmpty() ? typeReg["class"] : typeReg["enum"]); } outStream << ")" << endl; } void CodeGen::printEnumAssertions(QTextStream& outStream, const Enum & enumDef) { outStream << "namespace " << enumDef.options["namespace"] << " {" << endl; foreach(const QByteArray & value, enumDef.values) { outStream << " BOOST_STATIC_ASSERT(static_cast("; if (enumDef.options.contains("class") && !enumDef.options["class"].isEmpty()) { outStream << enumDef.options["class"] << "::"; } outStream << value; outStream << ") == static_cast("; if (enumDef.options.contains("prefix")) { outStream << enumDef.options["prefix"]; } else { outStream << namespaceToGstStyle(enumDef.options["namespace"]) << "_"; if (enumDef.options.contains("class") && !enumDef.options["class"].isEmpty()) { outStream << toGstStyle(enumDef.options["class"]) << "_"; } } if (enumDef.options.contains(value)) { outStream << enumDef.options[value]; } else { outStream << toGstStyle(value); } outStream << "));" << endl; } outStream << "}" << endl; } void CodeGen::printWrapperDefinition(QTextStream& outStream, const QByteArrayHash & def) { //This function is not printed inside namespace Private because it needs to be friend //with the actual class and we cannot declare a friend from another namespace in the //class without a forward declaration. outStream << "namespace " << def["namespace"] << " {" << endl; outStream << " QGlib::RefCountedObject *" << def["class"] << "_new(void *instance)" << endl; outStream << " {" << endl; QByteArrayPair index = qMakePair(def["namespace"], def["class"]); if (m_wrapperSubclasses.contains(index)) { outStream << " "<< def["namespace"] << "::" << def["class"] << " *cppClass = NULL;" << endl; outStream << " switch(" << namespaceToGstStyle(def["namespace"]) << "_" << toGstStyle(def["class"]) << "_" << "TYPE(instance)) {" << endl; Q_FOREACH(const QByteArrayHash & subclass, m_wrapperSubclasses[index]) { outStream << " case " << def["namespace"] << "::" << def["class"] << subclass["prefix"] << ":" << endl; outStream << " cppClass = new " << def["namespace"] << "::" << subclass["prefix"] << def["class"] << ";" << endl; outStream << " break;" << endl; } outStream << " default:" << endl; outStream << " cppClass = new " << def["namespace"] << "::" << def["class"] << ";" << endl; outStream << " break;" << endl; outStream << " }" << endl; } else { outStream << " " << def["namespace"] << "::" << def["class"] << " *cppClass = new " << def["namespace"] << "::" << def["class"] << ";" << endl; } outStream << " cppClass->m_object = instance;" << endl; outStream << " return cppClass;" << endl; outStream << " }" << endl; outStream << "} //namespace " << def["namespace"] << endl; s_wrapperDefinitions[def["namespace"]].append(def["class"]); } void CodeGen::printGlobalWrapperDefinitions(QTextStream & outStream) { QHashIterator > it(s_wrapperDefinitions); while (it.hasNext()) { it.next(); outStream << "namespace " << it.key() << " {" << endl; outStream << "namespace Private {" << endl; outStream << " void registerWrapperConstructors()" << endl; outStream << " {" << endl; outStream << " QGlib::Quark q = g_quark_from_static_string(\"QGlib__wrapper_constructor\");" << endl; Q_FOREACH(const QByteArray & classId, it.value()) { outStream << " QGlib::GetType<" << classId << ">()" << ".setQuarkData(q, reinterpret_cast(&" << classId << "_new));" << endl; } outStream << " }" << endl; outStream << "} //namespace Private" << endl; outStream << "} //namespace " << it.key() << endl << endl; } s_wrapperDefinitions.clear(); } QByteArray CodeGen::toGstStyle(const QByteArray & str) { QByteArray output; foreach(const char currentChar, str) { if (isupper(currentChar)) { if (!output.isEmpty()) { //if this is not the first char output.append('_'); } output.append(currentChar); } else { output.append(toupper(currentChar)); } } return output; } QByteArray CodeGen::namespaceToGstStyle(const QByteArray & ns) { return ns == "QGst" ? "GST" : "G"; } void CodeGen::addEnum(const QList & values, const QByteArrayHash & options) { Enum e; e.values = values; e.options = options; e.options["namespace"] = m_currentNamespace; e.options["class"] = m_currentClass; m_enums.append(e); } void CodeGen::addTypeRegistration(const QByteArray& namespaceId, const QByteArray& classId, const QByteArray& enumId, const QByteArrayHash & options) { QByteArrayHash typeReg(options); typeReg["namespace"] = namespaceId; typeReg["class"] = classId; typeReg["enum"] = enumId; m_typeRegistrations.append(typeReg); } void CodeGen::addWrapperDefinition(const QByteArray & classId, const QByteArrayHash & options) { QByteArrayHash def(options); def["namespace"] = m_currentNamespace; def["class"] = classId; m_wrapperDefinitions.append(def); } void CodeGen::addWrapperFakeSubclass(const QByteArray & prefix, const QByteArray & classId, const QByteArrayHash & options) { QByteArrayHash sub(options); sub["prefix"] = prefix; m_wrapperSubclasses[qMakePair(m_currentNamespace, classId)].append(sub); } //called by yyerror() void CodeGen::fatalError(const char* msg) { QTextStream(stderr) << "codegen: " << m_fileName << ":" << yylineno << ": error: " << msg << endl; std::exit(1); }