Add a new QtGstreamerUi library that contains a VideoWidget class, a widget that...
[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 outStream(stdout);
31     outStream << "// Autogenerated by the QtGstreamer helper code generator" << endl
32               << "#include <boost/static_assert.hpp>" << endl;
33
34     for (int i=1; i<argc; ++i) {
35         QString fileName(QFile::decodeName(argv[i]));
36         if (fileName.startsWith("-I")) {
37             outStream << "#include <" << fileName.remove(0, 2) << ">" << endl;
38         } else if (fileName.endsWith(".h") && QFile::exists(fileName)) {
39             CodeGen::parse(fileName);
40         } else {
41             QTextStream(stderr) << "Skipping " << fileName << ": Not an existing header" << endl;
42         }
43     }
44
45     return 0;
46 }
47
48 void CodeGen::parse(const QString & fileName)
49 {
50     CodeGen codegen(fileName);
51
52     FILE *fp = std::fopen(QFile::encodeName(fileName), "r");
53     if (!fp) {
54         std::perror("fopen");
55         QTextStream(stderr) << "Could not open " << fileName << endl;
56         return;
57     }
58
59     yylineno = 1;
60     yyrestart(fp);
61     yyparse(&codegen);
62     std::fclose(fp);
63
64     codegen.generateOutput();
65 }
66
67 void CodeGen::generateOutput()
68 {
69     QTextStream outStream(stdout);
70     outStream << "#include \"" << m_fileName << "\"" << endl << endl;
71
72     foreach(const TypeRegistration & typeReg, m_typeRegistrations) {
73         printTypeRegistration(outStream, typeReg);
74         outStream << endl;
75     }
76
77     foreach(const Enum & enumDef, m_enums) {
78         if (!enumDef.options.contains("skip")) {
79             printEnumAssertions(outStream, enumDef);
80         }
81         outStream << endl;
82     }
83 }
84
85 void CodeGen::printTypeRegistration(QTextStream & outStream, const TypeRegistration & typeReg)
86 {
87     outStream << "QGLIB_REGISTER_TYPE_IMPLEMENTATION(";
88
89     outStream << typeReg["namespace"] << "::" << typeReg["class"];
90     if (!typeReg["enum"].isEmpty()) {
91         outStream << "::" << typeReg["enum"];
92     }
93
94     outStream << ',';
95
96     if (typeReg.contains("GType")) {
97         outStream << typeReg["GType"];
98     } else {
99         outStream << (typeReg["namespace"] == "QGst" ? "GST_TYPE_" : "G_TYPE_");
100         outStream << toGstStyle(typeReg["enum"].isEmpty() ? typeReg["class"] : typeReg["enum"]);
101     }
102     outStream << ")" << endl;
103 }
104
105 void CodeGen::printEnumAssertions(QTextStream& outStream, const Enum & enumDef)
106 {
107     outStream << "namespace " << enumDef.options["namespace"] << " {" << endl;
108
109     foreach(const QByteArray & value, enumDef.values) {
110         outStream << "    BOOST_STATIC_ASSERT(static_cast<int>(";
111         if (enumDef.options.contains("class") && !enumDef.options["class"].isEmpty()) {
112             outStream << enumDef.options["class"] << "::";
113         }
114         outStream << value;
115         outStream << ") == static_cast<int>(";
116
117         if (enumDef.options.contains("prefix")) {
118             outStream << enumDef.options["prefix"];
119         } else {
120             outStream << (enumDef.options["namespace"] == "QGst" ? "GST_" : "G_");
121             if (enumDef.options.contains("class") && !enumDef.options["class"].isEmpty()) {
122                 outStream << toGstStyle(enumDef.options["class"]) << "_";
123             }
124         }
125
126         if (enumDef.options.contains(value)) {
127             outStream << enumDef.options[value];
128         } else {
129             outStream << toGstStyle(value);
130         }
131         outStream << "));" << endl;
132     }
133     outStream << "}" << endl;
134 }
135
136 QByteArray CodeGen::toGstStyle(const QByteArray & str)
137 {
138     QByteArray output;
139     foreach(const char currentChar, str) {
140         if (isupper(currentChar)) {
141             if (!output.isEmpty()) { //if this is not the first char
142                 output.append('_');
143             }
144             output.append(currentChar);
145         } else {
146             output.append(toupper(currentChar));
147         }
148     }
149     return output;
150 }
151
152
153 void CodeGen::addEnum(const QList<QByteArray> & values, const QHash<QByteArray, QByteArray> & options)
154 {
155     Enum e;
156     e.values = values;
157     e.options = options;
158     e.options["namespace"] = m_currentNamespace;
159     e.options["class"] = m_currentClass;
160     m_enums.append(e);
161 }
162
163 void CodeGen::addTypeRegistration(const QByteArray& namespaceId, const QByteArray& classId,
164                                  const QByteArray& enumId, const QHash<QByteArray, QByteArray>& options)
165 {
166     TypeRegistration typeReg(options);
167     typeReg["namespace"] = namespaceId;
168     typeReg["class"] = classId;
169     typeReg["enum"] = enumId;
170     m_typeRegistrations.append(typeReg);
171 }
172
173 //called by yyerror()
174 void CodeGen::fatalError(const char* msg)
175 {
176     QTextStream(stderr) << "codegen: " << m_fileName << ":" << yylineno << ": error: " << msg << endl;
177     std::exit(1);
178 }
179