835c6c2001-06-17Martin Nilsson // This file is part of Roxen WebServer.
f41b982009-05-07Martin Stjernholm // Copyright © 2000 - 2009, Roxen IS.
835c6c2001-06-17Martin Nilsson // // RXML Help by Martin Nilsson
cface32000-01-10Martin Nilsson //
3b194c2001-08-10Per Hedbor // inherited by configuration.pike
f5cadf2001-08-17Per Hedbor #define parse_rxml Roxen.parse_rxml
3b194c2001-08-10Per Hedbor 
d2b7e92008-09-16Martin Stjernholm #include <module.h>
2feec42000-01-24Martin Nilsson #ifdef RXMLHELP_DEBUG
91d3c32001-03-12Martin Nilsson # define RXMLHELP_WERR(X) report_debug("RXML help: %s\n", X);
2feec42000-01-24Martin Nilsson #else # define RXMLHELP_WERR(X) #endif
a104662000-01-25Martin Nilsson // --------------------- Layout help functions --------------------
e8ae642000-03-16Martin Nilsson #define TDBG "#d9dee7"
a104662000-01-25Martin Nilsson string mktable(array table) {
d2b7e92008-09-16Martin Stjernholm  string ret= "<table style='" "border: 1px solid black; " "border-collapse: collapse; " "background: " TDBG "; "
5506102008-09-29Martin Stjernholm  "width: 100%; " "margin: 2px 0'>"
d2b7e92008-09-16Martin Stjernholm  "<tbody style='vertical-align: top'>\n";
a104662000-01-25Martin Nilsson  foreach(table, array row)
d2b7e92008-09-16Martin Stjernholm  ret+="<tr>" "<td style='border: 1px solid'>"+ row * "</td><td style='border: 1px solid'>" + "</td></tr>\n";
a104662000-01-25Martin Nilsson 
d2b7e92008-09-16Martin Stjernholm  ret+="</tbody></table>";
a104662000-01-25Martin Nilsson  return ret; } string available_languages(object id) {
e40bf72000-01-28Martin Nilsson  string pl;
78be972001-04-23Martin Nilsson  if(id && id->misc->pref_languages && (pl=id->misc->pref_languages->get_language()))
b09a282000-03-21Martin Nilsson  if(!has_value(roxen->list_languages(),pl)) pl="en";
e40bf72000-01-28Martin Nilsson  else pl="en";
b09a282000-03-21Martin Nilsson  mapping languages=roxen->language_low(pl)->list_languages();
b0e8f92000-03-22Martin Nilsson  return mktable( map(sort(indices(languages) & roxen->list_languages()), lambda(string code) { return ({ code, languages[code] }); } ));
a104662000-01-25Martin Nilsson } // --------------------- Help layout functions --------------------
cface32000-01-10Martin Nilsson 
fc40392008-08-15Martin Stjernholm protected class TagdocParser (int level)
6cc5682002-08-13Martin Stjernholm { inherit Parser.HTML; mapping misc = ([]);
f735992006-12-12Martin Stjernholm  TagdocParser clone() { TagdocParser c = ::clone (level);
497f9c2009-01-09Martin Stjernholm  xml_tag_syntax (2);
f735992006-12-12Martin Stjernholm  c->misc = misc; return c; }
6cc5682002-08-13Martin Stjernholm }
f735992006-12-12Martin Stjernholm // Header tags for different levels.
fc40392008-08-15Martin Stjernholm protected array(array(array(string))) hdr_tags = ({
f735992006-12-12Martin Stjernholm  // Top level (0). ({({"<h2>", "</h2>"}), // Top header ({"<h3>", "</h3>"}), // Subheaders (Attributes/Defined in content/etc) ({"<h4>", "</h4>"})}), // <h1> inside doc. // Sublevel 1. ({({"<h3>", "</h3>"}), ({"<h4>", "</h4>"}), ({"<h5>", "</h5>"})}), // Sublevel 2. ({({"<h4>", "</h4>"}), ({"<h5>", "</h5>"}), ({"<h6>", "</h6>"})}), // Sublevel 3 (shouldn't occur). ({({"<h5>", "</h5>"}), ({"<h6>", "</h6>"}), ({"<h6>", "</h6>"})}), }); #define NEXT_HDR_LEVEL(LEVEL) min ((LEVEL) + 1, sizeof (hdr_tags) - 1)
fc40392008-08-15Martin Stjernholm protected array desc_cont(TagdocParser parser, mapping m, string c, string rt)
cface32000-01-10Martin Nilsson {
9044642001-09-21Johan Sundström  string type; if(m->tag) type = "tag"; if(m->cont) type = "cont"; if(m->cont && m->tag) type = "both"; if(m->plugin) type = "plugin"; if(m->ent) type = "entity"; if(m->scope) type = "scope"; if(m->pi) type = "pi"; if(m->type) type = m->type; switch(type) { case "tag": rt = sprintf("&lt;%s/&gt;", rt); break;
b1b7e02001-12-04Martin Stjernholm  case "cont": rt = sprintf("&lt;%s&gt;&lt;/%s&gt;", rt, rt); break; case "both": rt = sprintf("&lt;%s/&gt; or "
9044642001-09-21Johan Sundström  "&lt;%s&gt;&lt;/%s&gt;", rt, rt, rt); break;
f735992006-12-12Martin Stjernholm  case "plugin": rt = String.capitalize (replace(rt, "#", " plugin ")); break;
9044642001-09-21Johan Sundström  //case "entity": rt = rt; break; case "scope": rt = rt[..sizeof(rt)-2] + " ... ;"; case "pi": rt = "&lt;" + rt + " ... ?&gt;";
49ee2d2000-03-07Martin Nilsson  }
f735992006-12-12Martin Stjernholm  return ({sprintf("\n%s%s%s\n<p>%s</p>\n", hdr_tags[parser->level][0][0], parser->clone()->finish(rt)->read(), hdr_tags[parser->level][0][1], parser->clone()->finish(c)->read())});
cface32000-01-10Martin Nilsson }
fc40392008-08-15Martin Stjernholm protected array attr_cont(TagdocParser parser, mapping m, string c)
cface32000-01-10Martin Nilsson { string p=""; if(!m->name) m->name="(Not entered)";
ec8b312000-03-30Martin Nilsson  if(m->value) p=sprintf("<i>%s=%s</i>%s<br />", m->name, attr_vals(m->value), m->default?" ("+m->default+")":"" ); if(m->required) p+="<i>This attribute is required.</i><br />";
2430242003-05-20Anders Johansson  p = sprintf("<p><dl><dt><b>%s</b></dt><dd>%s%s</dd></dl></p>",m->name,p,c);
6cc5682002-08-13Martin Stjernholm  if (!parser->misc->got_attrs) { parser->misc->got_attrs = 1;
f735992006-12-12Martin Stjernholm  p = hdr_tags[parser->level][1][0] + "Attributes" + hdr_tags[parser->level][1][1] + p;
6cc5682002-08-13Martin Stjernholm  }
f735992006-12-12Martin Stjernholm  return ({parser->clone()->finish(p)->read()});
cface32000-01-10Martin Nilsson }
fc40392008-08-15Martin Stjernholm protected string attr_vals(string v)
cface32000-01-10Martin Nilsson {
b09a282000-03-21Martin Nilsson  if(has_value(v,"|")) return "{"+(v/"|")*", "+"}"; // FIXME Use real config url // if(v=="langcodes") return "<a href=\"/help/langcodes.pike\">language code</a>";
cface32000-01-10Martin Nilsson  return v; }
fc40392008-08-15Martin Stjernholm protected string noex_cont(TagdocParser parser, mapping m, string c) {
4a45f12001-03-13Martin Nilsson  return Parser.HTML()->add_container("ex","")-> add_quote_tag("!--","","--")->feed(c)->read();
b0e8f92000-03-22Martin Nilsson }
d2b7e92008-09-16Martin Stjernholm protected string ex_quote(string in) { sscanf (reverse (in), "%[ \t\n\r]", string trailing_ws); if (has_prefix (in, "\n")) in = in[1..<sizeof (trailing_ws)]; else in = in[..<sizeof (trailing_ws)];
c603312009-04-02Martin Stjernholm  // FIXME: Find out why we have the "&lt;" inconsistency and eliminate it. return "<div style='white-space: pre; font-family: monospace'>" + replace(in, ({"<", ">", "&", "&lt;"}), ({"&lt;", "&gt;", "&amp;", "&lt;"}) )+"</div>";
4acd362001-05-18Martin Nilsson }
fc40392008-08-15Martin Stjernholm protected string ex_cont(TagdocParser parser, mapping m, string c, string rt, void|object id)
9dcf432000-01-23Martin Nilsson {
fa78ad2001-08-23Martin Nilsson  c=Parser.HTML()->add_container("ent", lambda(Parser.HTML parser, mapping m, string c) {
c7da172001-01-29Per Hedbor  return "&amp;"+c+";";
bca6aa2008-09-28Martin Stjernholm  } )->feed(c)->read();
4acd362001-05-18Martin Nilsson  string quoted = ex_quote(c);
69f7112000-05-30Martin Nilsson  if(m->type=="box")
d2b7e92008-09-16Martin Stjernholm  return mktable( ({ ({ quoted }) }) );
69f7112000-05-30Martin Nilsson 
d2b7e92008-09-16Martin Stjernholm  if (m->type != "hr") c = "<colorscope bgcolor="+TDBG+">"+c+"</colorscope>"; string parsed;
9bfa2b2008-11-02Martin Stjernholm  if (!m["keep-var-scope"]) RXML_CONTEXT->add_scope ("var", ([]));
d2b7e92008-09-16Martin Stjernholm  if (m["any-result"]) { // Use if the example returns a non-xml result, e.g. an array. RXML.Parser p = RXML.t_any (id->conf->default_content_type->parser_prog)->
5506102008-09-29Martin Stjernholm  get_parser (RXML_CONTEXT, RXML_CONTEXT->tag_set);
d2b7e92008-09-16Martin Stjernholm  p->write_end (c); mixed res = p->eval(); parsed = String.capitalize (sprintf ("%t result: ", res)) + Roxen.html_encode_string (RXML.utils.format_short (res, 1024)); }
c603312009-04-02Martin Stjernholm  else { RXML.Parser p = id->conf->default_content_type-> get_parser (RXML_CONTEXT, RXML_CONTEXT->tag_set); p->write_end (c); parsed = p->eval(); }
d2b7e92008-09-16Martin Stjernholm 
9dcf432000-01-23Martin Nilsson  switch(m->type) { case "hr":
0d1bb22000-05-30Martin Nilsson  return quoted+"<hr />"+parsed;
4acd362001-05-18Martin Nilsson  case "svert":
d2b7e92008-09-16Martin Stjernholm  return mktable( ({ ({ quoted }), ({ ex_quote(parsed) }) }) );
4acd362001-05-18Martin Nilsson  case "shor":
d2b7e92008-09-16Martin Stjernholm  return mktable( ({ ({ quoted, ex_quote(parsed) }) }) );
9dcf432000-01-23Martin Nilsson  case "vert":
7580012001-09-03Martin Nilsson  default:
d2b7e92008-09-16Martin Stjernholm  return mktable( ({ ({ quoted }), ({ parsed }) }) );
9dcf432000-01-23Martin Nilsson  case "hor":
d2b7e92008-09-16Martin Stjernholm  return mktable( ({ ({ quoted, parsed }) }) );
9dcf432000-01-23Martin Nilsson  } }
fc40392008-08-15Martin Stjernholm protected string ex_box_cont(TagdocParser parser, mapping m, string c, string rt) {
d2b7e92008-09-16Martin Stjernholm  return mktable( ({ ({ ex_quote(c) }) }) );
7580012001-09-03Martin Nilsson }
fc40392008-08-15Martin Stjernholm protected string ex_html_cont(TagdocParser parser, mapping m, string c, string rt) {
d2b7e92008-09-16Martin Stjernholm  return mktable( ({ ({ c }) }) );
953f172001-09-10Martin Nilsson }
fc40392008-08-15Martin Stjernholm protected string ex_src_cont(TagdocParser parser, mapping m, string c, string rt, void|object id) {
7580012001-09-03Martin Nilsson  string quoted = ex_quote(c);
9044642001-09-21Johan Sundström  string parsed = parse_rxml("<colorscope bgcolor="+TDBG+">"+c+"</colorscope>", id);
d2b7e92008-09-16Martin Stjernholm  return mktable( ({ ({ quoted }), ({ ex_quote(parsed) }) }) );
7580012001-09-03Martin Nilsson }
fc40392008-08-15Martin Stjernholm protected string list_cont( TagdocParser parser, mapping m, string c )
9a669a2000-09-19Per Hedbor {
1399572001-11-26Anders Johansson  string type = m->type || "ul"; return "<"+type+">"+ Parser.HTML()-> add_containers( ([ "item":lambda(Parser.HTML p, mapping m, string c) { return ({ "<li>"+ (m->name ? "<b>"+m->name+"</b><br />" : "")+ c+"</li>" }); } ]) )->finish(c)->read()+ "</"+type+">";
9a669a2000-09-19Per Hedbor }
2b536f2011-04-20Martin Stjernholm protected string xtable_cont( mixed a, mapping m, string c )
9a669a2000-09-19Per Hedbor {
2b536f2011-04-20Martin Stjernholm  return Roxen.make_container ("table", m, c);
9a669a2000-09-19Per Hedbor }
2b536f2011-04-20Martin Stjernholm protected string module_cont( mixed a, mapping m, string c )
9a669a2000-09-19Per Hedbor {
2b536f2011-04-20Martin Stjernholm  return Roxen.make_container ("i", m, c);
9a669a2000-09-19Per Hedbor }
2b536f2011-04-20Martin Stjernholm protected string xtable_row_cont( mixed a, mapping m, string c )
9a669a2000-09-19Per Hedbor {
2b536f2011-04-20Martin Stjernholm  return Roxen.make_container ("tr", m, c);
9a669a2000-09-19Per Hedbor }
2b536f2011-04-20Martin Stjernholm protected string xtable_c_cont( mixed a, mapping m, string c )
9a669a2000-09-19Per Hedbor {
2b536f2011-04-20Martin Stjernholm  return Roxen.make_container ("td", m, c);
9a669a2000-09-19Per Hedbor }
2b536f2011-04-20Martin Stjernholm protected string xtable_h_cont( mixed a, mapping m, string c )
9044642001-09-21Johan Sundström {
2b536f2011-04-20Martin Stjernholm  return Roxen.make_container ("th", m, c);
9044642001-09-21Johan Sundström }
fc40392008-08-15Martin Stjernholm protected string help_tag( TagdocParser p, mapping m, string c )
9a669a2000-09-19Per Hedbor { if( m["for"] )
f735992006-12-12Martin Stjernholm  return find_tag_doc( m["for"], RXML.get_context()->id,0, NEXT_HDR_LEVEL (p->level));
9a669a2000-09-19Per Hedbor  return 0; // keep. }
fc40392008-08-15Martin Stjernholm protected string webserver_tag( mixed a, mixed b, string c )
93f7342002-11-26Anders Johansson { return roxen_product_name; }
9a669a2000-09-19Per Hedbor 
fc40392008-08-15Martin Stjernholm protected string format_doc(string|mapping doc, string name, object id, int level)
9a669a2000-09-19Per Hedbor {
9dcf432000-01-23Martin Nilsson  if(mappingp(doc)) {
5506102008-09-29Martin Stjernholm  if(id->misc->pref_languages) {
9a669a2000-09-19Per Hedbor  foreach(id->misc->pref_languages->get_languages()+({"en"}), string code) {
e3b9b92000-02-23Martin Nilsson  object lang=roxen->language_low(code);
e40bf72000-01-28Martin Nilsson  if(lang) { array lang_id=lang->id(); if(doc[lang_id[2]]) { doc=doc[lang_id[2]]; break; } if(doc[lang_id[1]]) { doc=doc[lang_id[1]]; break; } }
dfe0642000-01-26Martin Nilsson  }
9dcf432000-01-23Martin Nilsson  } else doc=doc->standard; }
e40bf72000-01-28Martin Nilsson 
c7da172001-01-29Per Hedbor  name=replace(name, ({ "<", ">", "&" }), ({ "&lt;", "&gt;", "&amp;" }) );
b2401f2000-08-31Martin Nilsson 
f735992006-12-12Martin Stjernholm  return TagdocParser (level)->
9a669a2000-09-19Per Hedbor  add_tag( "lang",lambda() { return available_languages(id); } )-> add_tag( "help", help_tag )->
93f7342002-11-26Anders Johansson  add_tag( "webserver", webserver_tag )->
9a669a2000-09-19Per Hedbor  add_containers( ([ "list":list_cont, "xtable":xtable_cont, "row":xtable_row_cont, "c":xtable_c_cont,
9044642001-09-21Johan Sundström  "h":xtable_h_cont,
9a669a2000-09-19Per Hedbor  "module":module_cont, "desc":desc_cont, "attr":attr_cont, "ex":ex_cont,
7580012001-09-03Martin Nilsson  "ex-box":ex_box_cont, "ex-src":ex_src_cont,
953f172001-09-10Martin Nilsson  "ex-html":ex_html_cont,
9a669a2000-09-19Per Hedbor  "noex":noex_cont,
6cc5682002-08-13Martin Stjernholm  "tag":lambda(TagdocParser p, mapping m, string c) {
fa78ad2001-08-23Martin Nilsson  return ({ "&lt;"+c+"&gt;" });
9a669a2000-09-19Per Hedbor  },
6cc5682002-08-13Martin Stjernholm  "ent":lambda(TagdocParser p, mapping m, string c) {
fa78ad2001-08-23Martin Nilsson  return ({ "&amp;" + c + ";" }); },
497f9c2009-01-09Martin Stjernholm  "xref":lambda(TagdocParser p, mapping m, string c) { string ref = m->href; if( ref ) { int is_tag = sscanf(ref, "%s.tag", ref); if (!is_tag && has_suffix (ref, "/")) { // There are references that look like <xref // href='../if/'/>. Assume it's the tag name // in the path. ref = (ref/"/")[-2]; is_tag = 1; } else ref = (ref/"/")[-1]; if (!c || !sizeof (c))
ce3d1d2009-01-09Martin Stjernholm  c = Roxen.html_encode_string (replace(ref, "_", " "));
497f9c2009-01-09Martin Stjernholm  if (is_tag && ref != "") c = "<a href='#tag_doc_" + Roxen.http_encode_url (ref) + "'>"
ce3d1d2009-01-09Martin Stjernholm  "&lt;" + c + "&gt;"
497f9c2009-01-09Martin Stjernholm  "</a>";
46ae1a2001-08-28Martin Nilsson  }
497f9c2009-01-09Martin Stjernholm  return c; },
6cc5682002-08-13Martin Stjernholm  "short":lambda(TagdocParser p, mapping m, string c) {
9a669a2000-09-19Per Hedbor  return m->hide?"":c; },
6cc5682002-08-13Martin Stjernholm  "note":lambda(TagdocParser p, mapping m, string c) {
84154a2001-10-05Martin Nilsson  return c; },
f735992006-12-12Martin Stjernholm  "h1": lambda (TagdocParser p, mapping m, string c) { return ({hdr_tags[p->level][2][0], p->clone()->finish(c)->read(), hdr_tags[p->level][2][1]}); }, ]) )->
4a45f12001-03-13Martin Nilsson  add_quote_tag("!--","","--")->
fa78ad2001-08-23Martin Nilsson  set_extra(name, id)->finish(doc)->read();
cface32000-01-10Martin Nilsson }
c284a02000-01-21Martin Nilsson 
cface32000-01-10Martin Nilsson // ------------------ Parse docs in mappings --------------
fc40392008-08-15Martin Stjernholm protected string parse_doc(string|mapping|array doc, string name, object id, int level) {
f735992006-12-12Martin Stjernholm  if(arrayp(doc) && (sizeof( doc ) == 2) ) { string top = format_doc(doc[0], name, id, level); string sub = parse_mapping(doc[1], id, NEXT_HDR_LEVEL (level)); if (sizeof (sub)) return top + hdr_tags[level][1][0] + "Defined in content" + hdr_tags[level][1][1] + "<dl><dd>" + sub + "</dd></dl>"; else return top; }
cac8242001-08-17Per Hedbor  if( arrayp( doc ) && sizeof(doc) )
f735992006-12-12Martin Stjernholm  return format_doc( doc[0], name, id, level); return format_doc(doc, name, id, level);
c284a02000-01-21Martin Nilsson }
fc40392008-08-15Martin Stjernholm protected string parse_mapping(mapping doc, object id, int level) {
cface32000-01-10Martin Nilsson  string ret=""; if(!mappingp(doc)) return "";
e3b9b92000-02-23Martin Nilsson  foreach(sort(indices(doc)), string tmp) {
f735992006-12-12Martin Stjernholm  ret+=parse_doc(doc[tmp], tmp, id, level);
cface32000-01-10Martin Nilsson  } return ret; }
6afce22001-01-16Martin Nilsson string parse_all_doc(RoxenModule o, void|RequestID id) { mapping doc = call_tagdocumentation(o); if(!doc) return 0; string ret = ""; foreach(sort(indices(doc)), string tagname)
f735992006-12-12Martin Stjernholm  ret += parse_doc(doc[tagname], tagname, id, 0);
6afce22001-01-16Martin Nilsson  return ret; }
c284a02000-01-21Martin Nilsson 
cface32000-01-10Martin Nilsson // --------------------- Find documentation --------------
c284a02000-01-21Martin Nilsson mapping call_tagdocumentation(RoxenModule o) {
c8a9d12000-03-30Martin Nilsson  if(!o->tagdocumentation) return 0;
78be972001-04-23Martin Nilsson  string name = o->register_module()[1];
d95f6f2000-01-26Martin Nilsson 
c8a9d12000-03-30Martin Nilsson  mapping doc; if(!zero_type(doc=cache_lookup("tagdoc", name)))
d95f6f2000-01-26Martin Nilsson  return doc;
2feec42000-01-24Martin Nilsson  doc=o->tagdocumentation(); RXMLHELP_WERR(sprintf("tagdocumentation() returned %t.",doc));
d95f6f2000-01-26Martin Nilsson  if(!doc || !mappingp(doc)) {
c8a9d12000-03-30Martin Nilsson  cache_set("tagdoc", name, 0);
d95f6f2000-01-26Martin Nilsson  return 0; }
39e0362000-08-30Martin Nilsson  RXMLHELP_WERR("("+String.implode_nicely(indices(doc))+")");
c8a9d12000-03-30Martin Nilsson  cache_set("tagdoc", name, doc);
c284a02000-01-21Martin Nilsson  return doc; }
dbbfdf2000-01-12Martin Nilsson 
fc40392008-08-15Martin Stjernholm protected int generation;
9dcf432000-01-23Martin Nilsson multiset undocumented_tags=(<>);
f735992006-12-12Martin Stjernholm 
cac8242001-08-17Per Hedbor string find_tag_doc(string name, RequestID id, int|void no_undoc,
f735992006-12-12Martin Stjernholm  int|void level, void|mapping(string:int) documented_tags)
f5cadf2001-08-17Per Hedbor {
124c202000-01-24Martin Nilsson  RXMLHELP_WERR("Help for tag "+name+" requested.");
f5cadf2001-08-17Per Hedbor 
f735992006-12-12Martin Stjernholm  if (documented_tags) { if (documented_tags[name]) { RXMLHELP_WERR("Already documented."); return ""; } documented_tags[name] = 1; }
f5cadf2001-08-17Per Hedbor  if( !id ) error("find_tag_doc called without ID-object\n");
cac8242001-08-17Per Hedbor 
f5cadf2001-08-17Per Hedbor  RXML.TagSet tag_set = id->conf->rxml_tag_set;
5506102008-09-29Martin Stjernholm  RXML.Context old_ctx, new_ctx; if (!level) { old_ctx = RXML.get_context(); new_ctx = tag_set->new_context (id); // Fake one frame depth so that the context doesn't get finished // after the first parse_rxml or similar. Have to do this since no // real rxml parser is used on the top level here. new_ctx->frame_depth = 1; RXML.set_context (new_ctx); }
c284a02000-01-21Martin Nilsson  int new_gen=tag_set->generation;
f5cadf2001-08-17Per Hedbor  if(generation!=new_gen) {
9dcf432000-01-23Martin Nilsson  undocumented_tags=(<>);
c284a02000-01-21Martin Nilsson  generation=new_gen; }
39e0362000-08-30Martin Nilsson  array tags;
7b95522001-08-23Martin Nilsson  if(name[0]=='?') { RXMLHELP_WERR("<"+name+"?> is a processing instruction."); object tmp=tag_set->get_tag(name[1..], 1);
39e0362000-08-30Martin Nilsson  if(tmp) tags=({ tmp }); else tags=({}); } else tags=tag_set->get_overridden_tags(name);
3b194c2001-08-10Per Hedbor  if(!sizeof(tags)) {
5506102008-09-29Martin Stjernholm  if( !level ) { new_ctx->frame_depth = 0; new_ctx->eval_finish();
cac8242001-08-17Per Hedbor  RXML.set_context( old_ctx );
5506102008-09-29Martin Stjernholm  }
7eff462016-06-08Henrik Grubbström (Grubba)  return no_undoc ? "" : "<h4>The tag (" + Roxen.html_encode_string(name) + ") is unknown</h4>";
3b194c2001-08-10Per Hedbor  }
c284a02000-01-21Martin Nilsson  foreach(tags, array|object|function tag) { if(objectp(tag)) { // FIXME: New style tag. Check for internal documentation.
5e71002000-12-19Anders Johansson  if(tag->is_compat_tag) { RXMLHELP_WERR(sprintf("CompatTag %O", tag)); tag=tag->fn; } else if(tag->is_generic_tag) { RXMLHELP_WERR(sprintf("GenericTag %O", tag));
e8ae642000-03-16Martin Nilsson  tag=tag->_do_return;
5e71002000-12-19Anders Johansson  } else { RXMLHELP_WERR(sprintf("NormalTag %O", tag));
e8ae642000-03-16Martin Nilsson  tag=object_program(tag);
5e71002000-12-19Anders Johansson  }
c284a02000-01-21Martin Nilsson  }
e8ae642000-03-16Martin Nilsson  else if(arrayp(tag)) {
c284a02000-01-21Martin Nilsson  if(tag[0]) tag=tag[0][1]; else if(tag[1]) tag=tag[1][1]; }
e8ae642000-03-16Martin Nilsson  else continue;
b0e8f92000-03-22Martin Nilsson  if(!functionp(tag)) continue;
c284a02000-01-21Martin Nilsson  tag=function_object(tag); if(!objectp(tag)) continue;
2feec42000-01-24Martin Nilsson  RXMLHELP_WERR(sprintf("Tag defined in module %O", tag));
c284a02000-01-21Martin Nilsson  mapping tagdoc=call_tagdocumentation(tag);
7b95522001-08-23Martin Nilsson  if(!tagdoc || !tagdoc[name]) { RXMLHELP_WERR(name+" not present in result."); continue; }
497f9c2009-01-09Martin Stjernholm  string res =
7cfd0e2009-01-29Martin Stjernholm  "<a name='tag_doc_" + Roxen.html_encode_string (name) + "'></a>\n" +
497f9c2009-01-09Martin Stjernholm  parse_doc(tagdoc[name], name, id, level);
f735992006-12-12Martin Stjernholm  mapping(string:RXML.Tag) plugins=tag_set->get_plugins(name); if(sizeof(plugins)) { foreach(sort(indices(plugins)), string plugin) res += find_tag_doc(name+"#"+plugin, id,no_undoc, NEXT_HDR_LEVEL (level), documented_tags); }
5506102008-09-29Martin Stjernholm  if( !level ) { new_ctx->frame_depth = 0; new_ctx->eval_finish();
cac8242001-08-17Per Hedbor  RXML.set_context( old_ctx );
5506102008-09-29Martin Stjernholm  }
3b194c2001-08-10Per Hedbor  return res;
c284a02000-01-21Martin Nilsson  }
9dcf432000-01-23Martin Nilsson  undocumented_tags[name]=1;
49ee2d2000-03-07Martin Nilsson  if(has_value(name,"#")) { sscanf(name,"%*s#%s", name); name="plugin "+name; }
5506102008-09-29Martin Stjernholm  if( !level ) { new_ctx->frame_depth = 0; new_ctx->eval_finish();
cac8242001-08-17Per Hedbor  RXML.set_context( old_ctx );
5506102008-09-29Martin Stjernholm  }
3b194c2001-08-10Per Hedbor  return (no_undoc ? "" :
7eff462016-06-08Henrik Grubbström (Grubba)  "<h4>No documentation available for \"" + Roxen.html_encode_string(name) + "\".</h4>\n");
cface32000-01-10Martin Nilsson }
2feec42000-01-24Martin Nilsson string find_module_doc( string cn, string mn, RequestID id )
cface32000-01-10Martin Nilsson {
124c202000-01-24Martin Nilsson  RXMLHELP_WERR("Help for module "+mn+" requested.");
cface32000-01-10Martin Nilsson  object c = roxen.find_configuration( cn );
2feec42000-01-24Martin Nilsson  if(!c) return "";
cface32000-01-10Martin Nilsson 
2feec42000-01-24Martin Nilsson  RoxenModule o = c->find_module( replace(mn,"!","#") );
124c202000-01-24Martin Nilsson  if(!o) return "";
cface32000-01-10Martin Nilsson 
f735992006-12-12Martin Stjernholm  return parse_mapping(o->tagdocumentation(), 0, 0);
cface32000-01-10Martin Nilsson }