Initial commit of the QtGstreamer helper code generator.
[qtgstreamer:qtgstreamer.git] / codegen / generator.cpp
1 /*
2     Copyright (C) 2010  George Kiagiadakis <kiagiadakis.george@gmail.com>
3
4     This library is free software; you can redistribute it and/or modify
5     it under the terms of the GNU Lesser General Public License as published
6     by the Free Software Foundation; either version 2.1 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU Lesser General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "generator.h"
18 #include <cstdio>
19 #include <cstdlib>
20 #include <QtCore/QCoreApplication>
21 #include <QtCore/QFile>
22
23 extern int yylineno;
24 int yyparse(CodeGen *codegen);
25 void yyrestart(FILE *file);
26
27 int main(int argc, char *argv[])
28 {
29     QCoreApplication a(argc, argv);
30     QTextStream(stdout) << "// Autogenerated by the QtGstreamer helper code generator" << endl
31                         << "#include <gst/gst.h>" << endl
32                         << "#include <boost/static_assert.hpp>" << endl << endl;
33
34     for (int i=1; i<argc; ++i) {
35         QString fileName(QFile::decodeName(argv[i]));
36         if (fileName.endsWith(".h") && QFile::exists(fileName)) {
37             CodeGen::parse(fileName);
38         } else {
39             QTextStream(stderr) << "Skipping " << fileName << ": Not an existing header" << endl;
40         }
41     }
42
43     return 0;
44 }
45
46 void CodeGen::parse(const QString & fileName)
47 {
48     CodeGen codegen(fileName);
49
50     FILE *fp = std::fopen(QFile::encodeName(fileName), "r");
51     if (!fp) {
52         std::perror("fopen");
53         QTextStream(stderr) << "Could not open " << fileName << endl;
54         return;
55     }
56
57     yylineno = 1;
58     yyrestart(fp);
59     yyparse(&codegen);
60     std::fclose(fp);
61
62     codegen.generateOutput();
63 }
64
65 void CodeGen::generateOutput()
66 {
67     QTextStream outStream(stdout);
68     outStream << "#include \"" << m_fileName << "\"" << endl << endl;
69
70     foreach(const TypeRegistration & typeReg, m_typeRegistrations) {
71         printTypeRegistration(outStream, typeReg);
72         outStream << endl;
73     }
74
75     foreach(const Enum & enumDef, m_enums) {
76         if (!enumDef.options.contains("skip")) {
77             printEnumAssertions(outStream, enumDef);
78         }
79         outStream << endl;
80     }
81 }
82
83 void CodeGen::printTypeRegistration(QTextStream & outStream, const TypeRegistration & typeReg)
84 {
85     outStream << "QGLIB_REGISTER_TYPE_IMPLEMENTATION(";
86
87     outStream << typeReg["namespace"] << "::" << typeReg["class"];
88     if (!typeReg["enum"].isEmpty()) {
89         outStream << "::" << typeReg["enum"];
90     }
91
92     outStream << ',';
93
94     if (typeReg.contains("GType")) {
95         outStream << typeReg["GType"];
96     } else {
97         outStream << (typeReg["namespace"] == "QGst" ? "GST_TYPE_" : "G_TYPE_");
98         outStream << toGstStyle(typeReg["enum"].isEmpty() ? typeReg["class"] : typeReg["enum"]);
99     }
100     outStream << ")" << endl;
101 }
102
103 void CodeGen::printEnumAssertions(QTextStream& outStream, const Enum & enumDef)
104 {
105     outStream << "namespace " << enumDef.options["namespace"] << " {" << endl;
106
107     foreach(const QByteArray & value, enumDef.values) {
108         outStream << "    BOOST_STATIC_ASSERT(static_cast<int>(";
109         outStream << enumDef.options["class"] << "::" << value;
110         outStream << ") == static_cast<int>(";
111
112         if (enumDef.options.contains("prefix")) {
113             outStream << enumDef.options["prefix"];
114         } else {
115             outStream << (enumDef.options["namespace"] == "QGst" ? "GST_TYPE_" : "G_TYPE_");
116         }
117
118         if (enumDef.options.contains(value)) {
119             outStream << enumDef.options[value];
120         } else {
121             outStream << toGstStyle(value);
122         }
123         outStream << "));" << endl;
124     }
125     outStream << "}" << endl;
126 }
127
128 QByteArray CodeGen::toGstStyle(const QByteArray & str)
129 {
130     QByteArray output;
131     foreach(const char currentChar, str) {
132         if (isupper(currentChar)) {
133             if (!output.isEmpty()) { //if this is not the first char
134                 output.append('_');
135             }
136             output.append(currentChar);
137         } else {
138             output.append(toupper(currentChar));
139         }
140     }
141     return output;
142 }
143
144
145 void CodeGen::addEnum(const QList<QByteArray> & values, const QHash<QByteArray, QByteArray> & options)
146 {
147     Enum e;
148     e.values = values;
149     e.options = options;
150     e.options["namespace"] = m_currentNamespace;
151     e.options["class"] = m_currentClass;
152     m_enums.append(e);
153 }
154
155 void CodeGen::addTypeRegistration(const QByteArray& namespaceId, const QByteArray& classId,
156                                  const QByteArray& enumId, const QHash<QByteArray, QByteArray>& options)
157 {
158     TypeRegistration typeReg(options);
159     typeReg["namespace"] = namespaceId;
160     typeReg["class"] = classId;
161     typeReg["enum"] = enumId;
162     m_typeRegistrations.append(typeReg);
163 }
164
165 //called by yyerror()
166 void CodeGen::fatalError(const char* msg)
167 {
168     QTextStream(stderr) << "codegen: " << m_fileName << ":" << yylineno << ": error: " << msg << endl;
169     std::exit(1);
170 }
171