1 /* -----------------------------------------------------------------------------
2 * This file is part of SWIG, which is licensed as a whole under version 3
3 * (or any later version) of the GNU General Public License. Some additional
4 * terms also apply to certain portions of SWIG. The full details of the SWIG
5 * license and copyrights can be found in the LICENSE and COPYRIGHT files
6 * included with the SWIG source code as distributed by the SWIG developers
7 * and at http://www.swig.org/legal.html.
8 *
9 * javadoc.cxx
10 * ----------------------------------------------------------------------------- */
11
12 #include "javadoc.h"
13 #include "doxyparser.h"
14 #include <iostream>
15 #include <vector>
16 #include <list>
17 #include "swigmod.h"
18 #define APPROX_LINE_LENGTH 64 // characters per line allowed
19 #define TAB_SIZE 8 // current tab size in spaces
20 //TODO {@link} {@linkplain} {@docRoot}, and other useful doxy commands that are not a javadoc tag
21
22 // define static tables, they are filled in JavaDocConverter's constructor
23 std::map<std::string, std::pair<JavaDocConverter::tagHandler, std::string> > JavaDocConverter::tagHandlers;
24
25 using std::string;
26 using std::list;
27 using std::vector;
28
fillStaticTables()29 void JavaDocConverter::fillStaticTables() {
30 if (tagHandlers.size()) // fill only once
31 return;
32
33 /*
34 * Some translation rules:
35 *
36 * @ and \ must be escaped for both Java and Python to appear on output: \@, \\,
37 * while Doxygen produces output in both cases.
38 * Rule: @ and \ with space on the right should get to output.
39 *
40 * :: remains intact, even in class::method(). But you can use class#method also
41 * in C++ comment and it is properly translated to C++ output (changed by doxygen to ::)
42 * and Java output (remains #).
43 * Rule: SWIG type system can't be used to convert C::m to C#m, because in Java it is C.m
44 * Use string replacement :: --> # in tag see and links.
45 *
46 * HTML tags must be translated - remain in Java, to markdown in Python
47 *
48 * Unknown HTML tags, for example <x> is translated to <x> by doxygen, while
49 * Java src is <x> and therefore invisible on output - browser ignores unknown command.
50 * This is handy in syntax descriptions, for example: more <fileName>.
51 *
52 * Standalone < and > need not be translated, they are rendered properly in
53 * all three outputs.
54 *
55 * ., %, and " need not to be translated
56 *
57 * entities must be translated - remain in Java, something meaningful in Python (<, ...)
58 *
59 * - Python
60 * - add comments also to auto-generated methods like equals(), delete() in Java,
61 * and methods for std::vector(), ...
62 * Commenting methods of std types is simple - add comment to std_*.i file.
63 */
64
65 // these commands insert HTML tags
66 tagHandlers["a"] = make_pair(&JavaDocConverter::handleTagHtml, "i");
67 tagHandlers["arg"] = make_pair(&JavaDocConverter::handleTagHtml, "li");
68 tagHandlers["b"] = make_pair(&JavaDocConverter::handleTagHtml, "b");
69 tagHandlers["c"] = make_pair(&JavaDocConverter::handleTagHtml, "code");
70 tagHandlers["cite"] = make_pair(&JavaDocConverter::handleTagHtml, "i");
71 tagHandlers["e"] = make_pair(&JavaDocConverter::handleTagHtml, "i");
72 tagHandlers["em"] = make_pair(&JavaDocConverter::handleTagHtml, "i");
73 tagHandlers["li"] = make_pair(&JavaDocConverter::handleTagHtml, "li");
74 tagHandlers["p"] = make_pair(&JavaDocConverter::handleTagHtml, "code");
75 // these commands insert just a single char, some of them need to be escaped
76 tagHandlers["$"] = make_pair(&JavaDocConverter::handleTagChar, "");
77 tagHandlers["@"] = make_pair(&JavaDocConverter::handleTagChar, "");
78 tagHandlers["\\"] = make_pair(&JavaDocConverter::handleTagChar, "");
79 tagHandlers["<"] = make_pair(&JavaDocConverter::handleTagChar, "<");
80 tagHandlers[">"] = make_pair(&JavaDocConverter::handleTagChar, ">");
81 tagHandlers["&"] = make_pair(&JavaDocConverter::handleTagChar, "&");
82 tagHandlers["#"] = make_pair(&JavaDocConverter::handleTagChar, "");
83 tagHandlers["%"] = make_pair(&JavaDocConverter::handleTagChar, "");
84 tagHandlers["~"] = make_pair(&JavaDocConverter::handleTagChar, "");
85 tagHandlers["\""] = make_pair(&JavaDocConverter::handleTagChar, """);
86 tagHandlers["."] = make_pair(&JavaDocConverter::handleTagChar, "");
87 tagHandlers["::"] = make_pair(&JavaDocConverter::handleTagChar, "");
88 // these commands are stripped out
89 tagHandlers["attention"] = make_pair(&JavaDocConverter::handleParagraph, "");
90 tagHandlers["anchor"] = make_pair(&JavaDocConverter::handleTagAnchor, "");
91 tagHandlers["brief"] = make_pair(&JavaDocConverter::handleParagraph, "");
92 tagHandlers["bug"] = make_pair(&JavaDocConverter::handleParagraph, "");
93 tagHandlers["date"] = make_pair(&JavaDocConverter::handleParagraph, "");
94 tagHandlers["details"] = make_pair(&JavaDocConverter::handleParagraph, "");
95 // this command is inserts text accumulated after cmd htmlonly -
96 // see DoxygenParser - CMD_HTML_ONLY.
97 tagHandlers["htmlonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
98 tagHandlers["invariant"] = make_pair(&JavaDocConverter::handleParagraph, "");
99 tagHandlers["latexonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
100 tagHandlers["manonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
101 tagHandlers["partofdescription"] = make_pair(&JavaDocConverter::handleParagraph, "");
102 tagHandlers["rtfonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
103 tagHandlers["short"] = make_pair(&JavaDocConverter::handleParagraph, "");
104 tagHandlers["xmlonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
105 // these commands are kept as-is, they are supported by JavaDoc
106 tagHandlers["author"] = make_pair(&JavaDocConverter::handleTagSame, "");
107 tagHandlers["authors"] = make_pair(&JavaDocConverter::handleTagSame, "author");
108 tagHandlers["deprecated"] = make_pair(&JavaDocConverter::handleTagSame, "");
109 tagHandlers["exception"] = make_pair(&JavaDocConverter::handleTagSame, "");
110 tagHandlers["package"] = make_pair(&JavaDocConverter::handleTagSame, "");
111 tagHandlers["param"] = make_pair(&JavaDocConverter::handleTagParam, "");
112 tagHandlers["tparam"] = make_pair(&JavaDocConverter::handleTagParam, "");
113 tagHandlers["ref"] = make_pair(&JavaDocConverter::handleTagRef, "");
114 tagHandlers["result"] = make_pair(&JavaDocConverter::handleTagSame, "return");
115 tagHandlers["return"] = make_pair(&JavaDocConverter::handleTagSame, "");
116 tagHandlers["returns"] = make_pair(&JavaDocConverter::handleTagSame, "return");
117 //tagHandlers["see"] = make_pair(&JavaDocConverter::handleTagSame, "");
118 //tagHandlers["sa"] = make_pair(&JavaDocConverter::handleTagSame, "see");
119 tagHandlers["since"] = make_pair(&JavaDocConverter::handleTagSame, "");
120 tagHandlers["throws"] = make_pair(&JavaDocConverter::handleTagSame, "");
121 tagHandlers["throw"] = make_pair(&JavaDocConverter::handleTagSame, "throws");
122 tagHandlers["version"] = make_pair(&JavaDocConverter::handleTagSame, "");
123 // these commands have special handlers
124 tagHandlers["code"] = make_pair(&JavaDocConverter::handleTagExtended, "code");
125 tagHandlers["cond"] = make_pair(&JavaDocConverter::handleTagMessage, "Conditional comment: ");
126 tagHandlers["copyright"] = make_pair(&JavaDocConverter::handleTagMessage, "Copyright: ");
127 tagHandlers["else"] = make_pair(&JavaDocConverter::handleTagIf, "Else: ");
128 tagHandlers["elseif"] = make_pair(&JavaDocConverter::handleTagIf, "Else if: ");
129 tagHandlers["endcond"] = make_pair(&JavaDocConverter::handleTagMessage, "End of conditional comment.");
130 // space in second arg prevents Javadoc to treat '@ example' as command. File name of
131 // example is still informative to user.
132 tagHandlers["example"] = make_pair(&JavaDocConverter::handleTagSame, " example");
133 tagHandlers["if"] = make_pair(&JavaDocConverter::handleTagIf, "If: ");
134 tagHandlers["ifnot"] = make_pair(&JavaDocConverter::handleTagIf, "If not: ");
135 tagHandlers["image"] = make_pair(&JavaDocConverter::handleTagImage, "");
136 tagHandlers["link"] = make_pair(&JavaDocConverter::handleTagLink, "");
137 tagHandlers["see"] = make_pair(&JavaDocConverter::handleTagSee, "");
138 tagHandlers["sa"] = make_pair(&JavaDocConverter::handleTagSee, "");
139 tagHandlers["note"] = make_pair(&JavaDocConverter::handleTagMessage, "Note: ");
140 tagHandlers["overload"] = make_pair(&JavaDocConverter::handleTagMessage,
141 "This is an overloaded member function, provided for"
142 " convenience. It differs from the above function only in what" " argument(s) it accepts.");
143 tagHandlers["par"] = make_pair(&JavaDocConverter::handleTagPar, "");
144 tagHandlers["remark"] = make_pair(&JavaDocConverter::handleTagMessage, "Remarks: ");
145 tagHandlers["remarks"] = make_pair(&JavaDocConverter::handleTagMessage, "Remarks: ");
146 tagHandlers["todo"] = make_pair(&JavaDocConverter::handleTagMessage, "TODO: ");
147 tagHandlers["verbatim"] = make_pair(&JavaDocConverter::handleTagExtended, "literal");
148
149 // \f commands output literal Latex formula, which is still better than nothing.
150 tagHandlers["f$"] = make_pair(&JavaDocConverter::handleTagVerbatim, "");
151 tagHandlers["f["] = make_pair(&JavaDocConverter::handleTagVerbatim, "");
152 tagHandlers["f{"] = make_pair(&JavaDocConverter::handleTagVerbatim, "");
153
154 tagHandlers["warning"] = make_pair(&JavaDocConverter::handleTagMessage, "Warning: ");
155 // this command just prints it's contents
156 // (it is internal command of swig's parser, contains plain text)
157 tagHandlers["plainstd::string"] = make_pair(&JavaDocConverter::handlePlainString, "");
158 tagHandlers["plainstd::endl"] = make_pair(&JavaDocConverter::handleNewLine, "");
159 tagHandlers["n"] = make_pair(&JavaDocConverter::handleNewLine, "");
160
161 // HTML tags
162 tagHandlers["<a"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<a");
163 tagHandlers["<b"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<b");
164 tagHandlers["<blockquote"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<blockquote");
165 tagHandlers["<body"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<body");
166 tagHandlers["<br"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<br");
167 tagHandlers["<center"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<center");
168 tagHandlers["<caption"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<caption");
169 tagHandlers["<code"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<code");
170 tagHandlers["<dd"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<dd");
171 tagHandlers["<dfn"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<dfn");
172 tagHandlers["<div"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<div");
173 tagHandlers["<dl"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<dl");
174 tagHandlers["<dt"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<dt");
175 tagHandlers["<em"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<em");
176 tagHandlers["<form"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<form");
177 tagHandlers["<hr"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<hr");
178 tagHandlers["<h1"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<h1");
179 tagHandlers["<h2"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<h2");
180 tagHandlers["<h3"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<h3");
181 tagHandlers["<i"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<i");
182 tagHandlers["<input"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<input");
183 tagHandlers["<img"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<img");
184 tagHandlers["<li"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<li");
185 tagHandlers["<meta"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<meta");
186 tagHandlers["<multicol"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<multicol");
187 tagHandlers["<ol"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<ol");
188 tagHandlers["<p"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<p");
189 tagHandlers["<pre"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<pre");
190 tagHandlers["<small"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<small");
191 tagHandlers["<span"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<span");
192 tagHandlers["<strong"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<strong");
193 tagHandlers["<sub"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<sub");
194 tagHandlers["<sup"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<sup");
195 tagHandlers["<table"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<table");
196 tagHandlers["<td"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<td");
197 tagHandlers["<th"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<th");
198 tagHandlers["<tr"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<tr");
199 tagHandlers["<tt"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<tt");
200 tagHandlers["<kbd"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<kbd");
201 tagHandlers["<ul"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<ul");
202 tagHandlers["<var"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<var");
203
204 // HTML entities
205 tagHandlers["©"] = make_pair(&JavaDocConverter::handleHtmlEntity, "©");
206 tagHandlers["&trade"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&trade");
207 tagHandlers["®"] = make_pair(&JavaDocConverter::handleHtmlEntity, "®");
208 tagHandlers["<"] = make_pair(&JavaDocConverter::handleHtmlEntity, "<");
209 tagHandlers[">"] = make_pair(&JavaDocConverter::handleHtmlEntity, ">");
210 tagHandlers["&"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&");
211 tagHandlers["&apos"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&apos");
212 tagHandlers["""] = make_pair(&JavaDocConverter::handleHtmlEntity, """);
213 tagHandlers["&lsquo"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&lsquo");
214 tagHandlers["&rsquo"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&rsquo");
215 tagHandlers["&ldquo"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&ldquo");
216 tagHandlers["&rdquo"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&rdquo");
217 tagHandlers["&ndash"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&ndash");
218 tagHandlers["&mdash"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&mdash");
219 tagHandlers[" "] = make_pair(&JavaDocConverter::handleHtmlEntity, " ");
220 tagHandlers["×"] = make_pair(&JavaDocConverter::handleHtmlEntity, "×");
221 tagHandlers["&minus"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&minus");
222 tagHandlers["&sdot"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&sdot");
223 tagHandlers["&sim"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&sim");
224 tagHandlers["&le"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&le");
225 tagHandlers["&ge"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&ge");
226 tagHandlers["&larr"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&larr");
227 tagHandlers["&rarr"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&rarr");
228 }
229
JavaDocConverter(int flags)230 JavaDocConverter::JavaDocConverter(int flags) :
231 DoxygenTranslator(flags) {
232 fillStaticTables();
233 }
234
235 /**
236 * Formats comment lines by inserting '\n *' at to long lines and tabs for
237 * indent. Currently it is disabled, which means original comment format is
238 * preserved. Experience shows, that this is usually better than breaking
239 * lines automatically, especially because original line endings are not removed,
240 * which results in short lines. To be useful, this function should have much
241 * better algorithm.
242 */
formatCommand(std::string unformattedLine,int indent)243 std::string JavaDocConverter::formatCommand(std::string unformattedLine, int indent) {
244 std::string formattedLines;
245 return unformattedLine; // currently disabled
246 std::string::size_type lastPosition = 0;
247 std::string::size_type i = 0;
248 int isFirstLine = 1;
249 while (i != std::string::npos && i < unformattedLine.length()) {
250 lastPosition = i;
251 if (isFirstLine) {
252 i += APPROX_LINE_LENGTH;
253 } else {
254 i += APPROX_LINE_LENGTH - indent * TAB_SIZE;
255 }
256
257 i = unformattedLine.find(" ", i);
258
259 if (i > 0 && i + 1 < unformattedLine.length()) {
260 if (!isFirstLine)
261 for (int j = 0; j < indent; j++) {
262 formattedLines.append("\t");
263 } else {
264 isFirstLine = 0;
265 }
266 formattedLines.append(unformattedLine.substr(lastPosition, i - lastPosition + 1));
267 formattedLines.append("\n *");
268
269 }
270 }
271 if (lastPosition < unformattedLine.length()) {
272 if (!isFirstLine) {
273 for (int j = 0; j < indent; j++) {
274 formattedLines.append("\t");
275 }
276 }
277 formattedLines.append(unformattedLine.substr(lastPosition, unformattedLine.length() - lastPosition));
278 }
279
280 return formattedLines;
281 }
282
283 /**
284 * Returns true, if the given parameter exists in the current node
285 * (for example param is a name of function parameter). If feature
286 * 'doxygen:nostripparams' is set, then this method always returns
287 * true - parameters are copied to output regardless of presence in
288 * function params list.
289 */
paramExists(std::string param)290 bool JavaDocConverter::paramExists(std::string param) {
291
292 if (GetFlag(currentNode, "feature:doxygen:nostripparams")) {
293 return true;
294 }
295
296 ParmList *plist = CopyParmList(Getattr(currentNode, "parms"));
297
298 for (Parm *p = plist; p;) {
299
300 if (Getattr(p, "name") && Char(Getattr(p, "name")) == param) {
301 return true;
302 }
303 /* doesn't seem to work always: in some cases (especially for 'self' parameters)
304 * tmap:in is present, but tmap:in:next is not and so this code skips all the parameters
305 */
306 //p = Getattr(p, "tmap:in") ? Getattr(p, "tmap:in:next") : nextSibling(p);
307 p = nextSibling(p);
308 }
309
310 Delete(plist);
311
312 return false;
313 }
314
translateSubtree(DoxygenEntity & doxygenEntity)315 std::string JavaDocConverter::translateSubtree(DoxygenEntity &doxygenEntity) {
316 std::string translatedComment;
317
318 if (doxygenEntity.isLeaf) {
319 return translatedComment;
320 }
321
322 for (DoxygenEntityListIt p = doxygenEntity.entityList.begin(); p != doxygenEntity.entityList.end(); p++) {
323
324 translateEntity(*p, translatedComment);
325 translateSubtree(*p);
326 }
327
328 return translatedComment;
329 }
330
331 /**
332 * Checks if a handler for the given tag exists, and calls it.
333 */
translateEntity(DoxygenEntity & tag,std::string & translatedComment)334 void JavaDocConverter::translateEntity(DoxygenEntity &tag, std::string &translatedComment) {
335
336 std::map<std::string, std::pair<tagHandler, std::string> >::iterator it;
337 it = tagHandlers.find(getBaseCommand(tag.typeOfEntity));
338
339 if (it != tagHandlers.end()) {
340 (this->*(it->second.first))(tag, translatedComment, it->second.second);
341 } else {
342 // do NOT print warning, since there are many tags, which are not
343 // translatable - many warnings hide important ones
344 // addError(WARN_DOXYGEN_COMMAND_ERROR, "Unknown doxygen or HTML tag: " + tag.typeOfEntity);
345 }
346 }
347
348
handleTagAnchor(DoxygenEntity & tag,std::string & translatedComment,std::string &)349 void JavaDocConverter::handleTagAnchor(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
350 translatedComment += "<a id=\"" + translateSubtree(tag) + "\"></a>";
351 }
352
353
handleTagHtml(DoxygenEntity & tag,std::string & translatedComment,std::string & arg)354 void JavaDocConverter::handleTagHtml(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
355 if (tag.entityList.size()) { // do not include empty tags
356 std::string tagData = translateSubtree(tag);
357 // wrap the thing, ignoring whitespace
358 size_t wsPos = tagData.find_last_not_of("\n\t ");
359 if (wsPos != std::string::npos)
360 translatedComment += "<" + arg + ">" + tagData.substr(0, wsPos + 1) + "</" + arg + ">" + tagData.substr(wsPos + 1);
361 else
362 translatedComment += "<" + arg + ">" + translateSubtree(tag) + "</" + arg + "> ";
363 }
364 }
365
handleDoxyHtmlTag(DoxygenEntity & tag,std::string & translatedComment,std::string & arg)366 void JavaDocConverter::handleDoxyHtmlTag(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
367 std::string htmlTagArgs = tag.data;
368 if (htmlTagArgs == "/") {
369 // end html tag, for example "</ul>
370 translatedComment += "</" + arg.substr(1) + ">";
371 } else {
372 translatedComment += arg + htmlTagArgs + ">";
373 }
374 }
375
handleHtmlEntity(DoxygenEntity &,std::string & translatedComment,std::string & arg)376 void JavaDocConverter::handleHtmlEntity(DoxygenEntity &, std::string &translatedComment, std::string &arg) {
377 // html entities can be preserved for Java
378 translatedComment += arg + ';';
379 }
380
handleNewLine(DoxygenEntity &,std::string & translatedComment,std::string &)381 void JavaDocConverter::handleNewLine(DoxygenEntity &, std::string &translatedComment, std::string &) {
382 // <br> tag is added, because otherwise to much text is joined
383 // into same paragraph by javadoc. For example, doxy list:
384 // - item one
385 // - item two
386 // becomes one paragraph with surrounding text without newlines.
387 // This way we get to many empty lines in javadoc output, but this
388 // is still better than joined lines. Possibility for improvements
389 // exists.
390 translatedComment += "<br>\n * ";
391 }
392
handleTagChar(DoxygenEntity & tag,std::string & translatedComment,std::string & arg)393 void JavaDocConverter::handleTagChar(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
394 // escape it if we need to, else just print
395 if (arg.size())
396 translatedComment += arg;
397 else
398 translatedComment += tag.typeOfEntity;
399 }
400
401 // handles tags which are the same in Doxygen and Javadoc.
handleTagSame(DoxygenEntity & tag,std::string & translatedComment,std::string & arg)402 void JavaDocConverter::handleTagSame(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
403 if (arg.size())
404 tag.typeOfEntity = arg;
405 translatedComment += formatCommand(std::string("@" + tag.typeOfEntity + " " + translateSubtree(tag)), 2);
406 }
407
handleParagraph(DoxygenEntity & tag,std::string & translatedComment,std::string &)408 void JavaDocConverter::handleParagraph(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
409 translatedComment += formatCommand(translateSubtree(tag), 0);
410 }
411
handlePlainString(DoxygenEntity & tag,std::string & translatedComment,std::string &)412 void JavaDocConverter::handlePlainString(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
413 translatedComment += tag.data;
414 // if (tag.data.size() && tag.data[tag.data.size()-1] != ' ')
415 // translatedComment += " ";
416 }
417
handleTagVerbatim(DoxygenEntity & tag,std::string & translatedComment,std::string & arg)418 void JavaDocConverter::handleTagVerbatim(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
419 translatedComment += arg + " ";
420 for (DoxygenEntityListCIt it = tag.entityList.begin(); it != tag.entityList.end(); it++) {
421 translatedComment += it->data;
422 }
423 }
424
handleTagExtended(DoxygenEntity & tag,std::string & translatedComment,std::string & arg)425 void JavaDocConverter::handleTagExtended(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
426 std::string dummy;
427 translatedComment += "{@" + arg + " ";
428 handleParagraph(tag, translatedComment, dummy);
429 translatedComment += "}";
430 }
431
handleTagIf(DoxygenEntity & tag,std::string & translatedComment,std::string & arg)432 void JavaDocConverter::handleTagIf(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
433 std::string dummy;
434 translatedComment += arg;
435 if (tag.entityList.size()) {
436 translatedComment += tag.entityList.begin()->data;
437 tag.entityList.pop_front();
438 translatedComment += " {" + translateSubtree(tag) + "}";
439 }
440 }
441
handleTagMessage(DoxygenEntity & tag,std::string & translatedComment,std::string & arg)442 void JavaDocConverter::handleTagMessage(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
443 std::string dummy;
444 translatedComment += formatCommand(arg, 0);
445 handleParagraph(tag, translatedComment, dummy);
446 }
447
handleTagImage(DoxygenEntity & tag,std::string & translatedComment,std::string &)448 void JavaDocConverter::handleTagImage(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
449 if (tag.entityList.size() < 2)
450 return;
451
452 std::string file;
453 std::string title;
454
455 std::list<DoxygenEntity>::iterator it = tag.entityList.begin();
456 if (it->data != "html")
457 return;
458
459 it++;
460 file = it->data;
461
462 it++;
463 if (it != tag.entityList.end())
464 title = it->data;
465
466 translatedComment += "<img src=" + file;
467 if (title.size())
468 translatedComment += " alt=" + title;
469
470 // the size indication is supported for Latex only in Doxygen, see manual
471
472 translatedComment += "/>";
473 }
474
handleTagPar(DoxygenEntity & tag,std::string & translatedComment,std::string &)475 void JavaDocConverter::handleTagPar(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
476 std::string dummy;
477 translatedComment += "<p";
478 if (tag.entityList.size()) {
479 translatedComment += " alt=\"" + tag.entityList.begin()->data + "\"";
480 translatedComment += ">";
481 tag.entityList.pop_front();
482 handleParagraph(tag, translatedComment, dummy);
483 }
484 translatedComment += "</p>";
485 }
486
487
handleTagParam(DoxygenEntity & tag,std::string & translatedComment,std::string &)488 void JavaDocConverter::handleTagParam(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
489 std::string dummy;
490
491 if (!tag.entityList.size())
492 return;
493 if (!paramExists(tag.entityList.begin()->data))
494 return;
495
496 translatedComment += "@param ";
497 translatedComment += tag.entityList.begin()->data;
498 tag.entityList.pop_front();
499 handleParagraph(tag, translatedComment, dummy);
500 }
501
502
handleTagRef(DoxygenEntity & tag,std::string & translatedComment,std::string &)503 void JavaDocConverter::handleTagRef(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
504 std::string dummy;
505 if (!tag.entityList.size())
506 return;
507
508 // we translate to link, although \page is not supported in Java, but
509 // reader at least knows what to look at. Also for \anchor tag on the same
510 // page this link works.
511 string anchor = tag.entityList.begin()->data;
512 tag.entityList.pop_front();
513 string anchorText = anchor;
514 if (!tag.entityList.empty()) {
515 anchorText = tag.entityList.begin()->data;
516 }
517 translatedComment += "<a href=\"#" + anchor + "\">" + anchorText + "</a>";
518 }
519
520
convertLink(string linkObject)521 string JavaDocConverter::convertLink(string linkObject) {
522 if (GetFlag(currentNode, "feature:doxygen:nolinktranslate"))
523 return linkObject;
524 // find the params in function in linkObject (if any)
525 size_t lbracePos = linkObject.find('(', 0);
526 size_t rbracePos = linkObject.find(')', 0);
527 if (lbracePos == string::npos || rbracePos == string::npos || lbracePos >= rbracePos)
528 return "";
529
530 string paramsStr = linkObject.substr(lbracePos + 1,
531 rbracePos - lbracePos - 1);
532 // strip the params, to fill them later
533 string additionalObject = linkObject.substr(rbracePos + 1, string::npos);
534 linkObject = linkObject.substr(0, lbracePos);
535
536 // find all the params
537 vector<string> params;
538 size_t lastPos = 0, commaPos = 0;
539 while (true) {
540 commaPos = paramsStr.find(',', lastPos);
541 if (commaPos == string::npos)
542 commaPos = paramsStr.size();
543 string param = paramsStr.substr(lastPos, commaPos - lastPos);
544 // if any param type is empty, we are failed
545 if (!param.size())
546 return "";
547 params.push_back(param);
548 lastPos = commaPos + 1;
549 if (lastPos >= paramsStr.size())
550 break;
551 }
552
553 linkObject += "(";
554 for (size_t i = 0; i < params.size(); i++) {
555 // translate c/c++ type string to swig's type
556 // i e 'int **arr[100][10]' -> 'a(100).a(10).p.p.int'
557 // also converting arrays to pointers
558 string paramStr = params[i];
559 String *swigType = NewString("");
560
561 // handle const qualifier
562 if (paramStr.find("const") != string::npos)
563 SwigType_add_qualifier(swigType, "const");
564
565 // handle pointers, references and arrays
566 for (int j = (int)params[i].size() - 1; j >= 0; j--) {
567 // skip all the [...] blocks, write 'p.' for every of it
568 if (paramStr[j] == ']') {
569 while (j >= 0 && paramStr[j] != '[')
570 j--;
571 // no closing brace
572 if (j < 0)
573 return "";
574 SwigType_add_pointer(swigType);
575 continue;
576 } else if (paramStr[j] == '*')
577 SwigType_add_pointer(swigType);
578 else if (paramStr[j] == '&')
579 SwigType_add_reference(swigType);
580 else if (isalnum(paramStr[j])) {
581 size_t typeNameStart = paramStr.find_last_of(' ', j + 1);
582 if (typeNameStart == string::npos)
583 typeNameStart = 0;
584 else
585 typeNameStart++;
586 Append(swigType, paramStr.substr(typeNameStart, j - typeNameStart + 1).c_str());
587 break;
588 }
589 }
590
591 // make dummy param list, to lookup typemaps for it
592 Parm *dummyParam = NewParm(swigType, "", 0);
593 Swig_typemap_attach_parms("jstype", dummyParam, NULL);
594 Language::instance()->replaceSpecialVariables(0, Getattr(dummyParam, "tmap:jstype"), dummyParam);
595
596 //Swig_print(dummyParam, 1);
597 linkObject += Char(Getattr(dummyParam, "tmap:jstype"));
598 if (i != params.size() - 1)
599 linkObject += ",";
600
601 Delete(dummyParam);
602 Delete(swigType);
603 }
604 linkObject += ")";
605
606 return linkObject + additionalObject;
607 }
608
handleTagLink(DoxygenEntity & tag,std::string & translatedComment,std::string &)609 void JavaDocConverter::handleTagLink(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
610 std::string dummy;
611 if (!tag.entityList.size())
612 return;
613
614 string linkObject = convertLink(tag.entityList.begin()->data);
615 if (!linkObject.size())
616 linkObject = tag.entityList.begin()->data;
617 tag.entityList.pop_front();
618
619 translatedComment += "{@link ";
620 translatedComment += linkObject + " ";
621 handleParagraph(tag, translatedComment, dummy);
622 translatedComment += "}";
623 }
624
handleTagSee(DoxygenEntity & tag,std::string & translatedComment,std::string &)625 void JavaDocConverter::handleTagSee(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
626 std::string dummy;
627 if (!tag.entityList.size())
628 return;
629
630 // tag.entity list contains contents of the @see paragraph. It should contain
631 // one link (references) to method with or without parameters. Doxygen supports
632 // arbitrary text and types mixed, but this feature is not supported here.
633 // :: or # may be used as a separator between class name and method name.
634 list<DoxygenEntity>::iterator it;
635 string methodRef;
636 for (it = tag.entityList.begin(); it != tag.entityList.end(); it++) {
637 if (it->typeOfEntity == "plainstd::endl") {
638 // handleNewLine(*it, translatedComment, dummy);
639 continue;
640 }
641 // restore entities which may be used in C++ type declaration
642 if (it->typeOfEntity == "&") {
643 methodRef += '&';
644 } else if (it->typeOfEntity == "<") {
645 methodRef += '<';
646 } else if (it->typeOfEntity == ">") {
647 methodRef += '>';
648 } else {
649 methodRef += it->data;
650 }
651 }
652
653 // replace :: with #, but only if it appears before left brace
654 size_t lbrace = methodRef.find('(');
655 size_t dblColon = methodRef.find("::");
656 if (dblColon < lbrace) {
657 methodRef = methodRef.substr(0, dblColon) + '#' + methodRef.substr(dblColon + 2);
658 }
659
660 translatedComment += "@see ";
661 string linkObject = convertLink(methodRef);
662 if (!linkObject.size()) {
663 linkObject = methodRef;
664 }
665 translatedComment += linkObject;
666 }
667
668 /* This function moves all line endings at the end of child entities
669 * out of the child entities to the parent.
670 * For example, entity tree:
671
672 -root
673 |-param
674 |-paramText
675 |-endline
676
677 should be turned to
678
679 -root
680 |-param
681 |-paramText
682 |-endline
683 *
684 */
shiftEndlinesUpTree(DoxygenEntity & root,int level)685 int JavaDocConverter::shiftEndlinesUpTree(DoxygenEntity &root, int level) {
686 DoxygenEntityListIt it = root.entityList.begin();
687 while (it != root.entityList.end()) {
688 // remove line endings
689 int ret = shiftEndlinesUpTree(*it, level + 1);
690 // insert them after this element
691 it++;
692 for (int i = 0; i < ret; i++) {
693 root.entityList.insert(it, DoxygenEntity("plainstd::endl"));
694 }
695 }
696
697 // continue only if we are not root
698 if (!level) {
699 return 0;
700 }
701
702 int removedCount = 0;
703 while (!root.entityList.empty()
704 && root.entityList.rbegin()->typeOfEntity == "plainstd::endl") {
705 root.entityList.pop_back();
706 removedCount++;
707 }
708 return removedCount;
709 }
710
711 /**
712 * This makes sure that all comment lines contain '*'. It is not mandatory in doxygen,
713 * but highly recommended for Javadoc. '*' in empty lines are indented according
714 * to indentation of the first line. Indentation of non-empty lines is not
715 * changed - garbage in garbage out.
716 */
indentAndInsertAsterisks(const string & doc)717 std::string JavaDocConverter::indentAndInsertAsterisks(const string &doc) {
718
719 size_t idx = doc.find('\n');
720 size_t indent = 0;
721 bool singleLineComment = idx == string::npos;
722 // Detect indentation.
723 // The first line in comment is the one after '/**', which may be
724 // spaces and '\n' or the text. In any case it is not suitable to detect
725 // indentation, so we have to skip the first '\n'.
726 // However, if there is just one line, then use that line to detect indentation.
727 if (idx != string::npos) {
728 size_t nonspaceIdx = doc.find_first_not_of(" \t", idx + 1);
729 if (nonspaceIdx != string::npos) {
730 indent = nonspaceIdx - idx;
731 }
732 }
733
734 if (indent == 0) {
735 // we can't indent the first line less than 0
736 indent = 1;
737 }
738 // Create the first line of Javadoc comment.
739 string indentStr(indent - 1, ' ');
740 string translatedStr = indentStr + "/**";
741 if (indent > 1) {
742 // remove the first space, so that '*' will be aligned
743 translatedStr = translatedStr.substr(1);
744 }
745
746 translatedStr += doc;
747
748 // insert '*' before each comment line, if it does not have it
749 idx = translatedStr.find('\n');
750
751 while (idx != string::npos) {
752
753 size_t nonspaceIdx = translatedStr.find_first_not_of(" \t", idx + 1);
754 if (nonspaceIdx != string::npos && translatedStr[nonspaceIdx] != '*') {
755 // line without '*' found - is it empty?
756 if (translatedStr[nonspaceIdx] != '\n') {
757 // add '* ' to each line without it
758 translatedStr = translatedStr.substr(0, nonspaceIdx) + "* " + translatedStr.substr(nonspaceIdx);
759 //printf(translatedStr.c_str());
760 } else {
761 // we found empty line, replace it with indented '*'
762 translatedStr = translatedStr.substr(0, idx + 1) + indentStr + "* " + translatedStr.substr(nonspaceIdx);
763 }
764 }
765 idx = translatedStr.find('\n', nonspaceIdx);
766 }
767
768 // Add the last comment line properly indented
769 size_t nonspaceEndIdx = translatedStr.find_last_not_of(" \t");
770 if (nonspaceEndIdx != string::npos) {
771 if (translatedStr[nonspaceEndIdx] != '\n') {
772 if (!singleLineComment)
773 translatedStr += '\n';
774 } else {
775 // remove trailing spaces
776 translatedStr = translatedStr.substr(0, nonspaceEndIdx + 1);
777 }
778 }
779 translatedStr += indentStr + "*/\n";
780
781 return translatedStr;
782 }
783
makeDocumentation(Node * node)784 String *JavaDocConverter::makeDocumentation(Node *node) {
785
786 String *documentation = getDoxygenComment(node);
787
788 if (documentation == NULL) {
789 return NewString("");
790 }
791
792 if (GetFlag(node, "feature:doxygen:notranslate")) {
793
794 string doc = Char(documentation);
795
796 string translatedStr = indentAndInsertAsterisks(doc);
797
798 return NewString(translatedStr.c_str());
799 }
800
801 DoxygenEntityList entityList = parser.createTree(node, documentation);
802
803 // entityList.sort(CompareDoxygenEntities()); sorting currently not used,
804
805 if (m_flags & debug_translator) {
806 std::cout << "---RESORTED LIST---" << std::endl;
807 printTree(entityList);
808 }
809 // store the current node
810 // (currently just to handle params)
811 currentNode = node;
812
813 std::string javaDocString = "/**\n * ";
814
815 DoxygenEntity root("root", entityList);
816
817 shiftEndlinesUpTree(root);
818
819 // strip line endings at the beginning
820 while (!root.entityList.empty()
821 && root.entityList.begin()->typeOfEntity == "plainstd::endl") {
822 root.entityList.pop_front();
823 }
824
825 // and at the end
826 while (!root.entityList.empty()
827 && root.entityList.rbegin()->typeOfEntity == "plainstd::endl") {
828 root.entityList.pop_back();
829 }
830
831 javaDocString += translateSubtree(root);
832
833 javaDocString += "\n */\n";
834
835 if (m_flags & debug_translator) {
836 std::cout << "\n---RESULT IN JAVADOC---" << std::endl;
837 std::cout << javaDocString;
838 }
839
840 return NewString(javaDocString.c_str());
841 }
842
addError(int warningType,const std::string & message)843 void JavaDocConverter::addError(int warningType, const std::string &message) {
844 Swig_warning(warningType, "", 0, "Doxygen parser warning: %s. \n", message.c_str());
845 }
846