28 #ifdef ENABLE_DOCSERVER
36 #include "libmicrohttpd/platform.h"
37 #include "libmicrohttpd/microhttpd.h"
45 #define DOCSERVER_NAME "ARTS built-in documentation server"
47 #define DS_ERROR_404 "Page not found"
50 static int ahc_echo(
void* cls,
51 struct MHD_Connection* connection,
55 const char* upload_data,
56 size_t* upload_data_size,
71 if (indent.length() + curline.str().length() + token.str().length() > linelen)
73 get_os() << curline.str() << endl << indent;
76 curline << token.str();
90 string Docserver::new_page(
const string& url)
94 if (surl.find(get_baseurl()) == 0)
95 surl.erase(0, get_baseurl().size());
99 while (tokens.size() && tokens[tokens.size()-1] ==
"")
102 while (tokens.size() && tokens[0] ==
"")
103 tokens.erase(tokens.begin());
105 string content_type =
"text/html; charset=utf-8";
106 if (tokens.size() && tokens[tokens.size()-1] ==
"styles.css")
109 content_type =
"text/css; charset=utf-8";
111 else if (tokens.size() && tokens[tokens.size()-1] ==
"doccheck")
113 insert_broken_doc_links();
117 switch (tokens.size())
127 insert_error(DS_ERROR_404);
144 void Docserver::split_tokens(
const string& s)
150 while (getline(ss, item,
'/'))
151 tokens.push_back(item);
166 string Docserver::html_escape_char(
const char ch)
172 case '<': ret.append(
"<");
break;
173 case '>': ret.append(
">");
break;
174 default: ret.append(1, ch);
191 string Docserver::html_escape_string(
const string& s)
195 for (string::const_iterator it = s.begin(); it != s.end(); it++)
196 ret.append(html_escape_char(*it));
208 void Docserver::begin_content()
210 get_os() <<
"<div class=\"content\">" << endl;
220 void Docserver::end_content()
222 get_os() <<
"</div>" << endl;
234 void Docserver::begin_page(
string title)
236 if (title.length()) title +=
" - ";
238 title += DOCSERVER_NAME;
241 <<
"<!DOCTYPE html>" << endl
242 <<
"<html lang=\"en\">" << endl
244 <<
"<title>" << title <<
"</title>" << endl
245 <<
"<meta charset=\"utf-8\">" << endl
246 <<
"<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />" << endl
247 <<
"<link rel=\"stylesheet\" href=\"" << mbaseurl <<
"/styles.css\">" << endl
259 void Docserver::end_page()
262 <<
" - <a href=\"" << mbaseurl <<
"/doccheck\">Check docs</a></div>\n" << endl;
264 get_os() <<
"</body>" << endl <<
"</html>";
278 String Docserver::insert_agenda_link(
const String& aname)
281 ret <<
"<a href=\"" << mbaseurl <<
"/agendas/" << aname <<
"\">" << aname <<
"</a>";
296 String Docserver::insert_group_link(
const String& gname)
299 ret <<
"<a href=\"" << mbaseurl <<
"/groups/" << gname <<
"\">" << gname <<
"</a>";
317 ret <<
"<a href=\"" << mbaseurl <<
"/methods/" << mname <<
"\">" << mname <<
"</a>";
341 ret <<
"<a href=\"" << mbaseurl <<
"/agendas/" << vname <<
"\">" << vname <<
"</a>";
343 ret <<
"<a href=\"" << mbaseurl <<
"/variables/" << vname <<
"\">" << vname <<
"</a>";
356 void Docserver::list_agendas()
360 get_os() <<
"<h2>Agendas</h2>" << endl;
362 get_os() <<
"<div class=\"firstcol\">" << endl <<
"<ul>" << endl;
374 get_os() <<
"<li>" << insert_agenda_link(
Workspace::wsv_data[i].Name()) <<
"</li>" << endl;
377 if (hitcount2 == hitcount/2)
378 get_os() <<
"</ul>" << endl <<
"</div>" << endl
379 <<
"<div class=\"secondcol\">" << endl <<
"<ul>" << endl;
383 get_os() <<
"</ul>" << endl <<
"</div>" << endl;
393 void Docserver::list_groups()
398 get_os() <<
"<h2>Workspace Groups</h2>" << endl;
400 get_os() <<
"<div class=\"firstcol\">" << endl <<
"<ul>" << endl;
403 get_os() <<
"<li>" << insert_group_link(
wsv_group_names[i]) <<
"</li>" << endl;
406 get_os() <<
"</ul>" << endl <<
"</div>" << endl
407 <<
"<div class=\"secondcol\">" << endl <<
"<ul>" << endl;
410 get_os() <<
"</ul>" << endl <<
"</div>" << endl;
420 void Docserver::list_methods()
425 get_os() <<
"<h2>Workspace Methods</h2>" << endl;
427 get_os() <<
"<div class=\"firstcol\">" << endl <<
"<ul>" << endl;
430 get_os() <<
"<li>" << insert_wsm_link(
md_data_raw[i].Name()) <<
"</li>" << endl;
433 get_os() <<
"</ul>" << endl <<
"</div>" << endl
434 <<
"<div class=\"secondcol\">" << endl <<
"<ul>" << endl;
437 get_os() <<
"</ul>" << endl <<
"</div>" << endl;
447 void Docserver::list_variables()
451 get_os() <<
"<h2>Workspace Variables</h2>" << endl;
453 get_os() <<
"<div class=\"firstcol\">" << endl <<
"<ul>" << endl;
469 if (hitcount2 == hitcount/2)
470 get_os() <<
"</ul>" << endl <<
"</div>" << endl
471 <<
"<div class=\"secondcol\">" << endl <<
"<ul>" << endl;
475 get_os() <<
"</ul>" << endl <<
"</div>" << endl;
494 bool inside_link =
false;
495 string::const_iterator it = desc.begin();
500 while (it != desc.end())
507 ret += html_escape_char(*it);
515 ret += insert_wsm_link(link);
517 ret += insert_agenda_link(link);
519 ret += insert_wsv_link(link);
521 ret += insert_group_link(link);
522 else if (mname !=
"")
528 map<String, Index>::const_iterator mit =
MdRawMap.find(mname);
534 for (ArrayOfString::const_iterator sit = mdr.
GIn().begin();
535 !found && sit != mdr.
GIn().end();
540 ret +=
"*" + link +
"*";
545 for (ArrayOfString::const_iterator sit = mdr.
GOut().begin();
546 !found && sit != mdr.
GOut().end();
551 ret +=
"*" + link +
"*";
558 ret +=
"<span class=\"brokendoclink\">*" + link +
"*</span>";
561 ret +=
"<span class=\"brokendoclink\">*" + link +
"*</span>";
567 if (!isalnum(*it) && *it !=
'_')
570 ret +=
"*" + link + *it;
573 else link += html_escape_char(*it);
580 if (inside_link) ret +=
"*" + link;
595 void Docserver::doc_method(
const string& mname)
606 map<String, Index>::const_iterator it =
MdRawMap.find(mname);
613 get_os() <<
"<h3>Description</h3>" << endl;
615 get_os() <<
"<pre>" << endl;
616 get_os() << description_add_links(mdr.
Description(), mname);
617 get_os() << endl <<
"</pre>" << endl << endl;
619 bool is_first_author =
true;
624 get_os() <<
"<p><b>Authors: </b>";
625 is_first_author =
false;
635 while (indent.length() < mdr.
Name().length() + 2)
638 get_os() <<
"<h3>Synopsis</h3>" << endl;
642 const size_t linelen = 2048;
644 buf <<
"<p><table><tr><td>" << mdr.
Name() <<
"( </td><td>";
646 for (
Index i = 0; i < mdr.
Out().nelem(); ++i)
648 if (first) first =
false;
657 if (first) first =
false;
660 if (mdr.
GOut()[i].length())
661 param << mdr.
GOut()[i];
663 param <<
"gout" << i;
671 if (first) first =
false;
681 if (first) first =
false;
684 if (mdr.
GIn()[i].length()) param << mdr.
GIn()[i];
685 else param <<
"gin" << i;
689 if (buf.str().length()) get_os() << buf.str();
691 get_os() <<
" )</td></tr></table>" << endl;
693 get_os() <<
"<h3>Variables</h3>" << endl;
698 get_os() <<
"<table>" << endl;
699 for (
Index i = 0; i < mdr.
Out().nelem(); ++i)
703 if (std::find(mdr.
In().begin(), mdr.
In().end(), mdr.
Out()[i]) == mdr.
In().end())
704 buf <<
"<td>OUT</td>";
706 buf <<
"<td>OUT+IN</td>";
710 buf <<
"<td class=\"right\">" << insert_wsv_link(vname) <<
"</td><td>(";
717 if (buf.str().length() + desc.length() > linelen)
720 buf << endl << indent << description_add_links(desc);
724 buf << description_add_links(desc);
727 get_os() << buf.str() <<
"</td></tr>" << endl;
732 for (
Index i = 0; i < mdr.
GOut().nelem(); ++i)
736 buf <<
"<td>GOUT</td><td class=\"right\">" << mdr.
GOut()[i] <<
"</td><td>(";
740 bool firstarg =
true;
743 if (!firstarg) buf <<
", ";
744 else firstarg =
false;
756 lastlen = desc.length();
765 buf << endl << indent << description_add_links(desc);
769 if (lastlen + desc.length() > linelen)
772 buf << endl << description_add_links(desc);
774 else buf << description_add_links(desc);
777 get_os() << buf.str() <<
"</td></tr>" << endl;
780 for (
Index i = 0; i < mdr.
In().nelem(); ++i)
782 if (std::find(mdr.
Out().begin(), mdr.
Out().end(), mdr.
In()[i]) != mdr.
Out().end())
787 buf <<
"<td>IN</td>";
790 buf <<
"<td class=\"right\">" << insert_wsv_link(vname);
797 if (buf.str().length() + desc.length() > linelen)
800 buf << endl << indent << description_add_links(desc);
802 else buf << description_add_links(desc);
804 get_os() << buf.str() <<
"</td></tr>" << endl;
807 for (
Index i = 0; i < mdr.
GIn().nelem(); ++i)
811 buf <<
"<td>GIN</td><td class=\"right\">" << mdr.
GIn()[i] <<
"</td><td>(";
815 bool firstarg =
true;
818 if (!firstarg) buf <<
", ";
819 else firstarg =
false;
830 buf <<
", Default: ";
844 lastlen = desc.length();
853 buf << indent << description_add_links(desc);
855 else if (lastlen + desc.length() > linelen)
858 buf << indent << description_add_links(desc);
862 buf << description_add_links(desc);
865 get_os() << buf.str() <<
"</td></tr>" << endl;
867 get_os() <<
"</table>" << endl;
871 insert_error_message(
"There is no method by this name.");
885 void Docserver::doc_variable_methods(
const string& vname)
893 Index wsv_key = mi->second;
899 <<
"<h3>Specific methods that can generate " << vname <<
"</h3>" << endl
909 if (count(mdd.
Out().begin(),
913 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) <<
"\n";
917 if (0 == hitcount) get_os() <<
"<li>none\n";
919 get_os() << endl <<
"</ul>" << endl;
922 get_os() <<
"<h3>Generic and supergeneric methods that can generate " << vname <<
"</h3>"
924 get_os() <<
"<ul>" << endl;
938 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
941 else if (count(mdd.
GOutType().begin(),
955 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
961 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
968 if (0 == hitcount) get_os() <<
"<li>none" << endl;
970 get_os() << endl <<
"</ul>" << endl;
975 <<
"<h3>Specific methods that require " << vname <<
"</h3>" << endl
985 if (count(mdd.
In().begin(), mdd.
In().end(), wsv_key))
987 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) <<
"\n";
991 if (0 == hitcount) get_os() <<
"<li>none\n";
993 get_os() << endl <<
"</ul>" << endl;
997 get_os() <<
"<h3>Generic and supergeneric methods that can use " << vname <<
"</h3>"
999 get_os() <<
"<ul>" << endl;
1009 if (count(mdd.
GInType().begin(),
1012 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1015 else if (count(mdd.
GInType().begin(),
1029 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1035 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1042 if (0 == hitcount) get_os() <<
"<li>none" << endl;
1044 get_os() << endl <<
"</ul>" << endl;
1050 <<
"<h3>Agendas that can generate " << vname <<
"</h3>" << endl
1060 if (count(ar.
Out().begin(), ar.
Out().end(), wsv_key))
1062 get_os() <<
"<li>" << insert_agenda_link(ar.
Name()) <<
"\n";
1066 if (0 == hitcount) get_os() <<
"<li>none\n";
1068 get_os() << endl <<
"</ul>" << endl;
1072 get_os() <<
"<h3>Agendas that require " << vname <<
"</h3>" << endl
1082 if (count(ar.
In().begin(), ar.
In().end(), wsv_key))
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>"
1123 doc_variable_methods(vname);
1127 insert_error_message(
"There is no variable by this name.");
1141 void Docserver::doc_agenda(
const string& aname)
1149 map<String, Index>::const_iterator ait =
AgendaMap.find(aname);
1155 get_os() <<
"<pre>" << endl;
1156 get_os() << description_add_links(
agenda_data[ait->second].Description());
1157 get_os() << endl <<
"</pre>" << endl << endl;
1159 get_os() <<
"<p><b>Group: </b>"
1163 get_os() <<
"<h3>Variables</h3>" << endl;
1173 size_t linelen = 80;
1174 get_os() <<
"<table>" << endl;
1175 for (
Index i = 0; i < agr.
Out().nelem(); ++i)
1179 buf <<
"<td>OUT</td>";
1183 buf <<
"<td class=\"right\">" << insert_wsv_link(vname) <<
"</td><td>(";
1185 buf <<
")</td><td>";
1190 if (buf.str().length() + desc.length() > linelen)
1193 buf << endl << indent << description_add_links(desc);
1197 buf << description_add_links(desc);
1200 get_os() << buf.str() <<
"</td></tr>" << endl;
1204 for (
Index i = 0; i < agr.
In().nelem(); ++i)
1208 buf <<
"<td>IN</td>";
1211 buf <<
"<td class=\"right\">" << insert_wsv_link(vname);
1212 buf <<
"</td><td>(";
1214 buf <<
")</td><td>";
1218 if (buf.str().length() + desc.length() > linelen)
1221 buf << endl << indent << description_add_links(desc);
1224 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>"
1300 get_os() <<
"<ul>" << endl;
1312 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1327 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1333 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1340 if (0 == hitcount) get_os() <<
"<li>none" << endl;
1342 get_os() << endl <<
"</ul>" << endl;
1347 get_os() <<
"<h3>Specific methods that require variables of group " << gname <<
"</h3>"
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;
1410 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1416 get_os() <<
"<li>" << insert_wsm_link(mdd.
Name()) << endl;
1423 if (0 == hitcount) get_os() <<
"<li>none" << endl;
1425 get_os() << endl <<
"</ul>" << endl;
1431 get_os() <<
"<h3>Workspace Variables of group " << gname <<
"</h3>" << endl
1443 if (0 == hitcount) get_os() <<
"<li>none" << endl;
1445 get_os() <<
"</ul>" << endl;
1450 insert_error_message(
"There is no group by this name.");
1463 void Docserver::find_token_type()
1465 if (tokens.size() < 1 || tokens[0] !=
"all")
return;
1473 tokens[0] =
"methods";
1475 tokens[0] =
"agendas";
1477 tokens[0] =
"variables";
1479 tokens[0] =
"groups";
1492 void Docserver::insert_breadcrumb_token(
size_t token_id)
1494 if (token_id != tokens.size())
1496 get_os() <<
"<a href=\"" << mbaseurl <<
"/";
1497 for (
size_t t = 0; t < token_id; t++)
1499 if (t) get_os() <<
"/";
1500 get_os() << tokens[t];
1505 if (!token_id) get_os() <<
"Home";
1506 else if (tokens[token_id-1] ==
"methods") get_os() <<
"Methods";
1507 else if (tokens[token_id-1] ==
"variables") get_os() <<
"Variables";
1508 else if (tokens[token_id-1] ==
"agendas") get_os() <<
"Agendas";
1509 else if (tokens[token_id-1] ==
"groups") get_os() <<
"Groups";
1510 else if (tokens[token_id-1] ==
"all") get_os() <<
"All";
1511 else if (tokens[token_id-1] ==
"doccheck") get_os() <<
"Doc Check";
1512 else get_os() << tokens[token_id-1];
1514 if (token_id != tokens.size()) get_os() <<
"</a>";
1525 void Docserver::insert_breadcrumbs()
1527 get_os() <<
"<div id=\"navbar\"><div class=\"breadcrumbs\">";
1528 for (
size_t t = 0; t <= tokens.size(); t++)
1530 if (t) get_os() <<
" >> ";
1531 insert_breadcrumb_token(t);
1533 get_os() <<
"</div>" << endl;
1536 <<
"<div class=\"goto\">Go to: "
1537 <<
"<a href=\"" << mbaseurl <<
"/groups/\">Groups</a> - "
1538 <<
"<a href=\"" << mbaseurl <<
"/variables/\">Variables</a> - "
1539 <<
"<a href=\"" << mbaseurl <<
"/methods/\">Methods</a> - "
1540 <<
"<a href=\"" << mbaseurl <<
"/agendas/\">Agendas</a>"
1541 <<
"</div></div>" << endl;
1553 void Docserver::insert_error(
const string& error)
1556 insert_breadcrumbs();
1558 insert_error_message(error);
1572 void Docserver::insert_error_message(
const string& error)
1575 get_os() <<
"<p class=\"error\">" << error <<
"</p>" << endl;
1587 void Docserver::insert_title(
const string& title)
1589 get_os() <<
"<h1>" DOCSERVER_NAME;
1591 get_os() <<
" — " << title;
1592 get_os() <<
"</h1>" << endl;
1603 void Docserver::insert_index()
1605 if (tokens.size() == 0 || tokens[0] ==
"all")
1608 insert_breadcrumbs();
1610 insert_title(
"Index");
1621 if (tokens[0] ==
"methods")
1623 begin_page(
"Method Index");
1624 insert_breadcrumbs();
1626 insert_title(
"Method Index");
1627 get_os() <<
"<table class=\"list\">" << endl;
1629 get_os() <<
"</table>" << endl;
1633 else if (tokens[0] ==
"variables")
1635 begin_page(
"Variable Index");
1636 insert_breadcrumbs();
1638 insert_title(
"Variable Index");
1639 get_os() <<
"<table class=\"list\">" << endl;
1641 get_os() <<
"</table>" << endl;
1645 else if (tokens[0] ==
"groups")
1647 begin_page(
"Group Index");
1648 insert_breadcrumbs();
1650 insert_title(
"Group Index");
1651 get_os() <<
"<table class=\"list\">" << endl;
1653 get_os() <<
"</table>" << endl;
1657 else if (tokens[0] ==
"agendas")
1659 begin_page(
"Agenda Index");
1660 insert_breadcrumbs();
1662 insert_title(
"Agenda Index");
1663 get_os() <<
"<table class=\"list\">" << endl;
1665 get_os() <<
"</table>" << endl;
1671 insert_error(DS_ERROR_404);
1684 void Docserver::insert_doc()
1688 if (tokens[0] ==
"methods")
1690 begin_page(tokens[1]);
1691 insert_breadcrumbs();
1694 get_os() <<
"<h2>" <<
"Workspace Method " + tokens[1] <<
"</h2>" << endl;
1695 doc_method(tokens[1]);
1699 else if (tokens[0] ==
"variables")
1701 begin_page(tokens[1]);
1702 insert_breadcrumbs();
1705 get_os() <<
"<h2>" <<
"Workspace Variable " + tokens[1] <<
"</h2>" << endl;
1706 doc_variable(tokens[1]);
1710 else if (tokens[0] ==
"groups")
1712 begin_page(tokens[1]);
1713 insert_breadcrumbs();
1716 get_os() <<
"<h2>" <<
"Workspace Group " + tokens[1] <<
"</h2>" << endl;
1717 doc_group(tokens[1]);
1721 else if (tokens[0] ==
"agendas")
1723 begin_page(tokens[1]);
1724 insert_breadcrumbs();
1727 get_os() <<
"<h2>" <<
"Agenda " + tokens[1] <<
"</h2>" << endl;
1728 doc_agenda(tokens[1]);
1734 insert_error(DS_ERROR_404);
1745 void Docserver::insert_stylesheet()
1748 <<
"body { font-family: monospace; }" << endl
1749 <<
"a:link { color: #3465a4; text-decoration: none; }" << endl
1750 <<
"a:visited { color: #729fcf; text-decoration: none; }" << endl
1751 <<
"a:active { color: #ce5c00; text-decoration: none; background-color: #eeeeec}" << endl
1752 <<
"a:hover { color: #f57900; text-decoration: none; }" << endl
1754 <<
"table.list {" << endl
1755 <<
"width: 90%;" << endl
1756 <<
"margin-left: 5%;" << endl
1757 <<
"margin-right: 5%;" << endl
1761 <<
"font-size: 1.5em;" << endl
1765 <<
"font-size: 1.25em;" << endl
1769 <<
"font-size: 1em;" << endl
1773 <<
"font-size: 1em;" << endl
1776 <<
"#navbar {" << endl
1777 <<
"position: fixed;" << endl
1778 <<
"top: 0px;" << endl
1779 <<
"left: 10px;" << endl
1780 <<
"right: 10px;" << endl
1781 <<
"background-color: #fff;" << endl
1782 <<
"border-bottom: solid 1px #ddd;" << endl
1783 <<
"border-left: solid 1px #ddd;" << endl
1784 <<
"border-right: solid 1px #ddd;" << endl
1785 <<
"padding: 2px;" << endl
1788 <<
".firstcol {" << endl
1789 <<
"float: left;" << endl
1790 <<
"clear: left;" << endl
1791 <<
"width: 50%;" << endl
1792 <<
"white-space: nowrap;" << endl
1795 <<
".firstcol ul {" << endl
1796 <<
"float: left;" << endl
1797 <<
"clear: both;" << endl
1798 <<
"padding-top: 0;" << endl
1801 <<
".secondcol ul {" << endl
1802 <<
"float: left;" << endl
1803 <<
"clear: both;" << endl
1804 <<
"padding-top: 0;" << endl
1807 <<
".secondcol {" << endl
1808 <<
"float: left;" << endl
1809 <<
"clear: right;" << endl
1810 <<
"width: 50%;" << endl
1811 <<
"white-space: nowrap;" << endl
1814 <<
".firstcol ul li {" << endl
1815 <<
"margin-left: 0;" << endl
1818 <<
".brokendoclink {" << endl
1819 <<
"color: #f00;" << endl
1822 <<
".goto {" << endl
1823 <<
"font-size: small;" << endl
1824 <<
"float: right;" << endl
1827 <<
".breadcrumbs {" << endl
1828 <<
"font-size: small;" << endl
1829 <<
"float: left;" << endl
1832 <<
"@media only screen and (max-device-width: 480px) {" << endl
1833 <<
"#navbar { position: static; border: none; }" << endl
1834 <<
".goto { position: static; float: none; }" << endl
1835 <<
".breadcrumbs { position: static; float: none; }" << endl
1836 <<
".firstcol { float: left; clear: left; width: 100%; }" << endl
1837 <<
".secondcol { float: left; clear: both; width: 100%; }" << endl
1838 <<
".firstcol ul { margin-top: 0; margin-bottom: 0; }" << endl
1839 <<
".secondcol ul { margin-top: 0; }" << endl
1840 <<
"ul { padding-left: 1em; }" << endl
1843 <<
"table {" << endl
1844 <<
"border-width: 0px;" << endl
1847 <<
"table td {" << endl
1848 <<
"vertical-align: top;" << endl
1851 <<
"table td.right {" << endl
1852 <<
"text-align: right;" << endl
1855 <<
".content {" << endl
1856 <<
"padding-top: 1em;" << endl
1857 <<
"clear: both;" << endl
1858 <<
"width: 100%;" << endl
1861 <<
".error {" << endl
1862 <<
"color: #ff0000;" << endl
1863 <<
"font-weight: bold;" << endl
1864 <<
"font-size: 1.2em;" << endl
1867 <<
"div.footer {" << endl
1868 <<
"float: left;" << endl
1869 <<
"text-align: right;" << endl
1870 <<
"color: #aaaaa8;" << endl
1871 <<
"font-size: small;" << endl
1872 <<
"clear: left;" << endl
1873 <<
"margin-top: 2em;" << endl
1874 <<
"width: 100%;" << endl
1888 void Docserver::insert_broken_doc_links()
1890 begin_page(tokens[1]);
1891 insert_breadcrumbs();
1893 insert_title(
"Broken links");
1899 vector<string> broken_links;
1902 if (broken_links.size())
1907 get_os() <<
"<h2>Variable descriptions</h2>" << endl;
1910 for (vector<string>::iterator it = broken_links.begin();
1911 it != broken_links.end(); it++)
1913 if (it != broken_links.begin()) get_os() <<
", ";
1916 get_os() <<
"</p>" << endl;
1927 vector<string> broken_links;
1928 broken_links = find_broken_description_links(ait->Description());
1930 if (broken_links.size())
1935 get_os() <<
"<h2>Agenda descriptions</h2>" << endl;
1937 get_os() <<
"<p>" << insert_agenda_link(ait->Name()) <<
": ";
1938 for (vector<string>::iterator it = broken_links.begin();
1939 it != broken_links.end(); it++)
1941 if (it != broken_links.begin()) get_os() <<
", ";
1944 get_os() <<
"</p>" << endl;
1956 vector<string> broken_links;
1957 broken_links = find_broken_description_links(mit->Description(), mit->Name());
1959 if (broken_links.size())
1964 get_os() <<
"<h2>Method descriptions</h2>" << endl;
1966 get_os() <<
"<p>" << insert_wsm_link(mit->Name()) <<
": ";
1967 for (vector<string>::iterator it = broken_links.begin();
1968 it != broken_links.end(); it++)
1970 if (it != broken_links.begin()) get_os() <<
", ";
1973 get_os() <<
"</p>" << endl;
1993 vector<string> Docserver::find_broken_description_links(
const String& desc,
const String& mname)
1995 vector<string> broken_links;
1998 bool inside_link =
false;
1999 string::const_iterator it = desc.begin();
2004 while (it != desc.end())
2011 ret += html_escape_char(*it);
2017 inside_link =
false;
2024 else if (mname !=
"")
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";
2120 if (daemon) pause();
2124 cout <<
"Stopping docserver.\n";
2126 cout <<
"Goodbye.\n";
2141 Docserver::Docserver(
const Index port,
const string& baseurl) : mos(NULL)
2144 if (port == -1) mport = 9000;
2167 static int ahc_echo(
void* cls,
2168 struct MHD_Connection* connection,
2171 const char* version
_U_,
2172 const char* upload_data
_U_,
2173 size_t* upload_data_size
_U_,
2178 struct MHD_Response* response;
2183 cerr <<
"Docserver error: Docserver object reference is NULL.\n";
2188 Docserver docserver = *((Docserver*)cls);
2190 if (0 != strcmp(method,
"GET"))
2192 cerr <<
"Docserver error: Unexpected method " << method <<
".\n";
2202 MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND,
"q");
2204 string content_type;
2206 docserver.set_ostream(hout);
2207 content_type = docserver.new_page(surl);
2208 docserver.clear_ostream();
2210 response = MHD_create_response_from_data(hout.str().length(),
2211 (
void*)hout.str().c_str(),
2214 if (response == NULL)
2216 cerr <<
"Docserver error: response = 0\n";
2220 MHD_add_response_header(response,
"Content-type", content_type.c_str());
2221 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
2222 MHD_destroy_response(response);