📄 click-pretty.cc
字号:
// -*- c-basic-offset: 4 -*-/* * click-pretty.cc -- pretty-print Click configurations * Eddie Kohler * * Copyright (c) 2001-2002 International Computer Science Institute * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include <click/pathvars.h>#include "routert.hh"#include "lexert.hh"#include "lexertinfo.hh"#include "html.hh"#include <click/error.hh>#include <click/driver.hh>#include <click/straccum.hh>#include <click/confparse.hh>#include <click/clp.h>#include "toolutils.hh"#include "processingt.hh"#include "elementmap.hh"#define HELP_OPT 300#define VERSION_OPT 301#define CLICKPATH_OPT 302#define ROUTER_OPT 303#define EXPRESSION_OPT 304#define OUTPUT_OPT 305#define CLASS_URLS_OPT 306#define TEMPLATE_OPT 307#define WRITE_TEMPLATE_OPT 308#define DEFINE_OPT 309#define PACKAGE_URLS_OPT 310#define FIRST_DRIVER_OPT 1000#define USERLEVEL_OPT (1000 + Driver::USERLEVEL)#define LINUXMODULE_OPT (1000 + Driver::LINUXMODULE)#define BSDMODULE_OPT (1000 + Driver::BSDMODULE)static Clp_Option options[] = { { "bsdmodule", 'b', BSDMODULE_OPT, 0, 0 }, { "clickpath", 'C', CLICKPATH_OPT, Clp_ArgString, 0 }, { "class-docs", 'u', CLASS_URLS_OPT, Clp_ArgString, 0 }, { "define", 'd', DEFINE_OPT, Clp_ArgString, 0 }, { "expression", 'e', EXPRESSION_OPT, Clp_ArgString, 0 }, { "file", 'f', ROUTER_OPT, Clp_ArgString, 0 }, { "help", 0, HELP_OPT, 0, 0 }, { "kernel", 'k', LINUXMODULE_OPT, 0, 0 }, { "linuxmodule", 'l', LINUXMODULE_OPT, 0, 0 }, { "output", 'o', OUTPUT_OPT, Clp_ArgString, 0 }, { "package-docs", 0, PACKAGE_URLS_OPT, Clp_ArgString, 0 }, { "template", 't', TEMPLATE_OPT, Clp_ArgString, 0 }, { "userlevel", 0, USERLEVEL_OPT, 0, 0 }, { "version", 'v', VERSION_OPT, 0, 0 }, { "write-template", 0, WRITE_TEMPLATE_OPT, 0, Clp_Negate },};static String::Initializer string_initializer;static const char *program_name;static HashMap<String, String> definitions;static int specified_driver = -1;static const char *default_template = "\<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n\<html><head>\n\<meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'>\n\<meta http-equiv='Content-Style-Type' content='text/css'>\n\<style type='text/css'><!--\n\SPAN.c-kw {\n\ font-weight: bold;\n\}\n\SPAN.c-cd {\n\ font-style: italic;\n\}\n\SPAN.c-cfg {\n\ color: green;\n\}\n\SPAN.c-cmt {\n\ color: gray;\n\}\n\SPAN.c-err {\n\ color: red;\n\ font-weight: bold;\n\}\n\SPAN.c-err:hover {\n\ color: black;\n\ font-weight: bold;\n\ background-color: #000;\n\}\n\P.ei, P.eit {\n\ margin-top: 0px;\n\ margin-bottom: 0px;\n\ text-indent: -2em;\n\ margin-left: 2em;\n\ font-family: sans-serif;\n\}\n\P.et {\n\ font-family: sans-serif;\n\}\n\TABLE.conntable TR TD {\n\ font-family: sans-serif;\n\ font-size: small;\n\}\n\--></style>\n\<body>\n\<h1>Configuration</h1>\n\<~config>\n\<h1><a name='index'>Element index</a></h1>\n\<table cellspacing='0' cellpadding='0' border='0'>\n\<tr valign='top'>\n\<td><~elements\n\ entry='<p class=\"ei\"><b><~name></b> :: <~type link> - <~configlink sep=\", \"><a href=\"#et-<~name>\"><i>table</i></a></p>'\n\ typeentry='<p class=\"eit\"><b><~type link></b> (type)<br><i>see</i> <~typerefs sep=\", \"></p>'\n\ typeref='<~name>'\n\ configlink='<i>config</i>'\n\ column='1/2' /--></td>\n\<td width='15'> </td>\n\<td><~elements\n\ entry='<p class=\"ei\"><b><~name></b> :: <~type link> - <~configlink sep=\", \"><a href=\"#et-<~name>\"><i>table</i></a></p>'\n\ typeentry='<p class=\"eit\"><b><~type link></b> (type)<br><i>see</i> <~typerefs sep=\", \"></p>'\n\ typeref='<~name>'\n\ configlink='<i>config</i>'\n\ column='2/2' /--></td>\n\</tr>\n\</table>\n\<h1><a name='tables'>Element tables</a></h1>\n\<table cellspacing='0' cellpadding='0' border='0'>\n\<tr valign='top'>\n\<td><~elements\n\ entry='<table cellspacing=\"0\" cellpadding=\"2\" border=\"0\">\n\ <tr valign=\"top\"><td colspan=\"2\"><p class=\"et\"><a name=\"et-<~name>\"><b><~name></b></a> :: <~type link> <~configlink></p></td></tr>\n\ <tr valign=\"top\"><td width=\"20\"> </td>\n\ <td><table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"conntable\">\n\ <~inputs><~outputs>\n\ </table></td></tr>\n\ </table>'\n\ configlink='<small>(<i>config</i>)</small>'\n\ inputentry='<tr valign=\"top\"><td>input </td><td align=\"right\"><~port></td><td align=\"center\"> (<~processing>)</td><td> <- </td><td><~inputconnections sep=\", \"></td></tr>'\n\ noinputentry='<tr valign=\"top\"><td colspan=\"5\">no inputs</td></tr>'\n\ outputentry='<tr valign=\"top\"><td>output </td><td align=\"right\"><~port></td><td align=\"center\"> (<~processing>)</td><td> -> </td><td><~outputconnections sep=\", \"></td></tr>'\n\ nooutputentry='<tr valign=\"top\"><td colspan=\"5\">no outputs</td></tr>'\n\ inputconnection='<a href=\"#et-<~name>\"><~name></a> [<~port>]'\n\ outputconnection='[<~port>] <a href=\"#et-<~name>\"><~name></a>'\n\ noinputconnection='not connected'\n\ nooutputconnection='not connected'\n\ column='1/2'\n\ /-->\n\</td><td width='20'> </td>\n\<td><~elements\n\ entry='<table cellspacing=\"0\" cellpadding=\"2\" border=\"0\">\n\ <tr valign=\"top\"><td colspan=\"2\"><p class=\"et\"><a name=\"et-<~name>\"><b><~name></b></a> :: <~type link> <~configlink></p></td></tr>\n\ <tr valign=\"top\"><td width=\"20\"> </td>\n\ <td><table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"conntable\">\n\ <~inputs><~outputs>\n\ </table></td></tr>\n\ </table>'\n\ configlink='<small>(<i>config</i>)</small>'\n\ inputentry='<tr valign=\"top\"><td>input </td><td align=\"right\"><~port></td><td align=\"center\"> (<~processing>)</td><td> <- </td><td><~inputconnections sep=\", \"></td></tr>'\n\ noinputentry='<tr valign=\"top\"><td colspan=\"5\">no inputs</td></tr>'\n\ outputentry='<tr valign=\"top\"><td>output </td><td align=\"right\"><~port></td><td align=\"center\"> (<~processing>)</td><td> -> </td><td><~outputconnections sep=\", \"></td></tr>'\n\ nooutputentry='<tr valign=\"top\"><td colspan=\"5\">no outputs</td></tr>'\n\ inputconnection='<a href=\"#et-<~name>\"><~name></a> [<~port>]'\n\ outputconnection='[<~port>] <a href=\"#et-<~name>\"><~name></a>'\n\ noinputconnection='not connected'\n\ nooutputconnection='not connected'\n\ column='2/2'\n\ /-->\n\</td></tr>\n\</table>\n\</body>\n\</html>\n";// list of classesstatic HashMap<ElementClassT *, int> class2cid(-1);static Vector<ElementClassT *> cid2class;static Vector<String> cid_hrefs;static HashMap<String, String> package_hrefs;static intcid(ElementClassT *type){ int *cidp = class2cid.findp_force(type, -1); if (*cidp < 0) { *cidp = cid2class.size(); cid2class.push_back(type); cid_hrefs.push_back(String()); } return *cidp;}static voidadd_class_href(ElementClassT *type, const String &href){ cid_hrefs[cid(type)] = href;}static Stringclass_href(ElementClassT *type){ String &sp = cid_hrefs[cid(type)]; if (sp) return sp; else if (String href = type->documentation_url()) { add_class_href(type, href); return href; } else if (String doc_name = type->documentation_name()) { String package_href = package_hrefs["x" + type->package()]; if (!package_href) package_href = package_hrefs["x"]; String href = percent_substitute(package_href, 's', doc_name.cc(), 0); add_class_href(type, href); return href; } else { add_class_href(type, String()); return String(); }}// handle output itemsstruct OutputItem { int pos; String text; int _other; bool active : 1; bool _end_item : 1; OutputItem() : pos(-1), _other(-1), active(0), _end_item(0) { } OutputItem(int p, const String &t, bool ei) : pos(p), text(t), _other(-1), active(0), _end_item(ei) { } bool end_item() const { return _end_item; } OutputItem *other() const; int other_index() const { return _other; } int item_index() const; int end_item_index() const; void activate(bool a);};static Vector<OutputItem> items;static Vector<OutputItem> end_items;static bool items_prepared;inline OutputItem *OutputItem::other() const{ if (_other < 0) return 0; else if (_end_item) return &items[_other]; else return &end_items[_other];}inline intOutputItem::item_index() const{ if (_end_item) return other_index(); else return other()->other_index();}inline intOutputItem::end_item_index() const{ if (_end_item) return other()->other_index(); else return other_index();}inline voidOutputItem::activate(bool a){ active = other()->active = a;}static voidadd_item(int p1, const String &t1, int p2, const String &t2){ items.push_back(OutputItem(p1, t1, false)); end_items.push_back(OutputItem(p2, t2, true)); items.back()._other = end_items.back()._other = items.size() - 1;}extern "C" {static OutputItem *compar_items;static intitem_compar(const void *v1, const void *v2){ const OutputItem &oi1 = compar_items[*((const int *)v1)]; const OutputItem &oi2 = compar_items[*((const int *)v2)]; int diff = oi1.pos - oi2.pos; if (diff != 0) return diff; else if (oi1.end_item()) // Sort end items in reverse order from corresponding start items. return oi2.other_index() - oi1.other_index(); else return oi2.other()->pos - oi1.other()->pos;}}static voidprepare_items(int last_pos){ if (items_prepared) return; items_prepared = true; add_item(last_pos + 1, "", last_pos + 1, ""); assert(items.size() == end_items.size()); // sort items for (int which = 0; which < 2; which++) { compar_items = (which == 0 ? &items[0] : &end_items[0]); Vector<int> permute; for (int i = 0; i < items.size(); i++) permute.push_back(i); qsort(&permute[0], items.size(), sizeof(int), item_compar); Vector<int> rev_permute(items.size(), -1); for (int i = 0; i < items.size(); i++) rev_permute[permute[i]] = i; OutputItem *other_items = (which == 0 ? &end_items[0] : &items[0]); for (int i = 0; i < items.size(); i++) other_items[i]._other = rev_permute[other_items[i]._other]; Vector<OutputItem> new_items(which == 0 ? items : end_items); for (int i = 0; i < items.size(); i++) compar_items[i] = new_items[permute[i]]; } // update class references for (int i = 0; i < items.size(); i++) { OutputItem *s = &items[i], *e = s->other(); if (s->text[0] == '{') { int cid; cp_integer(s->text.substring(1), &cid); if (String href = class_href(cid2class[cid])) { s->text = "<a href='" + href + "'>"; e->text = "</a>"; } else s->text = ""; } } // combine items that need to be combined (<a href> and <a name>) for (int i = 0; i < items.size() - 1; i++) { OutputItem *s1 = &items[i], *e1 = s1->other(); OutputItem *s2 = &items[i+1], *e2 = s2->other(); if (s1->pos != s2->pos || e1->pos != e2->pos) continue; if (s1->text == s2->text && e1->text == e2->text) s2->text = e2->text = ""; else if (s1->text.substring(0, 3) == "<a " && s2->text.substring(0, 3) == "<a ") { s1->text = s1->text.substring(0, s1->text.length() - 1) + " " + s2->text.substring(3); s2->text = e2->text = ""; } }}static Stringlink_class_decl(ElementClassT *type){ return "decl" + String(cid(type));}static Stringlink_element_decl(ElementT *e){ if (e->router()->declaration_scope()) return "e" + String(cid(e->router())) + "-" + e->name(); else return "e-" + e->name();}class PrettyLexerTInfo : public LexerTInfo { public: PrettyLexerTInfo() { } void notify_comment(int pos1, int pos2) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -