• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
24 using namespace std;
25 
26 // Convert a file name into a string that can be used to guard the include file with #ifdef...
makeGuardString(const string & filename)27 static 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.  If we're at the final version,
42  * add a check on a flag that can be set for internal builds.  This enables us to keep supporting
43  * old APIs in the runtime code.
44  */
writeVersionGuardStart(GeneratedFile * file,VersionInfo info,int finalVersion)45 static void writeVersionGuardStart(GeneratedFile* file, VersionInfo info, int finalVersion) {
46     if (info.intSize == 32) {
47         *file << "#ifndef __LP64__\n";
48     } else if (info.intSize == 64) {
49         *file << "#ifdef __LP64__\n";
50     }
51 
52     ostringstream checkMaxVersion;
53     if (info.maxVersion > 0) {
54         checkMaxVersion << "(";
55         if (info.maxVersion == finalVersion) {
56             checkMaxVersion << "defined(RS_DECLARE_EXPIRED_APIS) || ";
57         }
58         checkMaxVersion << "RS_VERSION <= " << info.maxVersion << ")";
59     }
60 
61     if (info.minVersion <= 1) {
62         // No minimum
63         if (info.maxVersion > 0) {
64             *file << "#if !defined(RS_VERSION) || " << checkMaxVersion.str() << "\n";
65         }
66     } else {
67         *file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << info.minVersion << ")";
68         if (info.maxVersion > 0) {
69             *file << " && " << checkMaxVersion.str();
70         }
71         *file << ")\n";
72     }
73 }
74 
writeVersionGuardEnd(GeneratedFile * file,VersionInfo info)75 static void writeVersionGuardEnd(GeneratedFile* file, VersionInfo info) {
76     if (info.minVersion > 1 || info.maxVersion != 0) {
77         *file << "#endif\n";
78     }
79     if (info.intSize != 0) {
80         *file << "#endif\n";
81     }
82 }
83 
writeComment(GeneratedFile * file,const string & name,const string & briefComment,const vector<string> & comment,bool addDeprecatedWarning,bool closeBlock)84 static void writeComment(GeneratedFile* file, const string& name, const string& briefComment,
85                          const vector<string>& comment, bool addDeprecatedWarning,
86                          bool closeBlock) {
87     if (briefComment.empty() && comment.size() == 0) {
88         return;
89     }
90     *file << "/*\n";
91     if (!briefComment.empty()) {
92         *file << " * " << name << ": " << briefComment << "\n";
93         *file << " *\n";
94     }
95     if (addDeprecatedWarning) {
96         *file << " * DEPRECATED.  Do not use.\n";
97         *file << " *\n";
98     }
99     for (size_t ct = 0; ct < comment.size(); ct++) {
100         string s = stripHtml(comment[ct]);
101         s = stringReplace(s, "@", "");
102         if (!s.empty()) {
103             *file << " * " << s << "\n";
104         } else {
105             *file << " *\n";
106         }
107     }
108     if (closeBlock) {
109         *file << " */\n";
110     }
111 }
112 
writeConstantComment(GeneratedFile * file,const Constant & constant)113 static void writeConstantComment(GeneratedFile* file, const Constant& constant) {
114     const string name = constant.getName();
115     writeComment(file, name, constant.getSummary(), constant.getDescription(),
116                  constant.deprecated(), true);
117 }
118 
writeConstantSpecification(GeneratedFile * file,const ConstantSpecification & spec)119 static void writeConstantSpecification(GeneratedFile* file, const ConstantSpecification& spec) {
120     const Constant* constant = spec.getConstant();
121     VersionInfo info = spec.getVersionInfo();
122     writeVersionGuardStart(file, info, constant->getFinalVersion());
123     *file << "#define " << constant->getName() << " " << spec.getValue() << "\n\n";
124     writeVersionGuardEnd(file, info);
125 }
126 
writeTypeSpecification(GeneratedFile * file,const TypeSpecification & spec)127 static void writeTypeSpecification(GeneratedFile* file, const TypeSpecification& spec) {
128     const Type* type = spec.getType();
129     const string& typeName = type->getName();
130     const VersionInfo info = spec.getVersionInfo();
131     writeVersionGuardStart(file, info, type->getFinalVersion());
132 
133     const string attribute =
134                 makeAttributeTag(spec.getAttribute(), "", type->getDeprecatedApiLevel(),
135                                  type->getDeprecatedMessage());
136     *file << "typedef ";
137     switch (spec.getKind()) {
138         case SIMPLE:
139             *file << spec.getSimpleType() << attribute;
140             break;
141         case ENUM: {
142             *file << "enum" << attribute << " ";
143             const string name = spec.getEnumName();
144             if (!name.empty()) {
145                 *file << name << " ";
146             }
147             *file << "{\n";
148 
149             const vector<string>& values = spec.getValues();
150             const vector<string>& valueComments = spec.getValueComments();
151             const size_t last = values.size() - 1;
152             for (size_t i = 0; i <= last; i++) {
153                 *file << "    " << values[i];
154                 if (i != last) {
155                     *file << ",";
156                 }
157                 if (valueComments.size() > i && !valueComments[i].empty()) {
158                     *file << " // " << valueComments[i];
159                 }
160                 *file << "\n";
161             }
162             *file << "}";
163             break;
164         }
165         case STRUCT: {
166             *file << "struct" << attribute << " ";
167             const string name = spec.getStructName();
168             if (!name.empty()) {
169                 *file << name << " ";
170             }
171             *file << "{\n";
172 
173             const vector<string>& fields = spec.getFields();
174             const vector<string>& fieldComments = spec.getFieldComments();
175             for (size_t i = 0; i < fields.size(); i++) {
176                 *file << "    " << fields[i] << ";";
177                 if (fieldComments.size() > i && !fieldComments[i].empty()) {
178                     *file << " // " << fieldComments[i];
179                 }
180                 *file << "\n";
181             }
182             *file << "}";
183             break;
184         }
185     }
186     *file << " " << typeName << ";\n";
187 
188     writeVersionGuardEnd(file, info);
189     *file << "\n";
190 }
191 
writeTypeComment(GeneratedFile * file,const Type & type)192 static void writeTypeComment(GeneratedFile* file, const Type& type) {
193     const string name = type.getName();
194     writeComment(file, name, type.getSummary(), type.getDescription(), type.deprecated(), true);
195 }
196 
writeFunctionPermutation(GeneratedFile * file,const FunctionSpecification & spec,const FunctionPermutation & permutation)197 static void writeFunctionPermutation(GeneratedFile* file, const FunctionSpecification& spec,
198                                      const FunctionPermutation& permutation) {
199     Function* function = spec.getFunction();
200     writeVersionGuardStart(file, spec.getVersionInfo(), function->getFinalVersion());
201 
202     // Write linkage info.
203     const auto inlineCodeLines = permutation.getInline();
204     if (inlineCodeLines.size() > 0) {
205         *file << "static inline ";
206     } else {
207         *file << "extern ";
208     }
209 
210     // Write the return type.
211     auto ret = permutation.getReturn();
212     if (ret) {
213         *file << ret->rsType;
214     } else {
215         *file << "void";
216     }
217 
218     *file << makeAttributeTag(spec.getAttribute(), "overloadable",
219                               function->getDeprecatedApiLevel(), function->getDeprecatedMessage());
220     *file << "\n";
221 
222     // Write the function name.
223     *file << "    " << permutation.getName() << "(";
224     const int offset = 4 + permutation.getName().size() + 1;  // Size of above
225 
226     // Write the arguments.  We wrap on mulitple lines if a line gets too long.
227     int charsOnLine = offset;
228     bool hasGenerated = false;
229     for (auto p : permutation.getParams()) {
230         if (hasGenerated) {
231             *file << ",";
232             charsOnLine++;
233         }
234         ostringstream ps;
235         ps << p->rsType;
236         if (p->isOutParameter) {
237             ps << "*";
238         }
239         if (!p->specName.empty()) {
240             ps << " " << p->specName;
241         }
242         const string s = ps.str();
243         if (charsOnLine + s.size() >= 100) {
244             *file << "\n" << string(offset, ' ');
245             charsOnLine = offset;
246         } else if (hasGenerated) {
247             *file << " ";
248             charsOnLine++;
249         }
250         *file << s;
251         charsOnLine += s.size();
252         hasGenerated = true;
253     }
254     // In C, if no parameters, we need to output void, e.g. fn(void).
255     if (!hasGenerated) {
256         *file << "void";
257     }
258     *file << ")";
259 
260     // Write the inline code, if any.
261     if (inlineCodeLines.size() > 0) {
262         *file << " {\n";
263         for (size_t ct = 0; ct < inlineCodeLines.size(); ct++) {
264             if (inlineCodeLines[ct].empty()) {
265                 *file << "\n";
266             } else {
267                 *file << "    " << inlineCodeLines[ct] << "\n";
268             }
269         }
270         *file << "}\n";
271     } else {
272         *file << ";\n";
273     }
274 
275     writeVersionGuardEnd(file, spec.getVersionInfo());
276     *file << "\n";
277 }
278 
writeFunctionComment(GeneratedFile * file,const Function & function)279 static void writeFunctionComment(GeneratedFile* file, const Function& function) {
280     // Write the generic documentation.
281     writeComment(file, function.getName(), function.getSummary(), function.getDescription(),
282                  function.deprecated(), false);
283 
284     // Comment the parameters.
285     if (function.someParametersAreDocumented()) {
286         *file << " *\n";
287         *file << " * Parameters:\n";
288         for (auto p : function.getParameters()) {
289             if (!p->documentation.empty()) {
290                 *file << " *   " << p->name << ": " << p->documentation << "\n";
291             }
292         }
293     }
294 
295     // Comment the return type.
296     const string returnDoc = function.getReturnDocumentation();
297     if (!returnDoc.empty()) {
298         *file << " *\n";
299         *file << " * Returns: " << returnDoc << "\n";
300     }
301 
302     *file << " */\n";
303 }
304 
writeFunctionSpecification(GeneratedFile * file,const FunctionSpecification & spec)305 static void writeFunctionSpecification(GeneratedFile* file, const FunctionSpecification& spec) {
306     // Write all the variants.
307     for (auto permutation : spec.getPermutations()) {
308         writeFunctionPermutation(file, spec, *permutation);
309     }
310 }
311 
writeHeaderFile(const string & directory,const SpecFile & specFile)312 static bool writeHeaderFile(const string& directory, const SpecFile& specFile) {
313     const string headerFileName = specFile.getHeaderFileName();
314 
315     // We generate one header file for each spec file.
316     GeneratedFile file;
317     if (!file.start(directory, headerFileName)) {
318         return false;
319     }
320 
321     // Write the comments that start the file.
322     file.writeNotices();
323     writeComment(&file, headerFileName, specFile.getBriefDescription(),
324                  specFile.getFullDescription(), false, true);
325     file << "\n";
326 
327     // Write the ifndef that prevents the file from being included twice.
328     const string guard = makeGuardString(headerFileName);
329     file << "#ifndef " << guard << "\n";
330     file << "#define " << guard << "\n\n";
331 
332     // Add lines that need to be put in "as is".
333     if (specFile.getVerbatimInclude().size() > 0) {
334         for (auto s : specFile.getVerbatimInclude()) {
335             file << s << "\n";
336         }
337         file << "\n";
338     }
339 
340     /* Write the constants, types, and functions in the same order as
341      * encountered in the spec file.
342      */
343     set<Constant*> documentedConstants;
344     for (auto spec : specFile.getConstantSpecifications()) {
345         Constant* constant = spec->getConstant();
346         if (documentedConstants.find(constant) == documentedConstants.end()) {
347             documentedConstants.insert(constant);
348             writeConstantComment(&file, *constant);
349         }
350         writeConstantSpecification(&file, *spec);
351     }
352     set<Type*> documentedTypes;
353     for (auto spec : specFile.getTypeSpecifications()) {
354         Type* type = spec->getType();
355         if (documentedTypes.find(type) == documentedTypes.end()) {
356             documentedTypes.insert(type);
357             writeTypeComment(&file, *type);
358         }
359         writeTypeSpecification(&file, *spec);
360     }
361 
362     set<Function*> documentedFunctions;
363     for (auto spec : specFile.getFunctionSpecifications()) {
364         Function* function = spec->getFunction();
365         if (documentedFunctions.find(function) == documentedFunctions.end()) {
366             documentedFunctions.insert(function);
367             writeFunctionComment(&file, *function);
368         }
369         writeFunctionSpecification(&file, *spec);
370     }
371 
372     file << "#endif // " << guard << "\n";
373     file.close();
374     return true;
375 }
376 
generateHeaderFiles(const string & directory)377 bool generateHeaderFiles(const string& directory) {
378     bool success = true;
379     for (auto specFile : systemSpecification.getSpecFiles()) {
380         if (!writeHeaderFile(directory, *specFile)) {
381             success = false;
382         }
383     }
384     return success;
385 }
386