blob: 1de53289bff21af2ac786035ffff32800b1745d9 [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
26struct DetailedFunctionEntry {
27 VersionInfo info;
28 string htmlDeclaration;
29};
30
31static void writeHtmlHeader(GeneratedFile* file) {
32 *file << "<!DOCTYPE html>\n";
33 *file << "<!-- " << AUTO_GENERATED_WARNING << "-->\n";
34
35 *file << "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n"
36 "<meta name='viewport' content='width=device-width'>\n"
37 "<link rel='shortcut icon' type='image/x-icon' "
38 "href='http://developer.android.com/favicon.ico'>\n"
39 "<title>android.renderscript | Android Developers</title>\n"
40 "<!-- STYLESHEETS -->\n"
41 "<link rel='stylesheet' "
42 "href='http://fonts.googleapis.com/css?family=Roboto+Condensed'>\n"
43 "<link rel='stylesheet' href='http://fonts.googleapis.com/"
44 "css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold' "
45 "title='roboto'>\n"
46 "<link href='./test_files/default.css' rel='stylesheet' type='text/css'>\n"
47 "<!-- FULLSCREEN STYLESHEET -->\n"
48 "<link href='./test_files/fullscreen.css' rel='stylesheet' class='fullscreen' "
49 "type='text/css'>\n"
50 "<!-- JAVASCRIPT -->\n"
51 "<script src='./test_files/cb=gapi.loaded_0' async=''></script><script "
52 "type='text/javascript' async='' src='./test_files/plusone.js' "
53 "gapi_processed='true'></script><script async='' "
54 "src='./test_files/analytics.js'></script><script src='./test_files/jsapi' "
55 "type='text/javascript'></script>\n"
56 "<script src='./test_files/android_3p-bundle.js' type='text/javascript'></script>\n"
57 "<script type='text/javascript'>\n"
58 " var toRoot = '/';\n"
59 " var metaTags = [];\n"
60 " var devsite = false;\n"
61 "</script>\n"
62 "<script src='./test_files/docs.js' type='text/javascript'></script><script "
63 "type='text/javascript' src='./test_files/saved_resource'></script>\n"
64 "<script>\n"
65 " (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n"
66 " (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n"
67 " m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n"
68 " })(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n"
69 " ga('create', 'UA-5831155-1', 'android.com');\n"
70 " ga('create', 'UA-49880327-2', 'android.com', {'name': 'universal'}); // New "
71 "tracker);\n"
72 " ga('send', 'pageview');\n"
73 " ga('universal.send', 'pageview'); // Send page view for new tracker.\n"
74 "</script>\n"
75 "<link type='text/css' href='./test_files/default+en.css' rel='stylesheet'><script "
76 "type='text/javascript' src='./test_files/default+en.I.js'></script></head>\n"
77 "<body class='gc-documentation\n"
78 " develop reference'>\n";
79 //" <div id='doc-api-level' class='11' style='display:none'></div>\n"
80 //" <a name='top'></a>\n";
81}
82
83static void writeHtmlFooter(GeneratedFile* file) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -070084 //*file << "</div>n"
85 *file << "<!-- end body-content -->\n</body></html>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070086}
87
88// If prefix starts input, copy it to stream and remove it from input.
89static void skipPrefix(ostringstream* stream, string* input, const string& prefix) {
90 size_t size = prefix.size();
91 if (input->compare(0, size, prefix) != 0) {
92 return;
93 }
94 input->erase(0, size);
95 *stream << prefix;
96}
97
98// Merge b into a. Returns true if successful
99static bool mergeVersionInfo(VersionInfo* a, const VersionInfo& b) {
100 if (a->intSize != b.intSize) {
101 cerr << "Error. We don't currently support versions that differ based on int size\n";
102 return false;
103 }
104 if (b.minVersion != 0 && a->maxVersion == b.minVersion - 1) {
105 a->maxVersion = b.maxVersion;
106 } else if (b.maxVersion != 0 && a->minVersion == b.maxVersion + 1) {
107 a->minVersion = b.minVersion;
108 } else {
109 cerr << "Error. This code currently assume that all versions are contiguous. Don't know "
110 "how to merge versions (" << a->minVersion << " - " << a->maxVersion << ") and ("
111 << b.minVersion << " - " << b.maxVersion << ")\n";
112 return false;
113 }
114 return true;
115}
116
117static string getHtmlStringForType(const ParameterDefinition& parameter) {
118 string s = parameter.rsType;
119 ostringstream stream;
120 skipPrefix(&stream, &s, "const ");
121 skipPrefix(&stream, &s, "volatile ");
122 bool endsWithAsterisk = s.size() > 0 && s[s.size() - 1] == '*';
123 if (endsWithAsterisk) {
124 s.erase(s.size() - 1, 1);
125 }
126
127 string anchor = systemSpecification.getHtmlAnchor(s);
128 if (anchor.empty()) {
129 // Not a RenderScript specific type.
130 return parameter.rsType;
131 } else {
132 stream << anchor;
133 }
134 if (endsWithAsterisk) {
135 stream << "*";
136 }
137 return stream.str();
138}
139
140static string getDetailedHtmlDeclaration(const FunctionPermutation& permutation) {
141 ostringstream stream;
142 auto ret = permutation.getReturn();
143 if (ret) {
144 stream << getHtmlStringForType(*ret);
145 } else {
146 stream << "void";
147 }
148 stream << " " << permutation.getName() << "(";
149 bool needComma = false;
150 for (auto p : permutation.getParams()) {
151 if (needComma) {
152 stream << ", ";
153 }
154 stream << getHtmlStringForType(*p);
155 if (p->isOutParameter) {
156 stream << "*";
157 }
158 if (!p->specName.empty()) {
159 stream << " " << p->specName;
160 }
161 needComma = true;
162 }
163 stream << ");\n";
164 return stream.str();
165}
166
167/* Some functions (like max) have changed implementations but not their
168 * declaration. We need to unify these so that we don't end up with entries
169 * like:
170 * char max(char a, char b); Removed from API level 20
171 * char max(char a, char b); Added to API level 20
172 */
173static bool getUnifiedFunctionPrototypes(Function* function,
174 map<string, DetailedFunctionEntry>* entries) {
175 for (auto f : function->getSpecifications()) {
176 DetailedFunctionEntry entry;
177 entry.info = f->getVersionInfo();
178 for (auto p : f->getPermutations()) {
179 entry.htmlDeclaration = getDetailedHtmlDeclaration(*p);
180 const string s = stripHtml(entry.htmlDeclaration);
181 auto i = entries->find(s);
182 if (i == entries->end()) {
183 entries->insert(pair<string, DetailedFunctionEntry>(s, entry));
184 } else {
185 if (!mergeVersionInfo(&i->second.info, entry.info)) {
186 return false;
187 }
188 }
189 }
190 }
191 return true;
192}
193
194// Convert words starting with @ into HTML references. Returns false if error.
195static bool convertDocumentationRefences(string* s) {
196 bool success = true;
197 size_t end = 0;
198 for (;;) {
199 size_t start = s->find('@', end);
200 if (start == string::npos) {
201 break;
202 }
203 // Find the end of the identifier
204 end = start;
205 char c;
206 do {
207 c = (*s)[++end];
208 } while (isalnum(c) || c == '_');
209
210 const string id = s->substr(start + 1, end - start - 1);
211 string anchor = systemSpecification.getHtmlAnchor(id);
212 if (anchor.empty()) {
213 cerr << "Error: Can't convert the documentation reference @" << id << "\n";
214 success = false;
215 }
216 s->replace(start, end - start, anchor);
217 }
218 return success;
219}
220
221static bool generateHtmlParagraphs(GeneratedFile* file, const vector<string>& description) {
222 bool inParagraph = false;
223 for (auto s : description) {
224 // Empty lines in the .spec marks paragraphs.
225 if (s.empty()) {
226 if (inParagraph) {
227 *file << "</p>\n";
228 inParagraph = false;
229 }
230 } else {
231 if (!inParagraph) {
232 *file << "<p> ";
233 inParagraph = true;
234 }
235 }
236 if (!convertDocumentationRefences(&s)) {
237 return false;
238 }
239 *file << s << "\n";
240 }
241 if (inParagraph) {
242 *file << "</p>\n";
243 }
244 return true;
245}
246
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700247static void writeSummaryTableStart(GeneratedFile* file, const string& label, bool labelIsHeading) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700248 if (labelIsHeading) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700249 *file << "<h2 style='margin-bottom: 0px;'>" << label << "</h2><hr/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700250 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700251 *file << "<table class='jd-sumtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700252 if (!labelIsHeading) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700253 *file << " <tr><th colspan='2'>" << label << "</th></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700254 }
255}
256
257static void writeSummaryTableEnd(GeneratedFile* file) {
258 *file << "</tbody></table>\n";
259}
260
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700261enum DeprecatedSelector {
262 DEPRECATED_ONLY,
263 NON_DEPRECATED_ONLY,
264 ALL,
265};
266
267static void writeSummaryTableEntry(ostream* stream, Definition* definition,
268 DeprecatedSelector deprecatedSelector) {
269 if (definition->hidden()) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700270 return;
271 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700272 const bool deprecated = definition->deprecated();
273 if ((deprecatedSelector == DEPRECATED_ONLY && !deprecated) ||
274 (deprecatedSelector == NON_DEPRECATED_ONLY && deprecated)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700275 return;
276 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700277
278 *stream << " <tr class='alt-color api apilevel-1'>\n";
279 *stream << " <td class='jd-linkcol'>\n";
280 *stream << " <a href='" << definition->getUrl() << "'>" << definition->getName() << "</a>\n";
281 *stream << " </td>\n";
282 *stream << " <td class='jd-descrcol' width='100%'>\n";
283 *stream << " ";
284 if (deprecated) {
285 *stream << "<b>Deprecated</b>. ";
286 }
287 *stream << definition->getSummary() << "\n";
288 *stream << " </td>\n";
289 *stream << " </tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700290}
291
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700292static void writeSummaryTable(GeneratedFile* file, const ostringstream* entries, const char* name,
293 DeprecatedSelector deprecatedSelector, bool labelAsHeader) {
294 string s = entries->str();
295 if (!s.empty()) {
296 string prefix;
297 if (deprecatedSelector == DEPRECATED_ONLY) {
298 prefix = "Deprecated ";
299 }
300 writeSummaryTableStart(file, prefix + name, labelAsHeader);
301 *file << s;
302 writeSummaryTableEnd(file);
303 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700304}
305
306static void writeSummaryTables(GeneratedFile* file, const map<string, Constant*>& constants,
307 const map<string, Type*>& types,
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700308 const map<string, Function*>& functions,
309 DeprecatedSelector deprecatedSelector, bool labelAsHeader) {
310 ostringstream constantStream;
311 for (auto e : constants) {
312 writeSummaryTableEntry(&constantStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700313 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700314 writeSummaryTable(file, &constantStream, "Constants", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700315
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700316 ostringstream typeStream;
317 for (auto e : types) {
318 writeSummaryTableEntry(&typeStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700319 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700320 writeSummaryTable(file, &typeStream, "Types", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700321
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700322 ostringstream functionStream;
323 for (auto e : functions) {
324 writeSummaryTableEntry(&functionStream, e.second, deprecatedSelector);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700325 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700326 writeSummaryTable(file, &functionStream, "Functions", deprecatedSelector, labelAsHeader);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700327}
328
329static void writeHtmlVersionTag(GeneratedFile* file, VersionInfo info) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700330 ostringstream stream;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700331 if (info.intSize == 32) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700332 stream << "When compiling for 32 bits. ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700333 } else if (info.intSize == 64) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700334 stream << "When compiling for 64 bits. ";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700335 }
336
337 if (info.minVersion > 1 || info.maxVersion) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700338 const char* mid =
339 "<a "
340 "href='http://developer.android.com/guide/topics/manifest/"
341 "uses-sdk-element.html#ApiLevels'>API level ";
342 if (info.minVersion <= 1) {
343 // No minimum
344 if (info.maxVersion > 0) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700345 stream << "Removed from " << mid << info.maxVersion + 1;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700346 }
347 } else {
348 if (info.maxVersion == 0) {
349 // No maximum
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700350 stream << "Added in " << mid << info.minVersion;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700351 } else {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700352 stream << mid << info.minVersion << " - " << info.maxVersion;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700353 }
354 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700355 stream << "</a>";
356 }
357 const string s = stream.str();
358 if (!s.empty()) {
359 // TODO simplify
360 //*file << " <p>" << s << "</p>\n";
361 *file << " " << s << "\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700362 }
363}
364
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700365
366static void writeDetailedTypeSpecification(GeneratedFile* file, const TypeSpecification* type) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700367 switch (type->getKind()) {
368 case SIMPLE:
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700369 *file << "<p>A typedef of: " << type->getSimpleType()
370 << "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
371 writeHtmlVersionTag(file, type->getVersionInfo());
372 *file << "</p>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700373 break;
374 case ENUM: {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700375 *file << "<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n";
376 writeHtmlVersionTag(file, type->getVersionInfo());
377 *file << "</p>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700378
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700379 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700380 const vector<string>& values = type->getValues();
381 const vector<string>& valueComments = type->getValueComments();
382 for (size_t i = 0; i < values.size(); i++) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700383 *file << " <tr><th>" << values[i] << "</th><td>";
384 if (valueComments.size() > i) {
385 *file << valueComments[i];
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700386 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700387 *file << "</td></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700388 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700389 *file << " </tbody></table><br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700390 break;
391 }
392 case STRUCT: {
393 // TODO string mStructName; // The name found after the struct keyword
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700394 *file << "<p>A structure with the following fields:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
395 writeHtmlVersionTag(file, type->getVersionInfo());
396 *file << "</p>\n";
397
398 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700399 const vector<string>& fields = type->getFields();
400 const vector<string>& fieldComments = type->getFieldComments();
401 for (size_t i = 0; i < fields.size(); i++) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700402 *file << " <tr><th>" << fields[i] << "</th><td>";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700403 if (fieldComments.size() > i && !fieldComments[i].empty()) {
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700404 *file << fieldComments[i];
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700405 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700406 *file << "</td></tr>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700407 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700408 *file << " </tbody></table><br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700409 break;
410 }
411 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700412}
413
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700414static void writeDetailedConstantSpecification(GeneratedFile* file, ConstantSpecification* c) {
415 *file << " <tr><td>";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700416 *file << "Value: " << c->getValue() << "\n";
417 writeHtmlVersionTag(file, c->getVersionInfo());
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700418 *file << " </td></tr>\n";
419 *file << "<br/>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700420}
421
422static bool writeOverviewForFile(GeneratedFile* file, const SpecFile& specFile) {
423 bool success = true;
424 *file << "<h2>" << specFile.getBriefDescription() << "</h2>\n";
425 if (!generateHtmlParagraphs(file, specFile.getFullDescription())) {
426 success = false;
427 }
428
429 // Write the summary tables.
430 // file << "<h2>Summary</h2>\n";
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700431 writeSummaryTables(file, specFile.getDocumentedConstants(), specFile.getDocumentedTypes(),
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700432 specFile.getDocumentedFunctions(), NON_DEPRECATED_ONLY, false);
433
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700434 return success;
435}
436
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700437static bool generateOverview(const string& directory) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700438 GeneratedFile file;
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700439 if (!file.start(directory, "index.html")) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700440 return false;
441 }
442 bool success = true;
443 writeHtmlHeader(&file);
444
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700445 file << "<h1>Overview</h1>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700446
447 for (auto specFile : systemSpecification.getSpecFiles()) {
448 if (!writeOverviewForFile(&file, *specFile)) {
449 success = false;
450 }
451 }
452
453 writeHtmlFooter(&file);
454 file.close();
455 return success;
456}
457
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700458static bool generateAlphabeticalIndex(const string& directory) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700459 GeneratedFile file;
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700460 if (!file.start(directory, "alpha_index.html")) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700461 return false;
462 }
463 writeHtmlHeader(&file);
464
465 writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700466 systemSpecification.getFunctions(), NON_DEPRECATED_ONLY, true);
467
468 writeSummaryTables(&file, systemSpecification.getConstants(), systemSpecification.getTypes(),
469 systemSpecification.getFunctions(), DEPRECATED_ONLY, true);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700470
471 writeHtmlFooter(&file);
472 file.close();
473 return true;
474}
475
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700476static void writeDeprecatedWarning(GeneratedFile* file, Definition* definition) {
477 if (definition->deprecated()) {
478 *file << " <p><b>Deprecated.</b> ";
479 string s = definition->getDeprecatedMessage();
480 convertDocumentationRefences(&s);
481 if (!s.empty()) {
482 *file << s;
483 } else {
484 *file << "Do not use.";
485 }
486 *file << "</p>\n";
487 }
488}
489
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700490static bool writeDetailedConstant(GeneratedFile* file, Constant* constant) {
491 if (constant->hidden()) {
492 return true;
493 }
494 const string& name = constant->getName();
495
496 // TODO need names that distinguish fn.const. type
497 // TODO had attr_android:...
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700498 *file << "<a id='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700499 *file << "<div class='jd-details'>\n";
500 *file << " <h4 class='jd-details-title'>\n";
501 *file << " <span class='sympad'>" << name << "</span>\n";
502 *file << " <span class='normal'>: " << constant->getSummary() << "</span>\n";
503 *file << " </h4>\n";
504
505 *file << " <div class='jd-details-descr'>\n";
506 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700507 auto specifications = constant->getSpecifications();
508 bool addSeparator = specifications.size() > 1;
509 for (auto spec : specifications) {
510 if (addSeparator) {
511 *file << " <h5 class='jd-tagtitle'>Variant:</h5>\n";
512 }
513 writeDetailedConstantSpecification(file, spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700514 }
515 *file << " </tbody></table>\n";
516 *file << " </div>\n";
517
518 *file << " <div class='jd-tagdata jd-tagdescr'>\n";
519
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700520 writeDeprecatedWarning(file, constant);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700521 if (!generateHtmlParagraphs(file, constant->getDescription())) {
522 return false;
523 }
524 *file << " </div>\n";
525
526 *file << "</div>\n";
527 *file << "\n";
528 return true;
529}
530
531static bool writeDetailedType(GeneratedFile* file, Type* type) {
532 if (type->hidden()) {
533 return true;
534 }
535 const string& name = type->getName();
536
537 // TODO need names that distinguish fn.const. type
538 // TODO had attr_android:...
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700539 *file << "<a id='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700540 *file << "<div class='jd-details'>\n";
541 *file << " <h4 class='jd-details-title'>\n";
542 *file << " <span class='sympad'>" << name << "</span>\n";
543 *file << " <span class='normal'>: " << type->getSummary() << "</span>\n";
544 *file << " </h4>\n";
545
546 *file << " <div class='jd-details-descr'>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700547 for (auto spec : type->getSpecifications()) {
548 writeDetailedTypeSpecification(file, spec);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700549 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700550
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700551 writeDeprecatedWarning(file, type);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700552 if (!generateHtmlParagraphs(file, type->getDescription())) {
553 return false;
554 }
555
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700556 *file << " </div>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700557 *file << "</div>\n";
558 *file << "\n";
559 return true;
560}
561
562static bool writeDetailedFunction(GeneratedFile* file, Function* function) {
563 const string& name = function->getName();
564
565 // TODO need names that distinguish fn.const. type
566 // TODO had attr_android:...
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700567 *file << "<a id='android_rs:" << name << "'></a>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700568 *file << "<div class='jd-details'>\n";
569 *file << " <h4 class='jd-details-title'>\n";
570 *file << " <span class='sympad'>" << name << "</span>\n";
571 *file << " <span class='normal'>: " << function->getSummary() << "</span>\n";
572 *file << " </h4>\n";
573
574 *file << " <div class='jd-details-descr'>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700575 map<string, DetailedFunctionEntry> entries;
576 if (!getUnifiedFunctionPrototypes(function, &entries)) {
577 return false;
578 }
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700579 *file << " <table class='jd-tagtable'><tbody>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700580 for (auto i : entries) {
581 *file << " <tr>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700582 *file << " <td>" << i.second.htmlDeclaration << "</td>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700583 *file << " <td>";
584 writeHtmlVersionTag(file, i.second.info);
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700585 *file << " </td>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700586 *file << " </tr>\n";
587 }
588 *file << " </tbody></table>\n";
589 *file << " </div>\n";
590
591 if (function->someParametersAreDocumented()) {
592 *file << " <div class='jd-tagdata'>";
593 *file << " <h5 class='jd-tagtitle'>Parameters</h5>\n";
594 *file << " <table class='jd-tagtable'><tbody>\n";
595 for (ParameterEntry* p : function->getParameters()) {
596 *file << " <tr><th>" << p->name << "</th><td>" << p->documentation << "</td></tr>\n";
597 }
598 *file << " </tbody></table>\n";
599 *file << " </div>\n";
600 }
601
602 string ret = function->getReturnDocumentation();
603 if (!ret.empty()) {
604 *file << " <div class='jd-tagdata'>";
605 *file << " <h5 class='jd-tagtitle'>Returns</h5>\n";
606 *file << " <table class='jd-tagtable'><tbody>\n";
607 *file << " <tr><td>" << ret << "</td></tr>\n";
608 *file << " </tbody></table>\n";
609 *file << " </div>\n";
610 }
611
612 *file << " <div class='jd-tagdata jd-tagdescr'>\n";
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700613 writeDeprecatedWarning(file, function);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700614 if (!generateHtmlParagraphs(file, function->getDescription())) {
615 return false;
616 }
617 *file << " </div>\n";
618
619 *file << "</div>\n";
620 *file << "\n";
621 return true;
622}
623
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700624static bool writeDetailedDocumentationFile(const string& directory, const SpecFile& specFile) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700625 GeneratedFile file;
626 const string htmlFileName = stringReplace(specFile.getSpecFileName(), ".spec", ".html");
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700627 if (!file.start(directory, htmlFileName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700628 return false;
629 }
630 bool success = true;
631
632 writeHtmlHeader(&file);
633 file << "<br/>";
634
635 // Write the file documentation.
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700636 file << "<h1>" << specFile.getBriefDescription() << "</h1>\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700637
638 file << "<h2>Overview</h2>\n";
639 if (!generateHtmlParagraphs(&file, specFile.getFullDescription())) {
640 success = false;
641 }
642
643 // Write the summary tables.
644 file << "<h2>Summary</h2>\n";
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -0700645 const auto& constants = specFile.getDocumentedConstants();
646 const auto& types = specFile.getDocumentedTypes();
647 const auto& functions = specFile.getDocumentedFunctions();
Jean-Luc Brouillet4a730042015-04-02 16:15:25 -0700648
649 writeSummaryTables(&file, constants, types, functions, NON_DEPRECATED_ONLY, false);
650 writeSummaryTables(&file, constants, types, functions, DEPRECATED_ONLY, false);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700651
652 // Write the full details of each constant, type, and function.
653 if (!constants.empty()) {
654 file << "<h2>Constants</h2>\n";
655 for (auto i : constants) {
656 if (!writeDetailedConstant(&file, i.second)) {
657 success = false;
658 }
659 }
660 }
661 if (!types.empty()) {
662 file << "<h2>Types</h2>\n";
663 for (auto i : types) {
664 if (!writeDetailedType(&file, i.second)) {
665 success = false;
666 }
667 }
668 }
669 if (!functions.empty()) {
670 file << "<h2>Functions</h2>\n";
671 for (auto i : functions) {
672 if (!writeDetailedFunction(&file, i.second)) {
673 success = false;
674 }
675 }
676 }
677
678 writeHtmlFooter(&file);
679 file.close();
680
681 if (!success) {
682 // If in error, write a final message to make it easier to figure out which file failed.
683 cerr << htmlFileName << ": Failed due to errors.\n";
684 }
685 return success;
686}
687
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700688bool generateHtmlDocumentation(const string& directory) {
689 bool success = generateOverview(directory) && generateAlphabeticalIndex(directory);
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700690 for (auto specFile : systemSpecification.getSpecFiles()) {
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700691 if (!writeDetailedDocumentationFile(directory, *specFile)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700692 success = false;
693 }
694 }
695 return success;
696}