283b622013-03-26Martin Nilsson #pike __REAL_VERSION__
3756b82011-11-16Henrik Grubbström (Grubba) //! AutoDoc XML to HTML converter. //! //! @seealso //! @[tree_split] constant description = "AutoDoc XML to HTML converter."; #define Node Parser.XML.Tree.SimpleNode #define XML_COMMENT Parser.XML.Tree.XML_COMMENT #define XML_ELEMENT Parser.XML.Tree.XML_ELEMENT #define XML_TEXT Parser.XML.Tree.XML_TEXT #define DEBUG Tools.AutoDoc.Flags flags = Tools.AutoDoc.FLAG_NORMAL; int verbosity = Tools.AutoDoc.FLAG_VERBOSE; //NORMAL;
3524712015-05-26Martin Nilsson function resolve_reference;
3756b82011-11-16Henrik Grubbström (Grubba) string image_path = "images/"; string dest_path; string default_ns; //! Layout template headers and trailers. mapping lay = ([
e0da342015-10-12Pontus Östlund  "docgroup" : "\n\n<hr />\n<dl class='group--doc'>",
3756b82011-11-16Henrik Grubbström (Grubba)  "_docgroup" : "</dl>\n", "ndochead" : "<dd><p>", "_ndochead" : "</p></dd>\n",
e0da342015-10-12Pontus Östlund  "dochead" : "\n<dt class='head--doc'>",
3756b82011-11-16Henrik Grubbström (Grubba)  "_dochead" : "</dt>\n",
e0da342015-10-12Pontus Östlund  "typehead" : "\n<dt class='head--type'>",
3756b82011-11-16Henrik Grubbström (Grubba)  "_typehead" : "</dt>\n",
e0da342015-10-12Pontus Östlund  "docbody" : "<dd class='body--doc'>",
3756b82011-11-16Henrik Grubbström (Grubba)  "_docbody" : "</dd>",
e0da342015-10-12Pontus Östlund  "fixmehead" : "<dt class='head--fixme'>",
3756b82011-11-16Henrik Grubbström (Grubba)  "_fixmehead" : "</dt>\n",
e0da342015-10-12Pontus Östlund  "fixmebody" : "<dd class='body--fixme'>",
3756b82011-11-16Henrik Grubbström (Grubba)  "_fixmebody" : "</dd>",
e0da342015-10-12Pontus Östlund  "parameter" : "<code class='parameter'>", "_parameter" : "</code>", "example" : "<dd class='example'><pre>",
3756b82011-11-16Henrik Grubbström (Grubba)  "_example" : "</pre></dd>",
e0da342015-10-12Pontus Östlund  "pre" : "<pre>", "_pre" : "</pre>", "code" : "<pre><code>", "_code" : "</code></pre>", "expr" : "<code class='expr'>", "_expr" : "</code>",
3756b82011-11-16Henrik Grubbström (Grubba)  ]); //! Path to where in the destination filesystem the images are. string image_prefix() { return image_path;
3524712015-05-26Martin Nilsson }
3756b82011-11-16Henrik Grubbström (Grubba)  class Position { string file; int line; void update(Node n) { mapping m = n->get_attributes(); if(!m->file || !m["first-line"]) { werror("Missing attribute in source-position element. %O\n", m); return; } file = m->file; line = (int) m["first-line"]; } string get() { return file + ":" + line; } } Position position = Position(); string quote(string in) { if(in-" "-"\t"=="") return "";
8ff89d2016-07-04Martin Nilsson  if(String.trim(in)=="") return "\n";
3756b82011-11-16Henrik Grubbström (Grubba)  return Parser.XML.Tree.text_quote(in); }
66557c2011-11-26Henrik Grubbström (Grubba) string render_tag(string tag, mapping(string:string) attrs, int|void term) { string res = "<" + tag; foreach(sort(indices(attrs)), string attr) { res += " " + attr + "='" + attrs[attr] + "'"; } if (term) res += " /"; return res + ">"; }
60f2ae2012-02-05Henrik Grubbström (Grubba) Node get_first_element(Node n) { if (!n) return UNDEFINED;
3756b82011-11-16Henrik Grubbström (Grubba)  foreach(n->get_children(), Node c) if(c->get_node_type()==XML_ELEMENT) { if(c->get_any_name()!="source-position") return c; else position->update(c); }
60f2ae2012-02-05Henrik Grubbström (Grubba)  return UNDEFINED;
3756b82011-11-16Henrik Grubbström (Grubba) } int section, subsection; string low_parse_chapter(Node n, int chapter) { string ret = ""; Node dummy = Node(XML_ELEMENT, "dummy", ([]), ""); foreach(n->get_elements(), Node c) switch(c->get_any_name()) { case "p": dummy->replace_children( ({ c }) ); ret += parse_text(dummy); break; case "example":
e0da342015-10-12Pontus Östlund  ret += "<p></p><pre>" + quote(c->value_of_node()) + "</pre><p></p>\n";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "ul": case "ol": ret += (string)c; break; case "dl": ret += "<dl>\n"; foreach(c->get_elements(), Node cc) { string tag = cc->get_any_name(); if(tag!="dt" && tag!="dd") error("dl contained element %O.\n", tag); ret += "<" + tag + ">" + parse_text(cc) + "</" + tag + ">\n"; } ret += "</dl>"; break; case "matrix": ret += layout_matrix( map(c->get_elements("r")->get_elements("c"), map, parse_text) ); break; case "section": if(section) error("Section inside section.\n"); if(subsection) error("Section inside subsection.\n"); section = (int)c->get_attributes()->number; ret += "</dd>\n<dt><a name='" + section + "'></a>\n"
058f0d2016-01-20Pontus Östlund  "<h2 class='header'>" + chapter + "." + section +
3756b82011-11-16Henrik Grubbström (Grubba)  ". " + quote(c->get_attributes()->title || // The following for bug compat. c->get_attributes()->name) +
058f0d2016-01-20Pontus Östlund  "</h2></dt>\n<dd>";
3756b82011-11-16Henrik Grubbström (Grubba)  ret += low_parse_chapter(c, chapter); section = 0; break; case "subsection": if(!section) error("Subsection outside section.\n"); if(subsection) error("Subsection inside subsection.\n"); subsection = (int)c->get_attributes()->number; ret += "</dd><dt>"
058f0d2016-01-20Pontus Östlund  "<h3 class='header'>" + chapter + "." + section + "." + subsection +
3756b82011-11-16Henrik Grubbström (Grubba)  ". " + quote(c->get_attributes()->title) +
058f0d2016-01-20Pontus Östlund  "</h3></dt><dd>";
3756b82011-11-16Henrik Grubbström (Grubba)  ret += low_parse_chapter(c, chapter); subsection = 0; break; case "docgroup": ret += parse_docgroup(c); break; case "autodoc": ret += parse_autodoc(c); break; case "namespace": ret += parse_namespace(c); break; case "module": ret += parse_module(c); break; case "class": ret += parse_class(c); break; case "enum": ret += parse_enum(c); break; default: if (!(flags & Tools.AutoDoc.FLAG_KEEP_GOING)) { error("Unknown element %O.\n", c->get_any_name()); } break; } return ret; } string parse_chapter(Node n, void|int noheader) { string ret = ""; if(!noheader) { ret += "<dl><dt>"
058f0d2016-01-20Pontus Östlund  "<h1 class='header'>";
3756b82011-11-16Henrik Grubbström (Grubba)  if(n->get_attributes()->number) ret += n->get_attributes()->number + ". "; ret += quote(n->get_attributes()->title) +
058f0d2016-01-20Pontus Östlund  "</h1>"
3756b82011-11-16Henrik Grubbström (Grubba)  "</dt><dd>"; } ret += low_parse_chapter(n, (int)n->get_attributes()->number); if(!noheader)
3524712015-05-26Martin Nilsson  ret = ret + "</dd></dl>";
3756b82011-11-16Henrik Grubbström (Grubba)  return ret; }
c75acb2012-02-11Henrik Grubbström (Grubba) string parse_appendix(Node n, void|int noheader) { string ret =""; if(!noheader) ret += "<dl><dt>"
058f0d2016-01-20Pontus Östlund  "<h2 class='header'>Appendix " +
c75acb2012-02-11Henrik Grubbström (Grubba)  (string)({ 64+(int)n->get_attributes()->number }) + ". " +
058f0d2016-01-20Pontus Östlund  n->get_attributes()->name + "</h2>\n"
c75acb2012-02-11Henrik Grubbström (Grubba)  "</dt><dd>"; Node c = n->get_first_element("doc"); if(c) ret += parse_text(c); else error( "No doc element in appendix.\n" ); #ifdef DEBUG if(sizeof(n->get_elements("doc"))>1) error( "More than one doc element in appendix node.\n" ); #endif if(!noheader)
3524712015-05-26Martin Nilsson  ret = ret + "</dd></dl>";
c75acb2012-02-11Henrik Grubbström (Grubba)  return ret; }
3756b82011-11-16Henrik Grubbström (Grubba) string parse_autodoc(Node n) { string ret =""; mapping m = n->get_attributes(); Node c = n->get_first_element("doc"); if(c) ret += "<dl>" + parse_doc(c) + "</dl>"; if((sizeof(n->get_elements("doc"))>1) && ((flags & (Tools.AutoDoc.FLAG_KEEP_GOING|Tools.AutoDoc.FLAG_DEBUG)) == Tools.AutoDoc.FLAG_DEBUG)) { error( "More than one doc element in autodoc node.\n" ); } ret += parse_children(n, "docgroup", parse_docgroup); ret += parse_children(n, "namespace", parse_namespace); return ret; } string parse_namespace(Node n, void|int noheader) { string ret = ""; mapping m = n->get_attributes(); int(0..1) header = !noheader && !(m->hidden) && m->name!=default_ns; if(header) ret += "<dl><dt>"
058f0d2016-01-20Pontus Östlund  "<h2 class='header'>Namespace <b class='ms datatype'>" + m->name + "::</b></h2>\n"
3756b82011-11-16Henrik Grubbström (Grubba)  "</dt><dd>"; Node c = n->get_first_element("doc"); if(c)
058f0d2016-01-20Pontus Östlund  ret += "<dl class='group--doc'>" + parse_doc(c) + "</dl>";
3756b82011-11-16Henrik Grubbström (Grubba)  if((sizeof(n->get_elements("doc"))>1) && ((flags & (Tools.AutoDoc.FLAG_KEEP_GOING|Tools.AutoDoc.FLAG_DEBUG)) == Tools.AutoDoc.FLAG_DEBUG)) { error( "More than one doc element in namespace node.\n" ); } ret += parse_children(n, "docgroup", parse_docgroup, noheader); ret += parse_children(n, "enum", parse_enum, noheader); ret += parse_children(n, "class", parse_class, noheader); ret += parse_children(n, "module", parse_module, noheader); if(header)
3524712015-05-26Martin Nilsson  ret += "</dd></dl>";
3756b82011-11-16Henrik Grubbström (Grubba)  return ret; } string parse_module(Node n, void|int noheader) { string ret =""; mapping m = n->get_attributes(); int(0..1) header = !noheader && !(m->hidden); if(header) ret += "<dl><dt>"
058f0d2016-01-20Pontus Östlund  "<h2 class='header'>Module <b class='ms datatype'>" + m->class_path + m->name + "</b></h2>\n"
3756b82011-11-16Henrik Grubbström (Grubba)  "</dt><dd>"; Node c = n->get_first_element("doc"); if(c)
058f0d2016-01-20Pontus Östlund  ret += "<dl class='group--doc'>" + parse_doc(c) + "</dl>";
3756b82011-11-16Henrik Grubbström (Grubba)  if((sizeof(n->get_elements("doc"))>1) && ((flags & (Tools.AutoDoc.FLAG_KEEP_GOING|Tools.AutoDoc.FLAG_DEBUG)) == Tools.AutoDoc.FLAG_DEBUG)) { error( "More than one doc element in module node.\n" ); } ret += parse_children(n, "docgroup", parse_docgroup, noheader); ret += parse_children(n, "enum", parse_enum, noheader); ret += parse_children(n, "class", parse_class, noheader); ret += parse_children(n, "module", parse_module, noheader); if(header)
e894cb2014-08-25Per Hedbor  ret += "</dd></dl>";
3756b82011-11-16Henrik Grubbström (Grubba)  return ret; }
abe61e2014-08-20Per Hedbor ADT.Stack old_class_name = ADT.Stack();
3756b82011-11-16Henrik Grubbström (Grubba) string parse_class(Node n, void|int noheader) { string ret =""; if(!noheader) ret += "<dl><dt>"
058f0d2016-01-20Pontus Östlund  "<h2 class='header'>Class <b class='ms datatype'>" +
3756b82011-11-16Henrik Grubbström (Grubba)  n->get_attributes()->class_path + n->get_attributes()->name +
058f0d2016-01-20Pontus Östlund  "</b></h2>\n"
3756b82011-11-16Henrik Grubbström (Grubba)  "</dt><dd>"; Node c = n->get_first_element("doc");
abe61e2014-08-20Per Hedbor  old_class_name->push(class_name); class_name = n->get_attributes()->class_path+n->get_attributes()->name;
3756b82011-11-16Henrik Grubbström (Grubba)  if(c)
058f0d2016-01-20Pontus Östlund  ret += "<dl class='group--doc'>" + parse_doc(c) + "</dl>";
3756b82011-11-16Henrik Grubbström (Grubba)  if((sizeof(n->get_elements("doc"))>1) && ((flags & (Tools.AutoDoc.FLAG_KEEP_GOING|Tools.AutoDoc.FLAG_DEBUG)) == Tools.AutoDoc.FLAG_DEBUG)) { error( "More than one doc element in class node.\n" ); } ret += parse_children(n, "docgroup", parse_docgroup);
e0da342015-10-12Pontus Östlund  ret += parse_children(n, "enum", parse_enum, noheader);
3756b82011-11-16Henrik Grubbström (Grubba)  ret += parse_children(n, "class", parse_class, noheader);
1114432014-08-22Henrik Grubbström (Grubba)  ret += parse_children(n, "module", parse_module, noheader);
3756b82011-11-16Henrik Grubbström (Grubba)  if(!noheader) ret += "</dd></dl>";
abe61e2014-08-20Per Hedbor  class_name = old_class_name->pop();
3756b82011-11-16Henrik Grubbström (Grubba)  return ret; } string parse_enum(Node n, void|int noheader) { string ret ="";
e0da342015-10-12Pontus Östlund  if(!noheader) {
3756b82011-11-16Henrik Grubbström (Grubba)  ret += "<dl><dt>"
058f0d2016-01-20Pontus Östlund  "<h2 class='header'>Enum <b class='ms datatype'>" +
3756b82011-11-16Henrik Grubbström (Grubba)  n->get_attributes()->class_path + n->get_attributes()->name +
058f0d2016-01-20Pontus Östlund  "</b></h2>\n"
3756b82011-11-16Henrik Grubbström (Grubba)  "</dt><dd>";
e0da342015-10-12Pontus Östlund  }
3756b82011-11-16Henrik Grubbström (Grubba)  Node c = n->get_first_element("doc"); if(c)
058f0d2016-01-20Pontus Östlund  ret += "<dl class='group--doc'>" + parse_doc(c) + "</dl>";
3756b82011-11-16Henrik Grubbström (Grubba)  if((sizeof(n->get_elements("doc"))>1) && ((flags & (Tools.AutoDoc.FLAG_KEEP_GOING|Tools.AutoDoc.FLAG_DEBUG)) == Tools.AutoDoc.FLAG_DEBUG)) { error( "More than one doc element in enum node.\n" ); } ret += parse_children(n, "docgroup", parse_docgroup); if(!noheader) ret += "</dd></dl>"; return ret; } string layout_matrix( array(array(string)) rows ) {
e0da342015-10-12Pontus Östlund 
058f0d2016-01-20Pontus Östlund  string ret = "<table class='box'>\n";
3756b82011-11-16Henrik Grubbström (Grubba) 
e0da342015-10-12Pontus Östlund 
3756b82011-11-16Henrik Grubbström (Grubba)  int dim; foreach(rows, array row) dim = max(dim, sizeof(row)); foreach(rows, array row) {
058f0d2016-01-20Pontus Östlund  ret += "<tr>";
3756b82011-11-16Henrik Grubbström (Grubba)  if(sizeof(row)<dim)
058f0d2016-01-20Pontus Östlund  ret += "<td>" + row[..sizeof(row)-2]*"</td><td>" + "</td><td colspan='"+ (dim-sizeof(row)) + "'>" + row[-1] + "</td>";
3756b82011-11-16Henrik Grubbström (Grubba)  else
058f0d2016-01-20Pontus Östlund  ret += "<td>" + row*"</td><td>" + "</td>";
3756b82011-11-16Henrik Grubbström (Grubba)  ret += "</tr>\n"; }
058f0d2016-01-20Pontus Östlund  return ret + "</table>\n";
3756b82011-11-16Henrik Grubbström (Grubba) } // ({ ({ array(string)+, void|string })* }) void nicebox(array rows, String.Buffer ret) {
e0da342015-10-12Pontus Östlund  ret->add("<table class='box'>"); int dim; foreach (rows, array row) { dim = max(dim, sizeof(row)); } foreach (rows, array row) { if (sizeof(row) == 1) { if (stringp(row[0])) { ret->add("<tr><td colspan='", (string)dim, "'>", row[0], "</td></tr>\n"); } else { foreach (row[0], string elem) {
f069a52016-04-19Pontus Östlund  ret->add("<tr><td><code>", elem, "</code></td>",
e0da342015-10-12Pontus Östlund  (dim == 2 ? "<td>&nbsp;</td>" : ""), "</tr>\n"); } } } else if (sizeof(row[0]) == 1) {
f069a52016-04-19Pontus Östlund  ret->add("<tr><td><code>", row[0][0], "</code></td>",
e0da342015-10-12Pontus Östlund  "<td>", row[1], "</td></tr>\n"); } else {
f069a52016-04-19Pontus Östlund  ret->add("<tr><td><code>", row[0][0], "</code></td>",
e0da342015-10-12Pontus Östlund  "<td rowspan='", (string)sizeof(row[0]), "'>", row[1], "</td></tr>\n"); foreach (row[0][1..], string elem) {
f069a52016-04-19Pontus Östlund  ret->add("<tr><td><code>", elem, "</code></td></tr>\n");
e0da342015-10-12Pontus Östlund  } } } ret->add("</table>");
3756b82011-11-16Henrik Grubbström (Grubba) } void build_box(Node n, String.Buffer ret, string first, string second, function layout, void|string header) {
e0da342015-10-12Pontus Östlund  //werror("build_box: %O\n", n);
3756b82011-11-16Henrik Grubbström (Grubba)  array rows = ({}); if(header) rows += ({ ({ header }) }); foreach(n->get_elements(first), Node d) { array elems = ({}); foreach(d->get_elements(second), Node e) elems += ({ layout(e) }); if(d->get_first_element("text")) rows += ({ ({ elems, parse_text(d->get_first_element("text")) }) }); else rows += ({ ({ elems }) }); } nicebox(rows, ret); }
6024172013-12-16Per Hedbor // type(min..max) string range_type( string type, Node min, Node max ) {
f9c5072014-02-09Chris Angelico  // Work with plain text; if there's no node, that's the same as an empty node. string min_text = min ? parse_text(min) : ""; string max_text = max ? parse_text(max) : ""; if( min_text == "" && max_text == "" )
6024172013-12-16Per Hedbor  return type;
f9c5072014-02-09Chris Angelico  if( min_text == "" ) return type+"(.."+max_text+")"; if( max_text == "" ) return type+"("+min_text+"..)";
6024172013-12-16Per Hedbor 
f9c5072014-02-09Chris Angelico  int low = (int)min_text; int high = (int)max_text;
6024172013-12-16Per Hedbor 
f9c5072014-02-09Chris Angelico  if( low == 0 && high && (high+1)->popcount() == 1 )
6024172013-12-16Per Hedbor  {
e894cb2014-08-25Per Hedbor  if( high == 1 && type == "int" ) return "bool"; return type+"("+strlen((high)->digits(2))+"bit)";
6024172013-12-16Per Hedbor  } return type+"("+low+".."+high+")"; }
e0da342015-10-12Pontus Östlund Tools.Standalone.pike_to_html code_highlighter; // Normalizes indentation of @code ... @endcode blocks. // Also tries to syntax highlight code that looks like Pike. string parse_code(Node n, void|String.Buffer ret) { string text; if (n->get_tag_name() != "code") { return parse_text(n, ret); } array(string) lines = n->get_children()[0]->get_children()->value_of_node(); if (!sizeof(lines)) { return parse_text(n, ret); } if (sizeof(lines) && lines[-1] == "\n") { lines[0..<1]; } if (sizeof(lines) > 1) { for (int i = 0; i < sizeof(lines); i++) { string ln = map(lines[i]/"\n", lambda (string s) { if (has_prefix(s, " ")) s = s[1..]; return s; }) * "\n"; if (!has_suffix(ln, "\n")) ln += "\n"; lines[i] = ln; } text = lines*""; } else { text = lines*""; } if (sizeof(text) && text[-1] == '\n'); text = text[..<1]; while (text[-1] == '\n') text = text[..<1];
bc2d6b2016-11-04Pontus Östlund  if (search(text, "->") > -1 || (search(text, "{") > -1 && search(text, "}") > -1) || (search(text, "(") > -1 && search(text, "\"") > -1) || (search(text, ".") > -1 && search(text, "=") > -1)) {
e0da342015-10-12Pontus Östlund  if (!code_highlighter) { code_highlighter = Tools.Standalone.pike_to_html(); } if (catch(text = code_highlighter->convert(text))) { text = text; } } if (ret) { ret->add(text); } else return quote(text); }
2dfb472011-12-03Henrik Grubbström (Grubba) //! Typically called with a <group/> node or a sub-node that is a container.
3756b82011-11-16Henrik Grubbström (Grubba) string parse_text(Node n, void|String.Buffer ret) { if(n->get_node_type()==XML_TEXT && n->get_text()) { if(ret)
e0da342015-10-12Pontus Östlund  ret->add("parse_text:#1:", quote(n->get_text()));
3756b82011-11-16Henrik Grubbström (Grubba)  else
e0da342015-10-12Pontus Östlund  return quote("parse_text:#1:" + n->get_text());
3756b82011-11-16Henrik Grubbström (Grubba)  } int cast; if(!ret) { ret = String.Buffer(); cast = 1; } foreach(n->get_children(), Node c) { int node_type = c->get_node_type(); if(c->get_node_type()==XML_TEXT) { // Don't use quote() here since we don't want to strip whitespace. ret->add(Parser.XML.Tree.text_quote (c->get_text())); continue; } if(c->get_node_type()==XML_COMMENT) continue; if((c->get_node_type()!=XML_ELEMENT) && ((flags & (Tools.AutoDoc.FLAG_KEEP_GOING|Tools.AutoDoc.FLAG_DEBUG)) == Tools.AutoDoc.FLAG_DEBUG)) { error( "Forbidden node type " + c->get_node_type() + " in doc node.\n" ); } array rows; string name = c->get_any_name(); switch(name) { case "text": ret->add("<dd>"); parse_text(c, ret); ret->add("</dd>\n"); break; case "p": case "b": case "i": case "tt": case "sub": case "sup": ret->add("<", name, ">"); parse_text(c, ret); ret->add("</", name, ">"); break; case "pre": ret->add(lay->pre); parse_text(c, ret); ret->add(lay->_pre); break; case "code": ret->add(lay->code);
e0da342015-10-12Pontus Östlund  parse_code(c, ret);
3756b82011-11-16Henrik Grubbström (Grubba)  ret->add(lay->_code); break; case "expr": ret->add(lay->expr, replace(parse_text(c), " ", "&nbsp;"), lay->_expr); break; case "ref": if(resolve_reference) { ret->add(resolve_reference(parse_text(c), c->get_attributes())); break; } string ref; //ref = c->get_attributes()->resolved; if(!ref) ref = parse_text(c);
f069a52016-04-19Pontus Östlund  ret->add("<code>", ref, "</code>");
3756b82011-11-16Henrik Grubbström (Grubba)  break;
f995462015-08-21Henrik Grubbström (Grubba)  case "rfc":
0c4ea52015-08-22Martin Nilsson  { string rfc = upper_case(parse_text(c)); string section; sscanf(rfc, "%[0-9]:%[.A-Z0-9]", rfc, section); if (sizeof(rfc) < 4) rfc = ("0000" + rfc)[<3..];
f4c8182015-08-24Henrik Grubbström (Grubba)  ret->add("<b><a href='http://pike.lysator.liu.se/rfc", rfc, ".xml");
0c4ea52015-08-22Martin Nilsson  if( section && sizeof(section) ) ret->add("#", section); else section = 0; ret->add("'>RFC ", rfc); if( section ) { if( section[0] > '9' ) ret->add(" appendix "); else ret->add(" section "); ret->add(section); } ret->add("</a></b>"); }
f995462015-08-21Henrik Grubbström (Grubba)  break;
3756b82011-11-16Henrik Grubbström (Grubba)  case "dl":
058f0d2016-01-20Pontus Östlund  ret->add("<dl class='group--doc'>", map(c->get_elements("group"), parse_text)*"", "</dl>");
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "item":
4e7de02014-04-02Henrik Grubbström (Grubba)  if(c->get_attributes()->name) {
3756b82011-11-16Henrik Grubbström (Grubba)  ret->add("<dt>", c->get_attributes()->name, "</dt>\n");
4e7de02014-04-02Henrik Grubbström (Grubba)  if(c->count_children() && ((flags & (Tools.AutoDoc.FLAG_KEEP_GOING|Tools.AutoDoc.FLAG_DEBUG)) == Tools.AutoDoc.FLAG_DEBUG)) { error( "dl item has a child.\n" ); } } else if (c->count_children()) { ret->add("<dt>"); parse_text(c, ret); ret->add("</dt>");
3756b82011-11-16Henrik Grubbström (Grubba)  } break; case "mapping": build_box(c, ret, "group", "member", lambda(Node n) {
2dfb472011-12-03Henrik Grubbström (Grubba)  string res = ""; Node nn = n->get_first_element("index"); if (nn) { res +=
f069a52016-04-19Pontus Östlund  "<code class='key'>" + parse_text(nn) + "</code> : ";
2dfb472011-12-03Henrik Grubbström (Grubba)  } nn = n->get_first_element("type"); if (nn) { res += parse_type(get_first_element(nn)); } return res;
3756b82011-11-16Henrik Grubbström (Grubba)  }); break; case "array": build_box(c, ret, "group", "elem", lambda(Node n) { string index =""; if(n->get_first_element("index")) index = parse_text(n->get_first_element("index")); else { if(n->get_first_element("minindex")) index = parse_text(n->get_first_element("minindex")); index += ".."; if(n->get_first_element("maxindex")) index += parse_text(n->get_first_element("maxindex")); } return parse_type(get_first_element(n->get_first_element("type"))) +
f069a52016-04-19Pontus Östlund  " <code class='key'>" + index + "</code>"; }, "Array" );
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "int": build_box(c, ret, "group", "value", lambda(Node n) {
f069a52016-04-19Pontus Östlund  return "<code class='key'>" +
6024172013-12-16Per Hedbor  range_type( parse_text(n), n->get_first_element("minvalue"), n->get_first_element("maxvalue"))+
f069a52016-04-19Pontus Östlund  "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  } ); break; case "mixed": if(c->get_attributes()->name)
f069a52016-04-19Pontus Östlund  ret->add("<code>", c->get_attributes()->name, "</code> can have any of the following types:<br />");
3756b82011-11-16Henrik Grubbström (Grubba)  rows = ({}); foreach(c->get_elements("group"), Node d) rows += ({ ({ ({ parse_type(get_first_element(d->get_first_element("type"))) }), parse_text(d->get_first_element("text")) }) }); nicebox(rows, ret); break; case "string": // Not in XSLT build_box(c, ret, "group", "value", lambda(Node n) {
f069a52016-04-19Pontus Östlund  return "<code class='key'>" +
6024172013-12-16Per Hedbor  range_type( parse_text(n), n->get_first_element("min"), n->get_first_element("max")) +
f069a52016-04-19Pontus Östlund  "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  } ); break; case "multiset": // Not in XSLT build_box(c, ret, "group", "index", lambda(Node n) {
f069a52016-04-19Pontus Östlund  return "<code class='key'>" + parse_text(n->get_first_element("value")) + "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  } ); break; case "image": // Not in XSLT mapping m = c->get_attributes(); m->src = image_prefix() + m_delete(m, "file");
66557c2011-11-26Henrik Grubbström (Grubba)  ret->add( render_tag("img", m, 1) );
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "url": // Not in XSLT if((c->count_children()!=1 && c->get_node_type()!=XML_ELEMENT) && ((flags & (Tools.AutoDoc.FLAG_KEEP_GOING|Tools.AutoDoc.FLAG_DEBUG)) == Tools.AutoDoc.FLAG_DEBUG)) { error( "url node has not one child. %O\n", c->html_of_node() ); } m = c->get_attributes(); if(!m->href) m->href=c->value_of_node();
66557c2011-11-26Henrik Grubbström (Grubba)  ret->add( sprintf("%s%s</a>", render_tag("a", m), c->value_of_node()) );
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "section": if(section && !(flags & Tools.AutoDoc.FLAG_KEEP_GOING)) error("Section inside section.\n"); ret->add ("<h2>", quote (c->get_attributes()->title || // The following for bug compat. c->get_attributes()->name), "</h2>\n"); if (!equal (c->get_children()->get_any_name(), ({"text"})) && !(flags & Tools.AutoDoc.FLAG_KEEP_GOING)) error ("Expected a single <text> element inside <section>.\n"); section = -1; parse_text (c->get_children()[0], ret); section = 0; break; case "ul": ret->add( "<ul>\n" ); foreach(c->get_elements("group"), Node c) { ret->add("<li>"); array(Node) d = c->get_elements("item"); if(sizeof(d->get_attributes()->name-({0}))) { ret->add("<b>"); ret->add( String.implode_nicely(d->get_attributes()->name-({0})) ); ret->add("</b>"); } Node e = c->get_first_element("text"); if(e) parse_text(e, ret); ret->add("</li>"); } ret->add("</ul>"); break; case "ol": ret->add("<ol>\n"); foreach(c->get_elements("group"), Node c) { ret->add("<li>"); parse_text(c->get_first_element("text"), ret); ret->add("</li>"); } ret->add("</ol>"); break; case "source-position": position->update(c); break; case "matrix": ret->add( layout_matrix( map(c->get_elements("r")->get_elements("c"), map, parse_text) ) ); break; case "fixme":
e0da342015-10-12Pontus Östlund  ret->add("<span class='fixme'>FIXME: ");
3756b82011-11-16Henrik Grubbström (Grubba)  parse_text(c, ret);
e0da342015-10-12Pontus Östlund  ret->add("</span>");
3756b82011-11-16Henrik Grubbström (Grubba)  break; // Not really allowed case "br":
66557c2011-11-26Henrik Grubbström (Grubba)  ret->add( render_tag(c->get_any_name(), c->get_attributes(), 1) );
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "table": case "td": case "tr": case "th":
66557c2011-11-26Henrik Grubbström (Grubba)  ret->add( sprintf("%s%s</%s>", render_tag(c->get_any_name(), c->get_attributes()),
3756b82011-11-16Henrik Grubbström (Grubba)  parse_text(c), c->get_any_name()) ); break; default: if (verbosity >= Tools.AutoDoc.FLAG_DEBUG) { werror("\n%s\n", (string)c); error( "Illegal element \"" + name + "\" in mode text.\n" ); } break; } } if(cast) return ret->get(); } string parse_doc(Node n, void|int no_text) { string ret =""; Node c = n->get_first_element("text");
f069a52016-04-19Pontus Östlund  if(c) {
3756b82011-11-16Henrik Grubbström (Grubba)  ret += lay->dochead + "Description" + lay->_dochead + lay->docbody + parse_text(c) + lay->_docbody;
f069a52016-04-19Pontus Östlund  } #define MAKE_ID(N) ("<span id='p-" + N + "'></span>")
3756b82011-11-16Henrik Grubbström (Grubba)  foreach(n->get_elements("group"), Node c) { Node header = c->get_first_element(); string name = header->get_any_name(); switch(name) { case "param":
f069a52016-04-19Pontus Östlund  foreach(c->get_elements("param"), Node d) { string name = quote(d->get_attributes()->name || ""); ret += lay->dochead + MAKE_ID(name) + "Parameter " + lay->parameter + name + lay->_parameter + lay->_dochead +
3756b82011-11-16Henrik Grubbström (Grubba)  "<dd></dd>";
f069a52016-04-19Pontus Östlund  }
3756b82011-11-16Henrik Grubbström (Grubba)  if (c = c->get_first_element("text")) { ret += lay->docbody + parse_text(c) + lay->_docbody; } break; case "seealso": ret += lay->dochead + "See also" + lay->_dochead; if (c = c->get_first_element("text")) { ret += lay->docbody + parse_text(c) + lay->_docbody; } break; case "fixme": ret += lay->fixmehead + "FIXME" + lay->_fixmehead; if (c = c->get_first_element("text")) { ret += lay->fixmebody + parse_text(c) + lay->_fixmebody; } break; case "deprecated": ret += lay->dochead + String.capitalize(name) + lay->_dochead; array(Node) replacements = header->get_elements("name"); if (sizeof(replacements)) { ret += lay->docbody + "<p>Replaced by " + String.implode_nicely(map(replacements, parse_text)) + ".</p>\n" + lay->_docbody; } if (c = c->get_first_element("text")) { ret += lay->docbody + parse_text(c) + lay->_docbody; } break; case "bugs":
28d4fc2011-12-03Henrik Grubbström (Grubba)  case "copyright":
3756b82011-11-16Henrik Grubbström (Grubba)  case "note": case "returns":
28d4fc2011-12-03Henrik Grubbström (Grubba)  case "thanks":
3756b82011-11-16Henrik Grubbström (Grubba)  case "throws": ret += lay->dochead + String.capitalize(name) + lay->_dochead;
a55a212011-12-18Henrik Grubbström (Grubba)  // FALL_THROUGH case "text":
3756b82011-11-16Henrik Grubbström (Grubba)  if (c = c->get_first_element("text")) { ret += lay->docbody + parse_text(c) + lay->_docbody; } break; case "example": ret += lay->dochead + "Example" + lay->_dochead; if (c = c->get_first_element("text")) { ret += lay->example + parse_text(c) + lay->_example; } break; default: error( "Unknown group type \"" + name + "\".\n" ); } } return ret; } string parse_type(Node n, void|string debug) {
2dfb472011-12-03Henrik Grubbström (Grubba)  if(!n || (n->get_node_type()!=XML_ELEMENT))
3756b82011-11-16Henrik Grubbström (Grubba)  return ""; string ret = ""; Node c, d; switch(n->get_any_name()) { case "object": if(n->count_children()) { if (resolve_reference) {
f069a52016-04-19Pontus Östlund  ret += "<code class='object resolved'>" +
3756b82011-11-16Henrik Grubbström (Grubba)  resolve_reference(n->value_of_node(), n->get_attributes()) +
f069a52016-04-19Pontus Östlund  "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  } else {
f069a52016-04-19Pontus Östlund  ret += "<code class='object unresolved'>" + n->value_of_node() + "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  } } else
f069a52016-04-19Pontus Östlund  ret += "<code class='datatype'>object</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "type":
f069a52016-04-19Pontus Östlund  ret += "<code class='type'>type</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  if (n->count_children() && (c = get_first_element(n)) && (c->get_any_name() != "mixed")) { ret += "(" + parse_type(c) + ")"; } break; case "multiset":
f069a52016-04-19Pontus Östlund  ret += "<code class='datatype'>multiset</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  c = n->get_first_element("indextype"); if(c) ret += "(" + parse_type( get_first_element(c) ) + ")"; break; case "array":
f069a52016-04-19Pontus Östlund  ret += "<code class='datatype'>array</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  c = n->get_first_element("valuetype"); if(c) ret += "(" + parse_type( get_first_element(c) ) + ")"; break; case "mapping":
f069a52016-04-19Pontus Östlund  ret += "<code class='datatype'>mapping</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  c = n->get_first_element("indextype"); d = n->get_first_element("valuetype"); if(c && d) ret += "(" + parse_type( get_first_element(c) ) + ":" + parse_type( get_first_element(d) ) + ")"; #ifdef DEBUG if( !c != !d ) error( "Indextype/valuetype defined while the other is not in mapping.\n" ); #endif break; case "function":
f069a52016-04-19Pontus Östlund  ret += "<code class='datatype'>function</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  array(Node) args = n->get_elements("argtype"); d = n->get_first_element("returntype"); // Doing different than the XSL here. Must both // argtype and returntype be defined? if(args || d) { ret += "("; if(args) ret += map(args->get_children() * ({}), parse_type)*", "; ret += ":"; if(d) ret += parse_type( get_first_element(d) );
f069a52016-04-19Pontus Östlund  else ret += "<code class='datatype void'>void</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  ret += ")"; } break; case "varargs": #ifdef DEBUG if(!n->count_children()) error( "varargs node must have child node.\n" ); #endif ret += parse_type(get_first_element(n)) + " ... "; break; case "or": ret += map(filter(n->get_children(), lambda(Node n){ return n->get_node_type()==XML_ELEMENT; }), parse_type)*"|"; break;
6024172013-12-16Per Hedbor  case "void": case "program": case "mixed": case "float":
3756b82011-11-16Henrik Grubbström (Grubba)  case "zero":
f069a52016-04-19Pontus Östlund  ret += "<code class='datatype'>" + n->get_any_name() + "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  break;
6024172013-12-16Per Hedbor  case "string":
3756b82011-11-16Henrik Grubbström (Grubba)  case "int":
f069a52016-04-19Pontus Östlund  ret += ("<code class='datatype'>" +
6024172013-12-16Per Hedbor  range_type( n->get_any_name(), n->get_first_element("min"), n->get_first_element("max")) +
f069a52016-04-19Pontus Östlund  "</code>");
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "attribute": string attr = n->get_first_element("attribute")->value_of_node(); string subtype = parse_type(n->get_first_element("subtype")->get_first_element()); if (n->get_first_element("prefix")) { if (attr == "\"deprecated\"") {
f069a52016-04-19Pontus Östlund  ret += "<code class='deprecated'>__deprecated__</code> " +
e0da342015-10-12Pontus Östlund  subtype;
3756b82011-11-16Henrik Grubbström (Grubba)  } else { ret += sprintf("__attribute__(%s) %s", attr, subtype); } } else if (attr == "\"deprecated\"") {
f069a52016-04-19Pontus Östlund  ret += "<code class='deprecated'>__deprecated__</code>(" +
e0da342015-10-12Pontus Östlund  subtype + ")";
3756b82011-11-16Henrik Grubbström (Grubba)  } else { ret += sprintf("__attribute__(%s, %s)", attr, subtype); } break; // Modifiers: case "extern": // Not in XSLT
f069a52016-04-19Pontus Östlund  ret += "<code class='modifier'>extern</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "final": // Not in XSLT case "nomask": // Not in XSLT
f069a52016-04-19Pontus Östlund  ret += "<code class='modifier'>final</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "inline": // Not in XSLT case "local": // Not in XSLT
f069a52016-04-19Pontus Östlund  ret += "<code class='modifier'>local</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "optional": // Not in XSLT
f069a52016-04-19Pontus Östlund  ret += "<code class='modifier'>optional</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "private": // Not in XSLT
f069a52016-04-19Pontus Östlund  ret += "<code class='modifier'>private</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "protected": // Not in XSLT case "static": // Not in XSLT
f069a52016-04-19Pontus Östlund  ret += "<code class='modifier'>protected</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "public": // Not in XSLT // Ignored. break; case "variant": // Not in XSLT
f069a52016-04-19Pontus Östlund  ret += "<code class='modifier'>variant</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  break; default: error( "Illegal element " + n->get_any_name() + " in mode type.\n" ); break; } return ret; } void resolve_class_paths(Node n, string|void path, Node|void parent) { if (!path) path = ""; mapping attrs = n->get_attributes() || ([]); string name = attrs->name; switch(n->get_any_name()) { case "arguments": case "returntype": case "type": case "doc": case "source-position": case "modifiers": case "classname": // We're not interrested in the stuff under the above nodes. return; default: if (verbosity >= Tools.AutoDoc.FLAG_NORMAL) { werror("Unhandled node: %O path:%O name: %O, parent: %O\n", n->get_any_name(), path, name, parent&&parent->get_any_name()); } // FALL_THROUGH case "": case "docgroup": break;
e894cb2014-08-25Per Hedbor 
3756b82011-11-16Henrik Grubbström (Grubba)  case "manual": case "dir": case "file": case "chapter": case "section": case "subsection": foreach(filter(n->get_children(), lambda(Node n) { return (<"manual", "dir", "file", "chapter", "section", "subsection", "autodoc">) [n->get_any_name()]; }), Node child) { resolve_class_paths(child, "", n); } return; case "autodoc": path = ""; break; case "namespace": if ((<"", "lfun">)[name]) { // Censor namespaces other than :: and lfun:: path = name+"::"; } else { path = ""; } break; case "class": case "module": attrs->class_path = path; path += name + "."; break; case "enum": // Enum names don't show up in the path. attrs->class_path = path; break; case "method": // Special case for create(). if (name == "create") { // Get rid of the extra dot. attrs->class_path = path[..sizeof(path)-2]; } else { // Hide the class path for methods. attrs->class_path = ""; } return; case "constant": case "inherit": case "import": case "typedef": case "variable":
2110692012-02-05Henrik Grubbström (Grubba)  case "directive":
3756b82011-11-16Henrik Grubbström (Grubba)  // These don't have children. attrs->class_path = path; return; } foreach(n->get_children(), Node child) { resolve_class_paths(child, path, n); } } #if 0 // DEAD code (for reference only). string render_class_path(Node n,int|void class_only) { array a = reverse(n->get_ancestors(0)); array b = a->get_any_name(); int root; foreach( ({ "manual", "dir", "file", "chapter", "section", "subsection" }), string node) root = max(root, search(b, node)); a = a[root+1..]; if(sizeof(a) && a[0]->get_any_name() == "autodoc") a = a[1..]; if (!sizeof(a)) return ""; string ret = ""; if ((sizeof(a) > 1) && a[-2]->get_any_name() == "enum") { // Enum names don't show up in the path. a = a[..sizeof(a)-3] + a[sizeof(a)-1..]; } if (a[0]->get_any_name() == "namespace") { a = a->get_attributes()->name; a[0] += "::"; if ((<"::","lfun::">)[a[0]]) { // Censor namespaces other than :: and lfun:: ret = a[0]; } a = a[1..]; } else { a = a->get_attributes()->name; } ret += a * "."; if (!sizeof(ret) || ret[-1] == ':') return ret; if((<"class", "module", "enum">)[n->get_any_name()]) return ret + "."; // Note we need two calls to get_parent() to skip over the docgroup. Node parent = n->get_parent()->get_parent(); // Hide the enum part. if (parent->get_any_name()=="enum") parent = parent->get_parent(); if(parent->get_any_name()=="class") if( !class_only ) return ""; //ret + "()->"; else return ret; if(parent->get_any_name()=="module") return ret + "."; if (verbosity >= Tools.AutoDoc.FLAG_NORMAL) { werror("Failure, raw path: %{%O, %}\n", reverse(n->get_ancestors(0))->get_any_name()); } return " (could not resolve) "; #ifdef DEBUG error( "Parent module is " + n->get_parent()->get_any_name() + ".\n" ); #else return ""; #endif } #endif /* 0 */
abe61e2014-08-20Per Hedbor string class_name = "";
058f0d2016-01-20Pontus Östlund #define HTML_ENC(S) (Parser.encode_html_entities(S))
3756b82011-11-16Henrik Grubbström (Grubba)  string parse_not_doc(Node n) { string ret = "";
e680902015-03-22Henrik Grubbström (Grubba)  int method, argument, variable, num_const, typedf, cppdir;
3756b82011-11-16Henrik Grubbström (Grubba) 
60f2ae2012-02-05Henrik Grubbström (Grubba)  if (!n) return "";
3756b82011-11-16Henrik Grubbström (Grubba)  foreach(n->get_children(), Node c) { if(c->get_node_type()!=XML_ELEMENT) continue; Node cc; switch(c->get_any_name()) { case "doc": continue; case "source-position": position->update(c); continue; case "method":
e0da342015-10-12Pontus Östlund  if(method++) ret += "<br>\n";
60f2ae2012-02-05Henrik Grubbström (Grubba) #if 0
3756b82011-11-16Henrik Grubbström (Grubba)  if(!c->get_first_element("returntype"))
60f2ae2012-02-05Henrik Grubbström (Grubba)  error( "No returntype element in method element.\n" );
3756b82011-11-16Henrik Grubbström (Grubba) #endif
e894cb2014-08-25Per Hedbor  void emit_default_func() {
f069a52016-04-19Pontus Östlund  ret += "<code>";
e894cb2014-08-25Per Hedbor  cc = c->get_first_element("modifiers"); if(cc) ret += map(cc->get_children(), parse_type)*" " + " "; ret += parse_type(get_first_element(c->get_first_element("returntype"))); ret += " "; ret += c->get_attributes()->class_path;
058f0d2016-01-20Pontus Östlund  ret += "<b><span class='method'>" + HTML_ENC(c->get_attributes()->name) + "</span>(</b>";
e894cb2014-08-25Per Hedbor  ret += parse_not_doc( c->get_first_element("arguments") ); ret += "<b>)</b>";
f069a52016-04-19Pontus Östlund  ret += "</code>";
e894cb2014-08-25Per Hedbor  }; if( class_name == "" )
3756b82011-11-16Henrik Grubbström (Grubba)  {
e894cb2014-08-25Per Hedbor  emit_default_func(); } else switch( string method = c->get_attributes()->name ) { case "_get_iterator":
f069a52016-04-19Pontus Östlund  ret += "<code><span class='class'>"+class_name+"</span> "
e0da342015-10-12Pontus Östlund  "<span class='method'>a</span>;<br>\n";
e894cb2014-08-25Per Hedbor  /* NOTE: We could get index and value types from the iterator type here. Doing so might be somewhat hard, however. */
f069a52016-04-19Pontus Östlund  ret += "foreach( a; index; value ) or<br></code>";
e894cb2014-08-25Per Hedbor  emit_default_func(); break; case "pow":
f069a52016-04-19Pontus Östlund  ret += "<code>"+parse_type(get_first_element(c->get_first_element("returntype"))); ret += " res = "+method+"([<span class='class'>"+class_name+"</span>]a, b) or <br></code>";
e894cb2014-08-25Per Hedbor  emit_default_func(); break; case "sqrt":
f069a52016-04-19Pontus Östlund  ret += "<code>"+parse_type(get_first_element(c->get_first_element("returntype"))); ret += " res = "+method+"([<span class='class'>"+class_name+"</span>]a) or <br></code>";
e894cb2014-08-25Per Hedbor  emit_default_func(); break; /* case "_is_type": overloads all the TYPEp() functions and cast. ret += "<tt>bool stringp(["+class_name+"])a</font>) or <br></tt>"; emit_default_func(); break; */
3756b82011-11-16Henrik Grubbström (Grubba)  case "create":
f069a52016-04-19Pontus Östlund  ret += "<code><span class='object'>" +class_name; // Check for more children
e0da342015-10-12Pontus Östlund  ret += "</span> <span class='class'>"; ret += class_name+"</span><b>(</b>";
3756b82011-11-16Henrik Grubbström (Grubba)  ret += parse_not_doc( c->get_first_element("arguments") );
f069a52016-04-19Pontus Östlund  ret += "<b>)</b></code>";
3756b82011-11-16Henrik Grubbström (Grubba)  break;
abe61e2014-08-20Per Hedbor 
e894cb2014-08-25Per Hedbor  case "__hash": method = "_hash_value"; case "_random": case "_sqrt": case "_sizeof": case "_indices": case "_values": /* simple overload type lfuns. */
f069a52016-04-19Pontus Östlund  ret += "<code>";
e894cb2014-08-25Per Hedbor  ret += parse_type(get_first_element(c->get_first_element("returntype"))); ret += " ";
e0da342015-10-12Pontus Östlund  ret += "<b><span class='method'>"+method[1..]+"</span>(</b> "; ret += "<span class='class'>"+class_name+"</span> <span class='argument'>arg</span>";
f069a52016-04-19Pontus Östlund  ret += " <b>)</b></code>";
e894cb2014-08-25Per Hedbor  break; case "_m_delete": case "_equal": case "_search":
f069a52016-04-19Pontus Östlund  ret += "<code>";
e894cb2014-08-25Per Hedbor  ret += parse_type(get_first_element(c->get_first_element("returntype")));
e0da342015-10-12Pontus Östlund  ret += " <b><span class='method'>"+method[1..]; ret += "</span>(</b><span class='class'>"+class_name+"</span> " "<span class='argument'>from</span>, ";
e894cb2014-08-25Per Hedbor  ret += parse_not_doc( c->get_first_element("arguments") );
f069a52016-04-19Pontus Östlund  ret += "<b>)</b></code>";
e894cb2014-08-25Per Hedbor  break; case "_sprintf":
e0da342015-10-12Pontus Östlund  //ret += "<tt>";
f069a52016-04-19Pontus Östlund  ret += "<code><span class='datatype'>string</span> ";
e0da342015-10-12Pontus Östlund  ret += ("<b><span class='method'>sprintf</span>(" "</b><span class='datatype'>string</span> " "<span class='constant'>format</span>, ... <span class='class'>" +class_name+"</span> <span class='constant'>"
f069a52016-04-19Pontus Östlund  "arg</span> ... <b>)</b></code>");
e894cb2014-08-25Per Hedbor  break; case "_decode":
f069a52016-04-19Pontus Östlund  ret += "<code>";
e0da342015-10-12Pontus Östlund  ret += "<span class='class'>"+class_name+"</span> "; ret += ("<b><span class='method'>decode_value</span>(" "</b><span class='datatype'>string(8bit)</span> "
f069a52016-04-19Pontus Östlund  "<span class='argument'>data</span>)</b></code>");
e894cb2014-08-25Per Hedbor  break; case "_encode":
f069a52016-04-19Pontus Östlund  ret += "<code>";
e0da342015-10-12Pontus Östlund  ret += "<span class='datatype'>string(8bit)</span> "; ret += ("<b><span class='method'>encode_value</span>(" "</b><span class='class'>"+class_name+"</span> "
f069a52016-04-19Pontus Östlund  "<span class='argument'>data</span>)</b></code>");
e894cb2014-08-25Per Hedbor  break; case "cast": {
f069a52016-04-19Pontus Östlund  ret += "<code>";
e894cb2014-08-25Per Hedbor  string base =
058f0d2016-01-20Pontus Östlund  "<b>(</b><span class='datatype'>_@_TYPE_@_</span>" "<b>)</b><span class='class'>"+class_name+"</span>()";
e894cb2014-08-25Per Hedbor  multiset seen = (<>); void add_typed( string type ) { if( type == "mixed" ) { add_typed("int"); ret +="<br>"; add_typed("float"); ret +="<br>"; add_typed("string"); ret +="<br>"; add_typed("array"); ret +="<br>"; add_typed("mapping"); ret +="<br>"; add_typed("multiset"); return; } if( !seen[type]++ ) ret += replace(base,"_@_TYPE_@_", type); }; void output_from_type(Node x, bool toplevel ) {
c419002014-10-18Henrik Grubbström (Grubba)  if( !x || x->get_node_type() != XML_ELEMENT ) return;
e894cb2014-08-25Per Hedbor  switch( x->get_any_name() ) { case "object": /*add_typed("object"); */break; /* this is a no-op.. */ case "int": case "float": case "array": case "mapping": case "string": case "function": add_typed(parse_type(x)); if( !toplevel ) ret += "<br>"; break; case "mixed": add_typed("mixed"); if( !toplevel ) ret += "<br>"; break; case "or": if( toplevel ) map( x->get_children(), output_from_type, false ); } }; output_from_type(get_first_element(c->get_first_element("returntype")), true); if( !sizeof(seen) ) add_typed("mixed");
058f0d2016-01-20Pontus Östlund 
f069a52016-04-19Pontus Östlund  ret += "</code>";
e894cb2014-08-25Per Hedbor  }; break; default: if( string pat = Tools.AutoDoc.PikeObjects.lfuns[method] ) { Node a = c->get_first_element("arguments") ; array(Node) args = a->get_elements("argument");
f069a52016-04-19Pontus Östlund  mapping repl = (["OBJ":"<code class='class'>"+ class_name+"()</code>"]);
e894cb2014-08-25Per Hedbor  /* there are a few cases: obj OP arg - we do not want types RET func(op,ARG) - we do want types. This code should only be triggered for the first case. Hence, no types wanted. */ if( sizeof(args) > 0 ) {
f069a52016-04-19Pontus Östlund  repl->x = "<code class='class'>"+ args[0]->get_attributes()->name+"</code>";
e894cb2014-08-25Per Hedbor  } if( sizeof(args) > 1 ) {
f069a52016-04-19Pontus Östlund  repl->y = "<code class='class'>"+ args[1]->get_attributes()->name+"</code>";
e894cb2014-08-25Per Hedbor  }
f069a52016-04-19Pontus Östlund  ret += "<code>";
e894cb2014-08-25Per Hedbor  if( method != "`+=" && method != "`[]=" && method != "`->=") { ret += parse_type(get_first_element(c->get_first_element("returntype"))); ret += " res = "; }
058f0d2016-01-20Pontus Östlund  ret += replace(HTML_ENC(pat), repl );
f069a52016-04-19Pontus Östlund  ret += "</code>";
e894cb2014-08-25Per Hedbor  break; } emit_default_func( ); break;
3756b82011-11-16Henrik Grubbström (Grubba)  } break; case "argument": if(argument++) ret += ", "; cc = c->get_first_element("value");
f069a52016-04-19Pontus Östlund  string arg_name = cc && cc->value_of_node(); if (arg_name) { ret += "<code class='argument'>" + arg_name + "</code>"; }
3756b82011-11-16Henrik Grubbström (Grubba)  else if( !c->count_children() ); else if( get_first_element(c)->get_any_name()=="type") { ret += parse_type(get_first_element(get_first_element(c)));
f069a52016-04-19Pontus Östlund  arg_name = c->get_attributes()->name; if(arg_name) { ret += " <code class='argument'>" + arg_name + "</code>"; }
3756b82011-11-16Henrik Grubbström (Grubba)  } else error( "Malformed argument element.\n" + c->html_of_node() + "\n" ); break; case "variable":
e0da342015-10-12Pontus Östlund  if(variable++) ret += "<br>\n";
f069a52016-04-19Pontus Östlund  ret += "<code>";
3756b82011-11-16Henrik Grubbström (Grubba)  cc = c->get_first_element("modifiers"); if(cc) ret += map(cc->get_children(), parse_type)*" " + " ";
1249d82011-11-18Henrik Grubbström (Grubba)  if (c->get_first_element("type")) { ret += parse_type(get_first_element(c->get_first_element("type")), "variable") + " " +
e0da342015-10-12Pontus Östlund  c->get_attributes()->class_path + "<b><span class='variable'>" +
f069a52016-04-19Pontus Östlund  c->get_attributes()->name + "</span></b></code>";
1249d82011-11-18Henrik Grubbström (Grubba)  } else error("Malformed variable element.\n" + c->html_of_node() + "\n");
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "constant":
058f0d2016-01-20Pontus Östlund  if(num_const++) ret += "<br>\n";
f069a52016-04-19Pontus Östlund  ret += "<code><code class='datatype'>";
3756b82011-11-16Henrik Grubbström (Grubba)  cc = c->get_first_element("modifiers"); if(cc) ret += map(cc->get_children(), parse_type)*" " + " ";
f069a52016-04-19Pontus Östlund  ret += "constant</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  if (Node type = c->get_first_element ("type")) ret += parse_type (get_first_element (type), "constant") + " "; ret += c->get_attributes()->class_path;
f069a52016-04-19Pontus Östlund  ret += "<code class='constant'>" + c->get_attributes()->name + "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  cc = c->get_first_element("typevalue");
058f0d2016-01-20Pontus Östlund  if(cc) {
f069a52016-04-19Pontus Östlund  ret += " = <code class='value'>" + parse_type(get_first_element(cc)) + "</code>";
058f0d2016-01-20Pontus Östlund  }
f069a52016-04-19Pontus Östlund  ret += "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "typedef":
058f0d2016-01-20Pontus Östlund  if(typedf++) ret += "<br>\n";
f069a52016-04-19Pontus Östlund  ret += "<code><code class='datatype'>";
3756b82011-11-16Henrik Grubbström (Grubba)  cc = c->get_first_element("modifiers"); if(cc) ret += map(cc->get_children(), parse_type)*" " + " ";
f069a52016-04-19Pontus Östlund  ret += "typedef</code> ";
3756b82011-11-16Henrik Grubbström (Grubba)  ret += parse_type(get_first_element(c->get_first_element("type")), "typedef") + " " +
058f0d2016-01-20Pontus Östlund  c->get_attributes()->class_path +
f069a52016-04-19Pontus Östlund  "<code class='typedef'>" + c->get_attributes()->name + "</code></code>";
3756b82011-11-16Henrik Grubbström (Grubba)  break; case "inherit":
f069a52016-04-19Pontus Östlund  ret += "<code><span class='datatype'>";
3756b82011-11-16Henrik Grubbström (Grubba)  cc = c->get_first_element("modifiers"); if(cc) ret += map(cc->get_children(), parse_type)*" " + " "; ret += "inherit "; Node n = c->get_first_element("classname"); if (resolve_reference) {
e0da342015-10-12Pontus Östlund  ret += "</span>" +
3756b82011-11-16Henrik Grubbström (Grubba)  resolve_reference(n->value_of_node(), n->get_attributes()); } else {
e0da342015-10-12Pontus Östlund  ret += Parser.encode_html_entities(n->value_of_node()) + "</span>";
3756b82011-11-16Henrik Grubbström (Grubba)  } if (c->get_attributes()->name) {
058f0d2016-01-20Pontus Östlund  ret += " : " + "<span class='inherit'>" +
3756b82011-11-16Henrik Grubbström (Grubba)  Parser.encode_html_entities(c->get_attributes()->name) +
058f0d2016-01-20Pontus Östlund  "</span>";
3756b82011-11-16Henrik Grubbström (Grubba)  }
f069a52016-04-19Pontus Östlund  ret += "</code>";
3756b82011-11-16Henrik Grubbström (Grubba)  break; // We don't need import information. case "import": break;
2110692012-02-05Henrik Grubbström (Grubba)  case "directive":
058f0d2016-01-20Pontus Östlund  if(cppdir++) ret += "<br>\n";
f069a52016-04-19Pontus Östlund  ret += "<code class='directive'>" + quote(c->get_attributes()->name) + "</code>";
2110692012-02-05Henrik Grubbström (Grubba)  break;
3756b82011-11-16Henrik Grubbström (Grubba)  default: error( "Illegal element " + c->get_any_name() + " in !doc.\n" ); break; } } return ret; } int foo; string parse_docgroup(Node n) { mapping m = n->get_attributes(); string ret = lay->docgroup;
2001482012-05-05Henrik Grubbström (Grubba)  if (m["homogen-type"] == "import") { // We don't need import information. return ""; }
3756b82011-11-16Henrik Grubbström (Grubba)  if(lay->typehead) { ret += lay->typehead; if(m["homogen-type"]) {
e0da342015-10-12Pontus Östlund  string type = "<span class='homogen--type'>" +
3756b82011-11-16Henrik Grubbström (Grubba)  quote(String.capitalize(m["homogen-type"])) +
e0da342015-10-12Pontus Östlund  "</span>\n";
3756b82011-11-16Henrik Grubbström (Grubba)  if(m["homogen-name"]) {
e0da342015-10-12Pontus Östlund  ret += type + "<span class='homogen--name'><b>" +
3756b82011-11-16Henrik Grubbström (Grubba)  quote((m->belongs?m->belongs+" ":"") + m["homogen-name"]) +
e0da342015-10-12Pontus Östlund  "</b></span>\n";
3756b82011-11-16Henrik Grubbström (Grubba)  } else { array(string) names = Array.uniq(map(n->get_elements(m["homogen-type"]), lambda(Node child) { return child->get_attributes()->name || child->value_of_node(); })); foreach(names, string name)
69d2e72012-03-24Henrik Grubbström (Grubba)  ret += type +
e0da342015-10-12Pontus Östlund  "<span class='homogen--name'><b>" + quote(name) + "</b></span><br>\n";
3756b82011-11-16Henrik Grubbström (Grubba)  } } else ret += "Syntax"; ret += lay->_typehead; } ret += lay->ndochead; ret += parse_not_doc(n); ret += lay->_ndochead; foreach(n->get_elements("doc"), Node c) ret += parse_doc(c); return ret + lay->_docgroup; } string parse_children(Node n, string tag, function cb, mixed ... args) { string ret = ""; foreach(n->get_elements(tag), Node c) ret += cb(c, @args); return ret; }
058f0d2016-01-20Pontus Östlund // This can be overridden by passing --template=template.html to main string html_template = "<!doctype html><html><head><title>$title$</title>\n" "<meta charset='utf-8'></head>\n" "<body>$contents$</body></html>";
3756b82011-11-16Henrik Grubbström (Grubba) string manual_title = "Pike Reference Manual"; string frame_html(string res, void|string title) { title = title || manual_title;
058f0d2016-01-20Pontus Östlund  return replace(html_template, ([ "$title$" : quote(title), "$contents$" : res ]));
3756b82011-11-16Henrik Grubbström (Grubba) } string layout_toploop(Node n, Git.Export|void exporter) { string res = ""; foreach(n->get_elements(), Node c) switch(c->get_any_name()) { case "dir": if (exporter) { layout_toploop(c, exporter); break; } string cwd; if(dest_path) { cwd=getcwd(); cd(dest_path);
3524712015-05-26Martin Nilsson  }
3756b82011-11-16Henrik Grubbström (Grubba)  Stdio.mkdirhier(c->get_attributes()->name); layout_toploop(c); if(cwd) cd(cwd); break; case "file": if (verbosity >= Tools.AutoDoc.FLAG_VERBOSE) { werror("\t%s\n", c->get_attributes()->name); } if (exporter) {
a55a212011-12-18Henrik Grubbström (Grubba)  string html = frame_html(layout_toploop(c));
3756b82011-11-16Henrik Grubbström (Grubba)  exporter->filemodify(Git.MODE_FILE, c->get_attributes()->name);
1c44522015-09-20Henrik Grubbström (Grubba)  exporter->data(string_to_utf8(html));
3756b82011-11-16Henrik Grubbström (Grubba)  break; } if(dest_path) { cwd=getcwd(); cd(dest_path);
3524712015-05-26Martin Nilsson  }
3756b82011-11-16Henrik Grubbström (Grubba)  Stdio.write_file( c->get_attributes()->name,
1c44522015-09-20Henrik Grubbström (Grubba)  string_to_utf8(frame_html(layout_toploop(c))) );
3756b82011-11-16Henrik Grubbström (Grubba)  if(cwd) cd(cwd); break;
c75acb2012-02-11Henrik Grubbström (Grubba)  case "appendix":
c0729f2012-02-11Henrik Grubbström (Grubba)  if (!(flags & Tools.AutoDoc.FLAG_COMPAT)) { error("Appendices are only supported in compat mode.\n"); }
c75acb2012-02-11Henrik Grubbström (Grubba)  res += parse_appendix(c); break;
3756b82011-11-16Henrik Grubbström (Grubba)  case "chapter": res += parse_chapter(c); break; default: error("Unknown element %O.\n", c->get_any_name()); } return res; } int low_main(string title, string input_file, string|void output_file, Git.Export|void exporter) { int t = time(); string file = Stdio.read_file(input_file); if(!file) error( "Could not read %s.\n", input_file ); if(!sizeof(file)) error( "%s is empty.\n", input_file ); // We are only interested in what's in the // module container. if (verbosity >= Tools.AutoDoc.FLAG_VERBOSE) { werror("Parsing %O...\n", input_file); } Node n = Parser.XML.Tree.simple_parse_input(file); Node n2 = n->get_first_element("manual"); if(!n2) { n2 = n->get_first_element("autodoc"); if(!n2) { if (verbosity >= Tools.AutoDoc.FLAG_NORMAL) { werror("Not an autodoc XML file.\n"); } return 1; } Node chap = Node(XML_ELEMENT, "chapter", (["title":title||"Documentation"]), 0); chap->add_child( n2 ); string fn = output_file || "index.html"; Node file = Node(XML_ELEMENT, "file", (["name":fn]), 0); file->add_child( chap ); Node top = Node(XML_ELEMENT, "manual", ([]), 0); top->add_child( file ); n = top; } else n = n2; if (verbosity >= Tools.AutoDoc.FLAG_VERBOSE) { werror("Resolving class paths...\n"); } resolve_class_paths(n); mapping m = n->get_attributes(); if (verbosity >= Tools.AutoDoc.FLAG_VERBOSE) { werror("Layouting...\n"); }
662caf2012-03-02Henrik Grubbström (Grubba)  if (flags & Tools.AutoDoc.FLAG_NO_DYNAMIC) {
72f0c92012-03-02Henrik Grubbström (Grubba)  manual_title = m->title || "Pike Reference Manual"; } else { manual_title = m->title || (m->version?"Reference Manual for "+m->version:"Pike Reference Manual"); }
3756b82011-11-16Henrik Grubbström (Grubba)  layout_toploop(n, exporter); if (verbosity >= Tools.AutoDoc.FLAG_VERBOSE) { werror("Took %d seconds.\n\n", time()-t); } return 0; }
bf55a52016-06-04Martin Nilsson void help(void|string err) { string msg = #"pike -x autodoc_to_html [args] <input file> [<output file>] --img=<image path> --dest=<destination path> --title=<document title> --template=<template.html path> "; if( err ) exit(1, err+"\n"+msg); write(msg); exit(0); }
3756b82011-11-16Henrik Grubbström (Grubba) int main(int num, array args) {
058f0d2016-01-20Pontus Östlund  string title, template;
3756b82011-11-16Henrik Grubbström (Grubba)  foreach(Getopt.find_all_options(args, ({
058f0d2016-01-20Pontus Östlund  ({ "img", Getopt.HAS_ARG, "--img" }), ({ "dest", Getopt.HAS_ARG, "--dest" }), ({ "title", Getopt.HAS_ARG, "--title" }), ({ "template", Getopt.HAS_ARG, "--template" }), ({ "defns", Getopt.HAS_ARG, "--default-ns" }), ({ "verbose", Getopt.NO_ARG, "-v,--verbose"/"," }), ({ "quiet", Getopt.NO_ARG, "-q,--quiet"/"," }), ({ "help", Getopt.NO_ARG, "--help" }),
3756b82011-11-16Henrik Grubbström (Grubba)  })), array opt) switch(opt[0]) { case "img": image_path = opt[1]; break; case "dest": dest_path = opt[1]; break; case "title": title = opt[1]; break;
058f0d2016-01-20Pontus Östlund  case "template": template = opt[1]; break;
3756b82011-11-16Henrik Grubbström (Grubba)  case "defns": default_ns = opt[1]; break; case "verbose": if (verbosity < Tools.AutoDoc.FLAG_DEBUG) { verbosity += 1; flags = (flags & ~Tools.AutoDoc.FLAG_VERB_MASK) | verbosity; } break; case "quiet": flags &= ~Tools.AutoDoc.FLAG_VERB_MASK; verbosity = Tools.AutoDoc.FLAG_QUIET; break; case "help":
bf55a52016-06-04Martin Nilsson  help();
3756b82011-11-16Henrik Grubbström (Grubba)  break; } args = Getopt.get_args(args)[1..]; if(!sizeof(args))
bf55a52016-06-04Martin Nilsson  { help( "No input file given.\n" ); }
3756b82011-11-16Henrik Grubbström (Grubba) 
058f0d2016-01-20Pontus Östlund  if (template && Stdio.exist(template)) { string dir = dirname(template); html_template = Stdio.read_file(template); Parser.HTML p = Parser.HTML(); p->add_tag("link", lambda (Parser.HTML pp, mapping attr) { if (attr->href && attr["data-inline"]) { return "<style>" + (Stdio.read_file(combine_path(dir, attr->href))) + "</style>"; } }); html_template = p->feed(html_template)->finish()->read(); }
3756b82011-11-16Henrik Grubbström (Grubba)  return low_main(title, @args); }