📄 click-pretty.cc
字号:
String _config;};voidshort_usage(){ fprintf(stderr, "Usage: %s [OPTION]... [ROUTERFILE]\n\Try '%s --help' for more information.\n", program_name, program_name);}static RouterT *pretty_read_router(const char *filename, bool file_is_expr, ErrorHandler *errh, String &config){ // This function is a paraphrase of read_router_file. // read file string int before_nerrors = errh->nerrors(); if (file_is_expr) config = filename; else config = file_string(filename, errh); if (!config && errh->nerrors() != before_nerrors) return 0; // set readable filename if (file_is_expr) filename = "config"; else if (!filename || strcmp(filename, "-") == 0) filename = "<stdin>"; // check for archive Vector<ArchiveElement> archive; if (config.length() && config[0] == '!') { ArchiveElement::parse(config, archive, errh); if (ArchiveElement *ae = ArchiveElement::find(archive, "config")) config = ae->data; else { errh->error("%s: archive has no %<config%> section", filename); config = String(); } } // clear list of items items.clear(); end_items.clear(); items_prepared = false; // read router if (!config.length()) errh->warning("%s: empty configuration", filename); LexerT lexer(ErrorHandler::silent_handler(), false); PrettyLexerTInfo pinfo(config); lexer.reset(config, archive, filename); lexer.set_lexinfo(&pinfo); // read statements while (lexer.ystatement()) /* nada */; // done return lexer.finish(global_scope);}static voidactivate(OutputItem &item, int &first_active){ item.activate(true); int iitem = item.item_index(); if (iitem < first_active) first_active = iitem;}static voiddeactivate(OutputItem &item, int &first_active, int ipos){ item.activate(false); int iitem = item.item_index(); if (iitem == first_active) { for (first_active++; first_active < ipos && !items[first_active].active; first_active++) /* nada */; if (first_active >= ipos) first_active = items.size(); }}static voidoutput_config(String r_config, FILE *outf){ // create two sorted lists of objects // add sentinel item, sort item lists if (!items_prepared) prepare_items(r_config.length()); // loop over characters const char *data = r_config.c_str(); int len = r_config.length(); int ipos = 0, eipos = 0; int first_active = items.size(); fputs("<pre>", outf); for (int pos = 0; pos < len; pos++) { while (items[ipos].pos <= pos || end_items[eipos].pos <= pos) if (end_items[eipos].pos <= items[ipos].pos) { if (end_items[eipos].active) fputs(end_items[eipos].text.c_str(), outf); deactivate(end_items[eipos], first_active, ipos); eipos++; } else { fputs(items[ipos].text.c_str(), outf); activate(items[ipos], first_active); ipos++; } switch (data[pos]) { case '\n': case '\r': for (int i = ipos - 1; i >= first_active; i--) if (items[i].active) fputs(items[i].other()->text.c_str(), outf); fputc('\n', outf); if (data[pos] == '\r' && pos < len - 1 && data[pos+1] == '\n') pos++; for (int i = first_active; i < ipos; i++) if (items[i].active) { if (items[i].other()->pos <= pos + 1) items[i].activate(false); else fputs(items[i].text.c_str(), outf); } break; case '<': fputs("<", outf); break; case '>': fputs(">", outf); break; case '&': fputs("&", outf); break; default: fputc(data[pos], outf); break; } } fputs("</pre>\n", outf);}static boolparse_columns(const String &s, int &which, int &count){ const char *slash = find(s, '/'); if (!cp_integer(s.substring(s.begin(), slash), &which) || !cp_integer(s.substring(slash + 1, s.end()), &count) || which <= 0 || which > count) { which = count = 1; return false; } else return true;}extern "C" {static const Vector<ConnectionT> *conn_compar_connvec;static bool conn_compar_from;static intconn_compar(const void *v1, const void *v2){ const int *i1 = (const int *)v1, *i2 = (const int *)v2; const ConnectionT &c1 = (*conn_compar_connvec)[*i1]; const ConnectionT &c2 = (*conn_compar_connvec)[*i2]; const PortT &p1 = (conn_compar_from ? c1.from() : c1.to()); const PortT &p2 = (conn_compar_from ? c2.from() : c2.to()); if (p1.element == p2.element) return p1.port - p2.port; else return click_strcmp(p1.element->name(), p2.element->name());}static intelement_name_compar(const void *v1, const void *v2){ const ElementT **e1 = (const ElementT **)v1, **e2 = (const ElementT **)v2; return click_strcmp((*e1)->name(), (*e2)->name());}}static voidsort_connections(RouterT *r, Vector<int> &conn, bool from){ conn_compar_connvec = &r->connections(); conn_compar_from = from; if (conn.size()) qsort(&conn[0], conn.size(), sizeof(int), conn_compar);}//// elements//static String type_landmark = "$fake_type$";class ElementsOutput { public: ElementsOutput(RouterT *, const ProcessingT &, const HashTable<String, String> &); ~ElementsOutput(); void run(ElementT *, FILE *); void run(FILE *); private: RouterT *_router; const ProcessingT &_processing; const HashTable<String, String> &_main_attrs; Vector<ElementT *> _entries; Vector<ElementT *> _elements; StringAccum _sa; String _sep; void run_template(String, ElementT *, int, bool); String expand(const String &, ElementT *, int, bool);};ElementsOutput::ElementsOutput(RouterT *r, const ProcessingT &processing, const HashTable<String, String> &main_attrs) : _router(r), _processing(processing), _main_attrs(main_attrs){ bool do_elements = main_attrs["entry"]; bool do_types = main_attrs["typeentry"]; // get list of elements and/or types HashTable<ElementClassT *, int> done_types(-1); for (RouterT::iterator x = r->begin_elements(); x; x++) { _elements.push_back(x); if (do_elements) _entries.push_back(x); if (do_types && done_types[x->type()] < 0) { ElementT *fake = new ElementT(x->type_name(), x->type(), "", LandmarkT(type_landmark)); _entries.push_back(fake); done_types.set(x->type(), 1); } } // sort by name if (_elements.size()) qsort(&_elements[0], _elements.size(), sizeof(ElementT *), element_name_compar); if (_entries.size()) qsort(&_entries[0], _entries.size(), sizeof(ElementT *), element_name_compar);}ElementsOutput::~ElementsOutput(){ for (int i = 0; i < _entries.size(); i++) if (_entries[i]->landmark() == type_landmark) delete _entries[i];}voidElementsOutput::run_template(String templ_str, ElementT *e, int port, bool is_output){ ElementClassT *t = e->type(); bool is_type = (e->landmark() == type_landmark); String tag; HashTable<String, String> attrs; const char *templ = templ_str.c_str(); while (templ) { templ = output_template_until_tag(templ, _sa, tag, attrs, true, &_sep); String next_sep; int pre_expansion_pos = _sa.length(); if (tag == "name") { String href, link = attrs["link"].lower(); if (link == "type" || (is_type && link)) href = class_href(t); else if (link) href = link_element_decl(e); if (href) _sa << _sep << "<a href='" << href << "'>" << e->name() << "</a>"; else _sa << _sep << e->name(); } else if (tag == "type") { String href = (attrs["link"] ? class_href(t) : String()); if (href) _sa << _sep << "<a href='" << href << "'>" << t->name() << "</a>"; else _sa << _sep << t->name(); } else if (tag == "config" && !is_type) { int limit = 0; if (attrs["limit"]) cp_integer(html_unquote(attrs["limit"]), &limit); String config = e->configuration(); if (limit && config.length() > limit) config = config.substring(0, limit) + "..."; if (config && attrs["parens"]) _sa << _sep << '(' << html_quote_text(config) << ')'; else if (config) _sa << _sep << html_quote_text(config); } else if (tag == "typerefs") { String subsep = attrs["sep"]; String text = attrs["entry"]; if (!text) text = _main_attrs["typeref"]; for (int i = 0; i < _elements.size(); i++) if (_elements[i]->type() == t) { run_template(text, _elements[i], -1, false); _sep = subsep; } } else if (tag == "configlink" && !is_type) { String text = attrs["text"]; if (!text) text = _main_attrs["configlink"]; if (text) { text = "<a href='#" + link_element_decl(e) + "'>" + text + "</a>"; run_template(text, e, port, is_output); next_sep = attrs["sep"]; } } else if (tag == "ninputs" && !is_type) { _sa << _sep << e->ninputs(); if (attrs["english"]) _sa << (e->ninputs() == 1 ? " input" : " inputs"); } else if (tag == "noutputs" && !is_type) { _sa << _sep << e->noutputs(); if (attrs["english"]) _sa << (e->noutputs() == 1 ? " output" : " outputs"); } else if (tag == "inputs" && !is_type) { if (e->ninputs() == 0) { String text = attrs["noentry"]; if (!text) text = _main_attrs["noinputentry"]; run_template(text, e, -1, false); } else { String subsep = attrs["sep"]; String text = attrs["entry"]; if (!text) text = _main_attrs["inputentry"]; for (int i = 0; i < e->ninputs(); i++) { run_template(text, e, i, false); _sep = subsep; } } } else if (tag == "outputs" && !is_type) { if (e->noutputs() == 0) { String text = attrs["noentry"]; if (!text) text = _main_attrs["nooutputentry"]; run_template(text, e, -1, true); } else { String subsep = attrs["sep"]; String text = attrs["entry"]; if (!text) text = _main_attrs["outputentry"]; for (int i = 0; i < e->noutputs(); i++) { run_template(text, e, i, true); _sep = subsep; } } } else if (tag == "inputconnections" && port >= 0 && !is_output) { Vector<int> conn; _router->find_connections_to(PortT(e, port), conn); if (conn.size() == 0) { String text = attrs["noentry"]; if (!text) text = _main_attrs["noinputconnection"]; run_template(text, e, port, false); } else { sort_connections(_router, conn, true); String subsep = attrs["sep"]; String text = attrs["entry"]; if (!text) text = _main_attrs["inputconnection"]; for (int i = 0; i < conn.size(); i++) { const ConnectionT &c = _router->connection(conn[i]); run_template(text, c.from_element(), c.from_port(), true); _sep = subsep; } } } else if (tag == "outputconnections" && port >= 0 && is_output) { Vector<int> conn; _router->find_connections_from(PortT(e, port), conn); if (conn.size() == 0) { String text = attrs["noentry"]; if (!text) text = _main_attrs["nooutputconnection"]; run_template(text, e, port, true); } else { sort_connections(_router, conn, false); String subsep = attrs["sep"]; String text = attrs["entry"]; if (!text) text = _main_attrs["outputconnection"]; for (int i = 0; i < conn.size(); i++) { const ConnectionT &c = _router->connection(conn[i]); run_template(text, c.to_element(), c.to_port(), false); _sep = subsep; } } } else if (tag == "port" && port >= 0) { _sa << _sep << port; } else if (tag == "processing" && port >= 0) { int p = (is_output ? _processing.output_processing(PortT(e, port)) : _processing.input_processing(PortT(e, port))); if (p == ProcessingT::pagnostic) _sa << _sep << "agnostic"; else if (p & ProcessingT::ppush) _sa << _sep << "push"; else if (p & ProcessingT::ppull) _sa << _sep << "pull"; else _sa << _sep << "??"; } else if (tag == "processingcode") { _sa << _sep << t->processing_code(); } else if (tag == "flowcode") { _sa << _sep << e->flow_code(); } else if (tag == "if") { String s = expand(attrs["test"], e, port, is_output); bool result; if (String v = attrs.get("eq")) result = (expand(v, e, port, is_output) == s); else if (String v = attrs.get("ne")) result = (expand(v, e, port, is_output) != s); else if (String v = attrs.get("gt")) result = (click_strcmp(s, expand(v, e, port, is_output)) > 0); else if (String v = attrs.get("lt")) result = (click_strcmp(s, expand(v, e, port, is_output)) < 0); else if (String v = attrs.get("ge")) result = (click_strcmp(s, expand(v, e, port, is_output)) >= 0); else if (String v = attrs.get("le")) result = (click_strcmp(s, expand(v, e, port, is_output)) <= 0); else result = (s.length() > 0); if (result) run_template(attrs["then"], e, port, is_output); else run_template(attrs["else"], e, port, is_output); } else if (_main_attrs[tag]) { String text = attrs[tag]; run_template(text, e, port, is_output); } else if (definitions[tag]) { String text = definitions[tag]; run_template(text, e, port, is_output); } if (_sa.length() != pre_expansion_pos) _sep = next_sep; }}StringElementsOutput::expand(const String &s, ElementT *e, int port, bool is_output){ int pos = _sa.length(); run_template(s, e, port, is_output);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -