28 #ifdef ENABLE_DOCSERVER
36 #include "libmicrohttpd/platform.h"
37 #include "libmicrohttpd/microhttpd.h"
44 #define DOCSERVER_NAME "ARTS built-in documentation server"
46 #define DS_ERROR_404 "Page not found"
49 static int ahc_echo(
void *cls,
struct MHD_Connection *connection,
50 const char *url,
const char *method,
51 const char *version,
const char *upload_data
_U_,
52 size_t *upload_data_size,
void **ptr);
66 if (indent.length() + curline.str().length() + token.str().length() > linelen)
68 get_os() << curline.str() << endl << indent;
71 curline << token.str();
85 string Docserver::new_page(
const string &url)
89 if (surl.find(get_baseurl()) == 0)
91 surl.erase(0, get_baseurl().size());
96 while (tokens.size() && tokens[tokens.size()-1] ==
"")
97 tokens.erase(tokens.end());
99 while (tokens.size() && tokens[0] ==
"")
100 tokens.erase(tokens.begin());
102 string content_type =
"text/html; charset=utf-8";
103 if (tokens.size() && tokens[tokens.size()-1] ==
"styles.css")
106 content_type =
"text/css; charset=utf-8";
108 else if (tokens.size() && tokens[tokens.size()-1] ==
"doccheck")
110 insert_broken_doc_links();
114 switch (tokens.size())
124 insert_error(DS_ERROR_404);
141 void Docserver::split_tokens(
const string &s)
147 while (getline(ss, item,
'/'))
149 tokens.push_back(item);
165 string Docserver::html_escape_char(
const char ch)
171 case '<': ret.append(
"<");
break;
172 case '>': ret.append(
">");
break;
173 default: ret.append(1, ch);
190 string Docserver::html_escape_string(
const string& s)
194 for (string::const_iterator it = s.begin(); it != s.end(); it++)
196 ret.append(html_escape_char(*it));
209 void Docserver::begin_content()
211 get_os() <<
"<div class=\"content\">" << endl;
221 void Docserver::end_content()
223 get_os() <<
"</div>" << endl;
235 void Docserver::begin_page (
string title)
240 title += DOCSERVER_NAME;
243 <<
"<!DOCTYPE html>" << endl
244 <<
"<html lang=\"en\">" << endl
246 <<
"<title>" << title <<
"</title>" << endl
247 <<
"<meta charset=\"utf-8\">" << endl
248 <<
"<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />" << endl
249 <<
"<link rel=\"stylesheet\" href=\"" << mbaseurl <<
"/styles.css\">" << endl
261 void Docserver::end_page ()
264 <<
" - <a href=\"" << mbaseurl <<
"/doccheck\">Check docs</a></div>\n" << endl;
266 get_os() <<
"</body>" << endl <<
"</html>";
280 String Docserver::insert_agenda_link (
const String &aname)
283 ret <<
"<a href=\"" << mbaseurl <<
"/agendas/" << aname <<
"\">" << aname <<
"</a>";
298 String Docserver::insert_group_link (
const String &gname)
301 ret <<
"<a href=\"" << mbaseurl <<
"/groups/" << gname <<
"\">" << gname <<
"</a>";
319 ret <<
"<a href=\"" << mbaseurl <<
"/methods/" << mname <<
"\">" << mname <<
"</a>";
343 ret <<
"<a href=\"" << mbaseurl <<
"/agendas/" << vname <<
"\">" << vname <<
"</a>";
345 ret <<
"<a href=\"" << mbaseurl <<
"/variables/" << vname <<
"\">" << vname <<
"</a>";
358 void Docserver::list_agendas ()
362 get_os() <<
"<h2>Agendas</h2>" << endl;
364 get_os() <<
"<div class=\"firstcol\">" << endl <<
"<ul>" << endl;
377 get_os() <<
"<li>" << insert_agenda_link(
Workspace::wsv_data[i].Name()) <<
"</li>" << endl;
380 if (hitcount2 == hitcount/2)
381 get_os() <<
"</ul>" << endl <<
"</div>" << endl
382 <<
"<div class=\"secondcol\">" << endl <<
"<ul>" << endl;
386 get_os() <<
"</ul>" << endl <<
"</div>" << endl;
396 void Docserver::list_groups ()
401 get_os() <<
"<h2>Workspace Groups</h2>" << endl;
403 get_os() <<
"<div class=\"firstcol\">" << endl <<
"<ul>" << endl;
406 get_os() <<
"<li>" << insert_group_link(
wsv_group_names[i]) <<
"</li>" << endl;
409 get_os() <<
"</ul>" << endl <<
"</div>" << endl
410 <<
"<div class=\"secondcol\">" << endl <<
"<ul>" << endl;
413 get_os() <<
"</ul>" << endl <<
"</div>" << endl;
423 void Docserver::list_methods ()
428 get_os() <<
"<h2>Workspace Methods</h2>" << endl;
430 get_os() <<
"<div class=\"firstcol\">" << endl <<
"<ul>" << endl;
433 get_os() <<
"<li>" << insert_wsm_link(
md_data_raw[i].Name()) <<
"</li>" << endl;
436 get_os() <<
"</ul>" << endl <<
"</div>" << endl
437 <<
"<div class=\"secondcol\">" << endl <<
"<ul>" << endl;
440 get_os() <<
"</ul>" << endl <<
"</div>" << endl;
450 void Docserver::list_variables ()
454 get_os() <<
"<h2>Workspace Variables</h2>" << endl;
456 get_os() <<
"<div class=\"firstcol\">" << endl <<
"<ul>" << endl;
472 if (hitcount2 == hitcount/2)
473 get_os() <<
"</ul>" << endl <<
"</div>" << endl
474 <<
"<div class=\"secondcol\">" << endl <<
"<ul>" << endl;
478 get_os() <<
"</ul>" << endl <<
"</div>" << endl;
497 bool inside_link =
false;
498 string::const_iterator it = desc.begin();
500 extern const map<String, Index>
MdRawMap;
501 extern const map<String, Index>
AgendaMap;
503 while (it != desc.end()) {
509 ret += html_escape_char(*it);
517 ret += insert_wsm_link(link);
519 ret += insert_agenda_link(link);
521 ret += insert_wsv_link(link);
523 ret += insert_group_link(link);
524 else if (mname !=
"")
526 extern const map<String, Index>
MdRawMap;
530 map<String, Index>::const_iterator mit =
MdRawMap.find(mname);
536 for (ArrayOfString::const_iterator sit = mdr.
GIn().begin();
537 !found && sit != mdr.
GIn().end();
542 ret +=
"*" + link +
"*";
547 for (ArrayOfString::const_iterator sit = mdr.
GOut().begin();
548 !found && sit != mdr.
GOut().end();
553 ret +=
"*" + link +
"*";
560 ret +=
"<span class=\"brokendoclink\">*" + link +
"*</span>";
563 ret +=
"<span class=\"brokendoclink\">*" + link +
"*</span>";
569 if (!isalnum(*it) && *it !=
'_')
572 ret +=
"*" + link + *it;
576 link += html_escape_char(*it);
583 if (inside_link) ret +=
"*" + link;
598 void Docserver::doc_method (
const string& mname)
602 extern const map<String, Index>
MdRawMap;
609 map<String, Index>::const_iterator it =
MdRawMap.find(mname);
616 get_os() <<
"<h3>Description</h3>" << endl;
618 get_os() <<
"<pre>" << endl;
619 get_os() << description_add_links(mdr.
Description(), mname);
620 get_os() << endl <<
"</pre>" << endl << endl;
622 bool is_first_author =
true;
627 get_os() <<
"<p><b>Authors: </b>";
628 is_first_author =
false;
638 while (indent.length() < mdr.
Name().length() + 2) indent +=
' ';
640 get_os() <<
"<h3>Synopsis</h3>" << endl;
644 const size_t linelen = 2048;
646 buf <<
"<p><table><tr><td>" << mdr.
Name() <<
"( </td><td>";
648 for (
Index i=0; i<mdr.
Out().nelem(); ++i )
650 if (first) first=
false;
else buf <<
", ";
658 if (first) first=
false;
else buf <<
", ";
659 if (mdr.
GOut()[i].length())
660 param << mdr.
GOut()[i];
662 param <<
"gout" << i;
670 if (first) first=
false;
else buf <<
", ";
678 if (first) first=
false;
else buf <<
", ";
679 if (mdr.
GIn()[i].length())
681 param << mdr.
GIn()[i];
690 if (buf.str().length()) get_os() << buf.str();
692 get_os() <<
" )</td></tr></table>" << endl;
694 get_os() <<
"<h3>Variables</h3>" << endl;
699 get_os() <<
"<table>" << endl;
700 for (
Index i=0; i<mdr.
Out().nelem(); ++i )
704 buf <<
"<td>OUT</td>";
708 buf <<
"<td class=\"right\">" << insert_wsv_link(vname) <<
"</td><td>(";
715 if (buf.str().length() + desc.length() > linelen)
718 buf << endl << indent << description_add_links(desc);
722 buf << description_add_links(desc);
725 get_os() << buf.str() <<
"</td></tr>" << endl;
730 for (
Index i=0; i<mdr.
GOut().nelem(); ++i )
734 buf <<
"<td>GOUT</td><td class=\"right\">" << mdr.
GOut()[i] <<
"</td><td>(";
738 bool firstarg =
true;
741 if (!firstarg) buf <<
", ";
else firstarg =
false;
752 lastlen = desc.length();
761 buf << endl << indent << description_add_links(desc);
763 else if (lastlen + desc.length() > linelen)
766 buf << endl << description_add_links(desc);
770 buf << description_add_links(desc);
773 get_os() << buf.str() <<
"</td></tr>" << endl;
776 for (
Index i=0; i<mdr.
In().nelem(); ++i )
780 buf <<
"<td>IN</td>";
783 buf <<
"<td class=\"right\">" << insert_wsv_link(vname);
790 if (buf.str().length() + desc.length() > linelen)
793 buf << endl << indent << description_add_links(desc);
797 buf << description_add_links(desc);
800 get_os() << buf.str() <<
"</td></tr>" << endl;
803 for (
Index i=0; i<mdr.
GIn().nelem(); ++i )
807 buf <<
"<td>GIN</td><td class=\"right\">" << mdr.
GIn()[i] <<
"</td><td>(";
811 bool firstarg =
true;
814 if (!firstarg) buf <<
", ";
else firstarg =
false;
825 buf <<
", Default: ";
839 lastlen = desc.length();
848 buf << indent << description_add_links(desc);
850 else if (lastlen + desc.length() > linelen)
853 buf << indent << description_add_links(desc);
857 buf << description_add_links(desc);
860 get_os() << buf.str() <<
"</td></tr>" << endl;
862 get_os() <<
"</table>" << endl;
866 insert_error_message(
"There is no method by this name.");
880 void Docserver::doc_variable_methods(
const string& vname)
888 Index wsv_key = mi->second;
894 <<
"<h3>Specific methods that can generate " << vname <<
"</h3>" << endl
904 if ( count( mdd.
Out().begin(),
908 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) <<
"\n";
912 if ( 0==hitcount ) get_os() <<
"<li>none\n";
914 get_os() << endl <<
"</ul>" << endl;
917 get_os() <<
"<h3>Generic and supergeneric methods that can generate " << vname <<
"</h3>" << endl;
918 get_os() <<
"<ul>" << endl;
932 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
935 else if ( count( mdd.
GOutType().begin(),
949 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
955 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
962 if ( 0==hitcount ) get_os() <<
"<li>none" << endl;
964 get_os() << endl <<
"</ul>" << endl;
969 <<
"<h3>Specific methods that require " << vname <<
"</h3>" << endl
979 if ( count( mdd.
In().begin(),
983 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) <<
"\n";
987 if ( 0==hitcount ) get_os() <<
"<li>none\n";
989 get_os() << endl <<
"</ul>" << endl;
993 get_os() <<
"<h3>Generic and supergeneric methods that can use " << vname <<
"</h3>" << endl;
994 get_os() <<
"<ul>" << endl;
1004 if ( count( mdd.
GInType().begin(),
1008 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1011 else if ( count( mdd.
GInType().begin(),
1025 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1031 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1038 if ( 0==hitcount ) get_os() <<
"<li>none" << endl;
1040 get_os() << endl <<
"</ul>" << endl;
1046 <<
"<h3>Agendas that can generate " << vname <<
"</h3>" << endl
1056 if ( count( ar.
Out().begin(),
1060 get_os() <<
"<li>" << insert_agenda_link(ar.
Name()) <<
"\n";
1064 if ( 0==hitcount ) get_os() <<
"<li>none\n";
1066 get_os() << endl <<
"</ul>" << endl;
1070 get_os() <<
"<h3>Agendas that require " << vname <<
"</h3>" << endl
1080 if ( count( ar.
In().begin(),
1084 get_os() <<
"<li>" << insert_agenda_link(ar.
Name()) <<
"\n";
1089 if ( 0==hitcount ) get_os() <<
"<li>none\n";
1091 get_os() << endl <<
"</ul>" << endl;
1105 void Docserver::doc_variable (
const string& vname)
1115 get_os() <<
"<pre>" << endl;
1117 get_os() << endl <<
"</pre>" << endl << endl;
1119 get_os() <<
"<p><b>Group: </b>"
1122 doc_variable_methods(vname);
1126 insert_error_message(
"There is no variable by this name.");
1140 void Docserver::doc_agenda (
const string& aname)
1147 extern const map<String, Index>
AgendaMap;
1148 map<String, Index>::const_iterator ait =
AgendaMap.find(aname);
1154 get_os() <<
"<pre>" << endl;
1155 get_os() << description_add_links(
agenda_data[ait->second].Description());
1156 get_os() << endl <<
"</pre>" << endl << endl;
1158 get_os() <<
"<p><b>Group: </b>"
1161 get_os() <<
"<h3>Variables</h3>" << endl;
1171 size_t linelen = 80;
1172 get_os() <<
"<table>" << endl;
1173 for (
Index i=0; i<agr.
Out().nelem(); ++i )
1177 buf <<
"<td>OUT</td>";
1181 buf <<
"<td class=\"right\">" << insert_wsv_link(vname) <<
"</td><td>(";
1183 buf <<
")</td><td>";
1188 if (buf.str().length() + desc.length() > linelen)
1191 buf << endl << indent << description_add_links(desc);
1195 buf << description_add_links(desc);
1198 get_os() << buf.str() <<
"</td></tr>" << endl;
1202 for (
Index i=0; i<agr.
In().nelem(); ++i )
1206 buf <<
"<td>IN</td>";
1209 buf <<
"<td class=\"right\">" << insert_wsv_link(vname);
1210 buf <<
"</td><td>(";
1212 buf <<
")</td><td>";
1216 if (buf.str().length() + desc.length() > linelen)
1219 buf << endl << indent << description_add_links(desc);
1223 buf << description_add_links(desc);
1226 get_os() << buf.str() <<
"</td></tr>" << endl;
1229 get_os() <<
"</table>" << endl;
1232 doc_variable_methods(aname);
1236 insert_error_message(
"There is no agenda by this name.");
1250 void Docserver::doc_group (
const string& gname)
1264 get_os() <<
"<h3>Specific methods that can generate " << gname <<
"</h3>" << endl;
1265 get_os() <<
"<ul>" << endl;
1272 for (
Index j=0; j<mdd.
Out().nelem(); j++)
1281 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) <<
" (";
1290 if (!first) get_os() <<
")" << endl;
1292 if ( 0==hitcount ) get_os() <<
"<li>none" << endl;
1294 get_os() << endl <<
"</ul>" << endl;
1298 get_os() <<
"<h3>Generic and supergeneric methods that can generate " << gname <<
"</h3>" << endl;
1299 get_os() <<
"<ul>" << endl;
1311 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1314 else if ( count( mdd.
GOutType().begin(),
1328 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1334 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1341 if ( 0==hitcount ) get_os() <<
"<li>none" << endl;
1343 get_os() << endl <<
"</ul>" << endl;
1348 get_os() <<
"<h3>Specific methods that require variables of group " << gname <<
"</h3>" << endl;
1349 get_os() <<
"<ul>" << endl;
1356 for (
Index j=0; j<mdd.
In().nelem(); j++)
1365 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) <<
" (";
1374 if (!first) get_os() <<
")" << endl;
1376 if ( 0==hitcount ) get_os() <<
"<li>none" << endl;
1378 get_os() << endl <<
"</ul>" << endl;
1382 get_os() <<
"<h3>Generic and supergeneric methods that can use " << gname <<
"</h3>" << endl;
1383 get_os() <<
"<ul>" << endl;
1395 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1398 else if ( count( mdd.
GInType().begin(),
1412 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1418 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1425 if ( 0==hitcount ) get_os() <<
"<li>none" << endl;
1427 get_os() << endl <<
"</ul>" << endl;
1433 get_os() <<
"<h3>Workspace Variables of group " << gname <<
"</h3>" << endl
1445 if ( 0==hitcount ) get_os() <<
"<li>none" << endl;
1447 get_os() <<
"</ul>" << endl;
1452 insert_error_message (
"There is no group by this name.");
1465 void Docserver::find_token_type ()
1467 if (tokens.size() < 1 || tokens[0] !=
"all")
return;
1470 extern const map<String, Index>
MdRawMap;
1471 extern const map<String, Index>
AgendaMap;
1475 tokens[0] =
"methods";
1477 tokens[0] =
"agendas";
1479 tokens[0] =
"variables";
1481 tokens[0] =
"groups";
1494 void Docserver::insert_breadcrumb_token (
size_t token_id)
1496 if (token_id != tokens.size())
1498 get_os() <<
"<a href=\"" << mbaseurl <<
"/";
1499 for (
size_t t = 0; t < token_id; t++)
1501 if (t) get_os() <<
"/";
1502 get_os() << tokens[t];
1507 if (!token_id) get_os() <<
"Home";
1508 else if (tokens[token_id-1] ==
"methods") get_os() <<
"Methods";
1509 else if (tokens[token_id-1] ==
"variables") get_os() <<
"Variables";
1510 else if (tokens[token_id-1] ==
"agendas") get_os() <<
"Agendas";
1511 else if (tokens[token_id-1] ==
"groups") get_os() <<
"Groups";
1512 else if (tokens[token_id-1] ==
"all") get_os() <<
"All";
1513 else if (tokens[token_id-1] ==
"doccheck") get_os() <<
"Doc Check";
1514 else get_os() << tokens[token_id-1];
1516 if (token_id != tokens.size()) get_os() <<
"</a>";
1527 void Docserver::insert_breadcrumbs ()
1529 get_os() <<
"<div id=\"navbar\"><div class=\"breadcrumbs\">";
1530 for (
size_t t = 0; t <= tokens.size(); t++)
1532 if (t) get_os() <<
" >> ";
1533 insert_breadcrumb_token(t);
1535 get_os() <<
"</div>" << endl;
1538 <<
"<div class=\"goto\">Go to: "
1539 <<
"<a href=\"" << mbaseurl <<
"/groups/\">Groups</a> - "
1540 <<
"<a href=\"" << mbaseurl <<
"/variables/\">Variables</a> - "
1541 <<
"<a href=\"" << mbaseurl <<
"/methods/\">Methods</a> - "
1542 <<
"<a href=\"" << mbaseurl <<
"/agendas/\">Agendas</a>"
1543 <<
"</div></div>" << endl;
1555 void Docserver::insert_error(
const string& error)
1558 insert_breadcrumbs();
1560 insert_error_message(error);
1574 void Docserver::insert_error_message(
const string& error)
1577 get_os() <<
"<p class=\"error\">" << error <<
"</p>" << endl;
1589 void Docserver::insert_title (
const string& title)
1591 get_os() <<
"<h1>"DOCSERVER_NAME;
1593 get_os() <<
" — " << title;
1594 get_os() <<
"</h1>" << endl;
1605 void Docserver::insert_index ()
1607 if (tokens.size() == 0 || tokens[0] ==
"all")
1610 insert_breadcrumbs();
1612 insert_title(
"Index");
1623 if (tokens[0] ==
"methods")
1625 begin_page(
"Method Index");
1626 insert_breadcrumbs();
1628 insert_title(
"Method Index");
1629 get_os() <<
"<table class=\"list\">" << endl;
1631 get_os() <<
"</table>" << endl;
1635 else if (tokens[0] ==
"variables")
1637 begin_page(
"Variable Index");
1638 insert_breadcrumbs();
1640 insert_title (
"Variable Index");
1641 get_os() <<
"<table class=\"list\">" << endl;
1643 get_os() <<
"</table>" << endl;
1647 else if (tokens[0] ==
"groups")
1649 begin_page(
"Group Index");
1650 insert_breadcrumbs();
1652 insert_title (
"Group Index");
1653 get_os() <<
"<table class=\"list\">" << endl;
1655 get_os() <<
"</table>" << endl;
1659 else if (tokens[0] ==
"agendas")
1661 begin_page(
"Agenda Index");
1662 insert_breadcrumbs();
1664 insert_title (
"Agenda Index");
1665 get_os() <<
"<table class=\"list\">" << endl;
1667 get_os() <<
"</table>" << endl;
1673 insert_error(DS_ERROR_404);
1686 void Docserver::insert_doc ()
1690 if (tokens[0] ==
"methods")
1692 begin_page(tokens[1]);
1693 insert_breadcrumbs();
1696 get_os() <<
"<h2>" <<
"Workspace Method " + tokens[1] <<
"</h2>" << endl;
1697 doc_method(tokens[1]);
1701 else if (tokens[0] ==
"variables")
1703 begin_page(tokens[1]);
1704 insert_breadcrumbs();
1707 get_os() <<
"<h2>" <<
"Workspace Variable " + tokens[1] <<
"</h2>" << endl;
1708 doc_variable(tokens[1]);
1712 else if (tokens[0] ==
"groups")
1714 begin_page(tokens[1]);
1715 insert_breadcrumbs();
1718 get_os() <<
"<h2>" <<
"Workspace Group " + tokens[1] <<
"</h2>" << endl;
1719 doc_group(tokens[1]);
1723 else if (tokens[0] ==
"agendas")
1725 begin_page(tokens[1]);
1726 insert_breadcrumbs();
1729 get_os() <<
"<h2>" <<
"Agenda " + tokens[1] <<
"</h2>" << endl;
1730 doc_agenda(tokens[1]);
1736 insert_error(DS_ERROR_404);
1747 void Docserver::insert_stylesheet ()
1750 <<
"body { font-family: monospace; }" << endl
1751 <<
"a:link { color: #3465a4; text-decoration: none; }" << endl
1752 <<
"a:visited { color: #729fcf; text-decoration: none; }" << endl
1753 <<
"a:active { color: #ce5c00; text-decoration: none; background-color: #eeeeec}" << endl
1754 <<
"a:hover { color: #f57900; text-decoration: none; }" << endl
1756 <<
"table.list {" << endl
1757 <<
"width: 90%;" << endl
1758 <<
"margin-left: 5%;" << endl
1759 <<
"margin-right: 5%;" << endl
1763 <<
"font-size: 1.5em;" << endl
1767 <<
"font-size: 1.25em;" << endl
1771 <<
"font-size: 1em;" << endl
1775 <<
"font-size: 1em;" << endl
1778 <<
"#navbar {" << endl
1779 <<
"position: fixed;" << endl
1780 <<
"top: 0px;" << endl
1781 <<
"left: 10px;" << endl
1782 <<
"right: 10px;" << endl
1783 <<
"background-color: #fff;" << endl
1784 <<
"border-bottom: solid 1px #ddd;" << endl
1785 <<
"border-left: solid 1px #ddd;" << endl
1786 <<
"border-right: solid 1px #ddd;" << endl
1787 <<
"padding: 2px;" << endl
1790 <<
".firstcol {" << endl
1791 <<
"float: left;" << endl
1792 <<
"clear: left;" << endl
1793 <<
"width: 50%;" << endl
1794 <<
"white-space: nowrap;" << endl
1797 <<
".firstcol ul {" << endl
1798 <<
"float: left;" << endl
1799 <<
"clear: both;" << endl
1800 <<
"padding-top: 0;" << endl
1803 <<
".secondcol ul {" << endl
1804 <<
"float: left;" << endl
1805 <<
"clear: both;" << endl
1806 <<
"padding-top: 0;" << endl
1809 <<
".secondcol {" << endl
1810 <<
"float: left;" << endl
1811 <<
"clear: right;" << endl
1812 <<
"width: 50%;" << endl
1813 <<
"white-space: nowrap;" << endl
1816 <<
".firstcol ul li {" << endl
1817 <<
"margin-left: 0;" << endl
1820 <<
".brokendoclink {" << endl
1821 <<
"color: #f00;" << endl
1824 <<
".goto {" << endl
1825 <<
"font-size: small;" << endl
1826 <<
"float: right;" << endl
1829 <<
".breadcrumbs {" << endl
1830 <<
"font-size: small;" << endl
1831 <<
"float: left;" << endl
1834 <<
"@media only screen and (max-device-width: 480px) {" << endl
1835 <<
"#navbar { position: static; border: none; }" << endl
1836 <<
".goto { position: static; float: none; }" << endl
1837 <<
".breadcrumbs { position: static; float: none; }" << endl
1838 <<
".firstcol { float: left; clear: left; width: 100%; }" << endl
1839 <<
".secondcol { float: left; clear: both; width: 100%; }" << endl
1840 <<
".firstcol ul { margin-top: 0; margin-bottom: 0; }" << endl
1841 <<
".secondcol ul { margin-top: 0; }" << endl
1842 <<
"ul { padding-left: 1em; }" << endl
1845 <<
"table {" << endl
1846 <<
"border-width: 0px;" << endl
1849 <<
"table td {" << endl
1850 <<
"vertical-align: top;" << endl
1853 <<
"table td.right {" << endl
1854 <<
"text-align: right;" << endl
1857 <<
".content {" << endl
1858 <<
"padding-top: 1em;" << endl
1859 <<
"clear: both;" << endl
1860 <<
"width: 100%;" << endl
1863 <<
".error {" << endl
1864 <<
"color: #ff0000;" << endl
1865 <<
"font-weight: bold;" << endl
1866 <<
"font-size: 1.2em;" << endl
1869 <<
"div.footer {" << endl
1870 <<
"float: left;" << endl
1871 <<
"text-align: right;" << endl
1872 <<
"color: #aaaaa8;" << endl
1873 <<
"font-size: small;" << endl
1874 <<
"clear: left;" << endl
1875 <<
"margin-top: 2em;" << endl
1876 <<
"width: 100%;" << endl
1890 void Docserver::insert_broken_doc_links()
1892 begin_page(tokens[1]);
1893 insert_breadcrumbs();
1895 insert_title (
"Broken links");
1901 vector<string> broken_links;
1904 if (broken_links.size())
1909 get_os() <<
"<h2>Variable descriptions</h2>" << endl;
1912 for (vector<string>::iterator it = broken_links.begin();
1913 it != broken_links.end(); it++)
1915 if (it != broken_links.begin()) get_os() <<
", ";
1918 get_os() <<
"</p>" << endl;
1929 vector<string> broken_links;
1930 broken_links = find_broken_description_links(ait->Description());
1932 if (broken_links.size())
1937 get_os() <<
"<h2>Agenda descriptions</h2>" << endl;
1939 get_os() <<
"<p>" << insert_agenda_link(ait->Name()) <<
": ";
1940 for (vector<string>::iterator it = broken_links.begin();
1941 it != broken_links.end(); it++)
1943 if (it != broken_links.begin()) get_os() <<
", ";
1946 get_os() <<
"</p>" << endl;
1957 vector<string> broken_links;
1958 broken_links = find_broken_description_links(mit->Description(), mit->Name());
1960 if (broken_links.size())
1965 get_os() <<
"<h2>Method descriptions</h2>" << endl;
1967 get_os() <<
"<p>" << insert_wsm_link(mit->Name()) <<
": ";
1968 for (vector<string>::iterator it = broken_links.begin();
1969 it != broken_links.end(); it++)
1971 if (it != broken_links.begin()) get_os() <<
", ";
1974 get_os() <<
"</p>" << endl;
1994 vector<string> Docserver::find_broken_description_links (
const String& desc,
const String& mname)
1996 vector<string> broken_links;
1999 bool inside_link =
false;
2000 string::const_iterator it = desc.begin();
2002 extern const map<String, Index>
MdRawMap;
2003 extern const map<String, Index>
AgendaMap;
2005 while (it != desc.end()) {
2011 ret += html_escape_char(*it);
2017 inside_link =
false;
2024 else if (mname !=
"")
2026 extern const map<String, Index>
MdRawMap;
2029 map<String, Index>::const_iterator mit =
MdRawMap.find(mname);
2035 for (ArrayOfString::const_iterator sit = mdr.
GIn().begin();
2036 !found && sit != mdr.
GIn().end();
2041 ret +=
"*" + link +
"*";
2046 for (ArrayOfString::const_iterator sit = mdr.
GOut().begin();
2047 !found && sit != mdr.
GOut().end();
2052 ret +=
"*" + link +
"*";
2060 broken_links.push_back(
"<span class=\"brokendoclink\">*" + link +
"*</span>");
2066 if (!isalnum(*it) && *it !=
'_')
2068 inside_link =
false;
2069 ret +=
"*" + link + *it;
2073 link += html_escape_char(*it);
2082 return broken_links;
2096 int Docserver::launch(
bool daemon)
2098 struct MHD_Daemon *d;
2100 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
2101 (uint16_t)mport, NULL, NULL, &ahc_echo, (
void *)
this, MHD_OPTION_END);
2105 cerr <<
"Error: Cannot start server. Maybe port " << mport <<
" is already in use?\n";
2111 cerr <<
"ARTS docserver listening at http://localhost:" << mport <<
"\n";
2114 <<
"===========================================================\n"
2115 <<
"Now point your web browser to http://localhost:" << mport <<
"\n"
2116 <<
"===========================================================\n\n"
2117 <<
"Press enter to exit.\n";
2126 (void) getc (stdin);
2127 cout <<
"Stopping docserver.\n";
2128 MHD_stop_daemon (d);
2129 cout <<
"Goodbye.\n";
2144 Docserver::Docserver(
const Index port,
const string& baseurl) : mos(NULL)
2147 if (port == -1) mport=9000;
else mport=port;
2169 static int ahc_echo (
void *cls,
2170 struct MHD_Connection *connection,
2173 const char *version
_U_,
2174 const char *upload_data
_U_,
2175 size_t *upload_data_size
_U_,
2180 struct MHD_Response *response;
2185 cerr <<
"Docserver error: Docserver object reference is NULL.\n";
2190 Docserver docserver = *((Docserver *)cls);
2192 if (0 != strcmp (method,
"GET"))
2194 cerr <<
"Docserver error: Unexpected method " << method <<
".\n";
2204 MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND,
"q");
2206 string content_type;
2208 docserver.set_ostream(hout);
2209 content_type = docserver.new_page(surl);
2210 docserver.clear_ostream();
2212 response = MHD_create_response_from_data (hout.str().length(),
2213 (
void *)hout.str().c_str(),
2216 if (response == NULL) {
2217 cerr <<
"Docserver error: response = 0\n";
2221 MHD_add_response_header (response,
"Content-type", content_type.c_str());
2222 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
2223 MHD_destroy_response (response);