blob: 4b2ecc70562a7e84cb6b1d50bb50d5ee3df9151c [file] [log] [blame]
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <iostream>
18#include <sstream>
19
20#include "Generator.h"
21#include "Specification.h"
22#include "Utilities.h"
23
24using namespace std;
25
26// Convert a file name into a string that can be used to guard the include file with #ifdef...
27static string makeGuardString(const string& filename) {
28 string s;
29 s.resize(15 + filename.size());
30 s = "RENDERSCRIPT_";
31 for (char c : filename) {
32 if (c == '.') {
33 s += '_';
34 } else {
35 s += toupper(c);
36 }
37 }
38 return s;
39}
40
41// Write #ifdef's that ensure that the specified version is present
42static void writeVersionGuardStart(GeneratedFile* file, VersionInfo info) {
43 if (info.intSize == 32) {
44 *file << "#ifndef __LP64__\n";
45 } else if (info.intSize == 64) {
46 *file << "#ifdef __LP64__\n";
47 }
48
49 if (info.minVersion <= 1) {
50 // No minimum
51 if (info.maxVersion > 0) {
52 *file << "#if !defined(RS_VERSION) || (RS_VERSION <= " << info.maxVersion << ")\n";
53 }
54 } else {
55 if (info.maxVersion == 0) {
56 // No maximum
57 *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion << "))\n";
58 } else {
59 *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion
60 << ") && (RS_VERSION <= " << info.maxVersion << "))\n";
61 }
62 }
63}
64
65static void writeVersionGuardEnd(GeneratedFile* file, VersionInfo info) {
66 if (info.minVersion > 1 || info.maxVersion != 0) {
67 *file << "#endif\n";
68 }
69 if (info.intSize != 0) {
70 *file << "#endif\n";
71 }
72}
73
74static void writeComment(GeneratedFile* file, const string& name, const string& briefComment,
75 const vector<string>& comment, bool closeBlock) {
76 if (briefComment.empty() && comment.size() == 0) {
77 return;
78 }
79 *file << "/*\n";
80 if (!briefComment.empty()) {
81 *file << " * " << name << ": " << briefComment << "\n";
82 *file << " *\n";
83 }
84 for (size_t ct = 0; ct < comment.size(); ct++) {
85 string s = stripHtml(comment[ct]);
86 s = stringReplace(s, "@", "");
87 if (!s.empty()) {
88 *file << " * " << s << "\n";
89 } else {
90 *file << " *\n";
91 }
92 }
93 if (closeBlock) {
94 *file << " */\n";
95 }
96}
97
98static void writeConstant(GeneratedFile* file, const Constant& constant) {
99 const string name = constant.getName();
100 writeComment(file, name, constant.getSummary(), constant.getDescription(), true);
101
102 for (auto spec : constant.getSpecifications()) {
103 VersionInfo info = spec->getVersionInfo();
104 writeVersionGuardStart(file, info);
105 *file << "#define " << name << " " << spec->getValue() << "\n";
106 writeVersionGuardEnd(file, info);
107 }
108 *file << "\n";
109}
110
111static void writeTypeSpecification(GeneratedFile* file, const string& typeName,
112 const TypeSpecification& spec) {
113 const VersionInfo info = spec.getVersionInfo();
114 writeVersionGuardStart(file, info);
115 switch (spec.getKind()) {
116 case SIMPLE:
117 *file << "typedef " << spec.getSimpleType() << " " << typeName << ";\n";
118 break;
119 case ENUM: {
120 *file << "typedef enum ";
121 const string name = spec.getEnumName();
122 if (!name.empty()) {
123 *file << name << " ";
124 }
125 *file << "{\n";
126
127 const vector<string>& values = spec.getValues();
128 const vector<string>& valueComments = spec.getValueComments();
129 const size_t last = values.size() - 1;
130 for (size_t i = 0; i <= last; i++) {
131 *file << " " << values[i];
132 if (i != last) {
133 *file << ",";
134 }
135 if (valueComments.size() > i && !valueComments[i].empty()) {
136 *file << " // " << valueComments[i];
137 }
138 *file << "\n";
139 }
140 *file << "} " << typeName << ";\n";
141 break;
142 }
143 case STRUCT: {
144 *file << "typedef struct ";
145 const string name = spec.getStructName();
146 if (!name.empty()) {
147 *file << name << " ";
148 }
149 *file << "{\n";
150
151 const vector<string>& fields = spec.getFields();
152 const vector<string>& fieldComments = spec.getFieldComments();
153 for (size_t i = 0; i < fields.size(); i++) {
154 *file << " " << fields[i] << ";";
155 if (fieldComments.size() > i && !fieldComments[i].empty()) {
156 *file << " // " << fieldComments[i];
157 }
158 *file << "\n";
159 }
160 *file << "} ";
161 const string attrib = spec.getAttrib();
162 if (!attrib.empty()) {
163 *file << attrib << " ";
164 }
165 *file << typeName << ";\n";
166 break;
167 }
168 }
169 writeVersionGuardEnd(file, info);
170 *file << "\n";
171}
172
173static void writeType(GeneratedFile* file, const Type& type) {
174 const string name = type.getName();
175 writeComment(file, name, type.getSummary(), type.getDescription(), true);
176
177 for (auto spec : type.getSpecifications()) {
178 writeTypeSpecification(file, name, *spec);
179 }
180 *file << "\n";
181}
182
183static void writeFunctionPermutation(GeneratedFile* file, const FunctionSpecification& spec,
184 const FunctionPermutation& permutation) {
185 writeVersionGuardStart(file, spec.getVersionInfo());
186
187 // Write linkage info.
188 const auto inlineCodeLines = permutation.getInline();
189 if (inlineCodeLines.size() > 0) {
190 *file << "static inline ";
191 } else {
192 *file << "extern ";
193 }
194
195 // Write the return type.
196 auto ret = permutation.getReturn();
197 if (ret) {
198 *file << ret->rsType;
199 } else {
200 *file << "void";
201 }
202
203 // Write the attribute.
204 *file << " __attribute__((";
205 const string attrib = spec.getAttribute();
206 if (attrib.empty()) {
207 *file << "overloadable";
208 } else if (attrib[0] == '=') {
209 /* If starts with an equal, we don't automatically add overloadable.
210 * This is because of the error we made defining rsUnpackColor8888().
211 */
212 *file << attrib.substr(1);
213 } else {
214 *file << attrib << ", overloadable";
215 }
216 *file << "))\n";
217
218 // Write the function name.
219 *file << " " << permutation.getName() << "(";
220 const int offset = 4 + permutation.getName().size() + 1; // Size of above
221
222 // Write the arguments. We wrap on mulitple lines if a line gets too long.
223 int charsOnLine = offset;
224 bool hasGenerated = false;
225 for (auto p : permutation.getParams()) {
226 if (hasGenerated) {
227 *file << ",";
228 charsOnLine++;
229 }
230 ostringstream ps;
231 ps << p->rsType;
232 if (p->isOutParameter) {
233 ps << "*";
234 }
235 if (!p->specName.empty()) {
236 ps << " " << p->specName;
237 }
238 const string s = ps.str();
239 if (charsOnLine + s.size() >= 100) {
240 *file << "\n" << string(offset, ' ');
241 charsOnLine = offset;
242 } else if (hasGenerated) {
243 *file << " ";
244 charsOnLine++;
245 }
246 *file << s;
247 charsOnLine += s.size();
248 hasGenerated = true;
249 }
250 // In C, if no parameters, we need to output void, e.g. fn(void).
251 if (!hasGenerated) {
252 *file << "void";
253 }
254 *file << ")";
255
256 // Write the inline code, if any.
257 if (inlineCodeLines.size() > 0) {
258 *file << " {\n";
259 for (size_t ct = 0; ct < inlineCodeLines.size(); ct++) {
260 if (inlineCodeLines[ct].empty()) {
261 *file << "\n";
262 } else {
263 *file << " " << inlineCodeLines[ct] << "\n";
264 }
265 }
266 *file << "}\n";
267 } else {
268 *file << ";\n";
269 }
270
271 writeVersionGuardEnd(file, spec.getVersionInfo());
272 *file << "\n";
273}
274
275static void writeFunction(GeneratedFile* file, const Function& function) {
276 // Write the generic documentation.
277 writeComment(file, function.getName(), function.getSummary(), function.getDescription(), false);
278
279 // Comment the parameters.
280 if (function.someParametersAreDocumented()) {
281 *file << " *\n";
282 *file << " * Parameters:\n";
283 for (auto p : function.getParameters()) {
284 if (!p->documentation.empty()) {
285 *file << " * " << p->name << " " << p->documentation << "\n";
286 }
287 }
288 }
289
290 // Comment the return type.
291 const string returnDoc = function.getReturnDocumentation();
292 if (!returnDoc.empty()) {
293 *file << " *\n";
294 *file << " * Returns: " << returnDoc << "\n";
295 }
296
297 *file << " */\n";
298
299 // Write all the variants.
300 for (auto spec : function.getSpecifications()) {
301 for (auto permutation : spec->getPermutations()) {
302 writeFunctionPermutation(file, *spec, *permutation);
303 }
304 }
305}
306
307static bool writeHeaderFile(const SpecFile& specFile) {
308 const string headerFileName = specFile.getHeaderFileName();
309
310 // We generate one header file for each spec file.
311 GeneratedFile file;
312 if (!file.start(headerFileName)) {
313 return false;
314 }
315
316 // Write the comments that start the file.
317 file.writeNotices();
318 writeComment(&file, headerFileName, specFile.getBriefDescription(),
319 specFile.getFullDescription(), true);
320
321 // Write the ifndef that prevents the file from being included twice.
322 const string guard = makeGuardString(headerFileName);
323 file << "#ifndef " << guard << "\n";
324 file << "#define " << guard << "\n\n";
325
326 // Add lines that need to be put in "as is".
327 if (specFile.getVerbatimInclude().size() > 0) {
328 for (auto s : specFile.getVerbatimInclude()) {
329 file << s << "\n";
330 }
331 file << "\n";
332 }
333
334 /* Write the constants, types, and functions in the same order as
335 * encountered in the spec file.
336 */
337 for (auto iter : specFile.getConstantsList()) {
338 writeConstant(&file, *iter);
339 }
340 for (auto iter : specFile.getTypesList()) {
341 writeType(&file, *iter);
342 }
343 for (auto iter : specFile.getFunctionsList()) {
344 writeFunction(&file, *iter);
345 }
346
347 file << "#endif // " << guard << "\n";
348 file.close();
349 return true;
350}
351
352bool GenerateHeaderFiles() {
353 bool success = true;
354 for (auto specFile : systemSpecification.getSpecFiles()) {
355 if (!writeHeaderFile(*specFile)) {
356 success = false;
357 }
358 }
359 return success;
360}