/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_generator.h" #include "thrift/generate/t_html_generator.h" using std::map; using std::ofstream; using std::ostringstream; using std::pair; using std::string; using std::stringstream; using std::vector; enum input_type { INPUT_UNKNOWN, INPUT_UTF8, INPUT_PLAIN }; /** * HTML code generator * * mostly copy/pasting/tweaking from mcslee's work. */ class t_html_generator : public t_generator { public: t_html_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; standalone_ = false; unsafe_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("standalone") == 0) { standalone_ = true; } else if( iter->first.compare("noescape") == 0) { unsafe_ = true; } else { throw "unknown option html:" + iter->first; } } out_dir_base_ = "gen-html"; input_type_ = INPUT_UNKNOWN; escape_.clear(); escape_['&'] = "&"; escape_['<'] = "<"; escape_['>'] = ">"; escape_['"'] = """; escape_['\''] = "'"; init_allowed__markup(); } std::string display_name() const override; void generate_program() override; void generate_program_toc(); void generate_program_toc_row(t_program* tprog); void generate_program_toc_rows(t_program* tprog, std::vector& finished); void generate_index(); std::string escape_html(std::string const& str); std::string escape_html_tags(std::string const& str); void generate_css(); void generate_css_content(std::ostream& f_target); void generate_style_tag(); std::string make_file_link(std::string name); bool is_utf8_sequence(std::string const& str, size_t firstpos); void detect_input_encoding(std::string const& str, size_t firstpos); void init_allowed__markup(); /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_service(t_service* tservice) override; void generate_xception(t_struct* txception) override; void print_doc(t_doc* tdoc); int print_type(t_type* ttype); void print_const_value(t_type* type, t_const_value* tvalue); void print_fn_args_doc(t_function* tfunction); private: ofstream_with_content_based_conditional_update f_out_; std::string current_file_; input_type input_type_; std::map allowed_markup; bool standalone_; bool unsafe_; }; /** * Emits the Table of Contents links at the top of the module's page */ void t_html_generator::generate_program_toc() { f_out_ << "" << "" << '\n'; generate_program_toc_row(program_); f_out_ << "
ModuleServicesData typesConstants
" << '\n'; } /** * Recurses through from the provided program and generates a ToC row * for each discovered program exactly once by maintaining the list of * completed rows in 'finished' */ void t_html_generator::generate_program_toc_rows(t_program* tprog, std::vector& finished) { for (auto & iter : finished) { if (tprog->get_path() == iter->get_path()) { return; } } finished.push_back(tprog); generate_program_toc_row(tprog); vector includes = tprog->get_includes(); for (auto & include : includes) { generate_program_toc_rows(include, finished); } } /** * Emits the Table of Contents links at the top of the module's page */ void t_html_generator::generate_program_toc_row(t_program* tprog) { string fname = tprog->get_name() + ".html"; f_out_ << "" << '\n' << "" << tprog->get_name() << ""; if (!tprog->get_services().empty()) { vector services = tprog->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { string name = get_service_name(*sv_iter); f_out_ << "" << name << "
" << '\n'; f_out_ << "
    " << '\n'; map fn_html; vector functions = (*sv_iter)->get_functions(); vector::iterator fn_iter; for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { string fn_name = (*fn_iter)->get_name(); string html = "
  • " + fn_name + "
  • "; fn_html.insert(pair(fn_name, html)); } for (auto & html_iter : fn_html) { f_out_ << html_iter.second << '\n'; } f_out_ << "
" << '\n'; } } f_out_ << "" << '\n' << ""; map data_types; if (!tprog->get_enums().empty()) { vector enums = tprog->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { string name = (*en_iter)->get_name(); // f_out_ << "" << name // << "
" << '\n'; string html = "" + name + ""; data_types.insert(pair(name, html)); } } if (!tprog->get_typedefs().empty()) { vector typedefs = tprog->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { string name = (*td_iter)->get_symbolic(); // f_out_ << "" << name // << "
" << '\n'; string html = "" + name + ""; data_types.insert(pair(name, html)); } } if (!tprog->get_objects().empty()) { vector objects = tprog->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { string name = (*o_iter)->get_name(); // f_out_ << "" << name //<< "
" << '\n'; string html = "" + name + ""; data_types.insert(pair(name, html)); } } for (auto & data_type : data_types) { f_out_ << data_type.second << "
" << '\n'; } f_out_ << "" << '\n' << ""; if (!tprog->get_consts().empty()) { map const_html; vector consts = tprog->get_consts(); vector::iterator con_iter; for (con_iter = consts.begin(); con_iter != consts.end(); ++con_iter) { string name = (*con_iter)->get_name(); string html = "" + name + ""; const_html.insert(pair(name, html)); } for (auto & con_iter : const_html) { f_out_ << con_iter.second << "
" << '\n'; } } f_out_ << "" << '\n' << ""; } /** * Prepares for file generation by opening up the necessary file output * stream. */ void t_html_generator::generate_program() { // Make output directory MKDIR(get_out_dir().c_str()); current_file_ = program_->get_name() + ".html"; string fname = get_out_dir() + current_file_; f_out_.open(fname.c_str()); f_out_ << "" << '\n'; f_out_ << "" << '\n'; f_out_ << "" << '\n'; f_out_ << "" << '\n'; generate_style_tag(); f_out_ << "Thrift module: " << program_->get_name() << "" << '\n' << "
" << '\n' << "

Thrift module: " << program_->get_name() << "

" << '\n'; print_doc(program_); generate_program_toc(); if (!program_->get_consts().empty()) { f_out_ << "

Constants

" << '\n'; vector consts = program_->get_consts(); f_out_ << ""; f_out_ << "" << '\n'; generate_consts(consts); f_out_ << "
ConstantTypeValue
"; } if (!program_->get_enums().empty()) { f_out_ << "

Enumerations

" << '\n'; // Generate enums vector enums = program_->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { generate_enum(*en_iter); } } if (!program_->get_typedefs().empty()) { f_out_ << "

Type declarations

" << '\n'; // Generate typedefs vector typedefs = program_->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { generate_typedef(*td_iter); } } if (!program_->get_objects().empty()) { f_out_ << "

Data structures

" << '\n'; // Generate structs and exceptions in declared order vector objects = program_->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { if ((*o_iter)->is_xception()) { generate_xception(*o_iter); } else { generate_struct(*o_iter); } } } if (!program_->get_services().empty()) { f_out_ << "

Services

" << '\n'; // Generate services vector services = program_->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { service_name_ = get_service_name(*sv_iter); generate_service(*sv_iter); } } f_out_ << "
" << '\n'; f_out_.close(); generate_index(); generate_css(); } /** * Emits the index.html file for the recursive set of Thrift programs */ void t_html_generator::generate_index() { current_file_ = "index.html"; string index_fname = get_out_dir() + current_file_; f_out_.open(index_fname.c_str()); f_out_ << "" << '\n' << "" << '\n'; generate_style_tag(); f_out_ << "All Thrift declarations" << '\n' << "
" << '\n' << "

All Thrift declarations

" << '\n'; f_out_ << "" << "" << '\n'; vector programs; generate_program_toc_rows(program_, programs); f_out_ << "
ModuleServicesData typesConstants
" << '\n'; f_out_ << "
" << '\n'; f_out_.close(); } void t_html_generator::generate_css() { if (!standalone_) { current_file_ = "style.css"; string css_fname = get_out_dir() + current_file_; f_out_.open(css_fname.c_str()); generate_css_content(f_out_); f_out_.close(); } } void t_html_generator::generate_css_content(std::ostream& f_target) { f_target << BOOTSTRAP_CSS() << '\n'; f_target << "/* Auto-generated CSS for generated Thrift docs */" << '\n'; f_target << "h3, h4 { margin-bottom: 6px; }" << '\n'; f_target << "div.definition { border: 1px solid #CCC; margin-bottom: 10px; padding: 10px; }" << '\n'; f_target << "div.extends { margin: -0.5em 0 1em 5em }" << '\n'; f_target << "td { vertical-align: top; }" << '\n'; f_target << "table { empty-cells: show; }" << '\n'; f_target << "code { line-height: 20px; }" << '\n'; f_target << ".table-bordered th, .table-bordered td { border-bottom: 1px solid #DDDDDD; }" << '\n'; } /** * Generates the CSS tag. * Depending on "standalone", either a CSS file link (default), or the entire CSS is embedded * inline. */ void t_html_generator::generate_style_tag() { if (!standalone_) { f_out_ << "" << '\n'; } else { f_out_ << "" << '\n'; } } /** * Returns the target file for a link * The returned string is empty, whenever filename refers to the current file. */ std::string t_html_generator::make_file_link(std::string filename) { return (current_file_.compare(filename) != 0) ? filename : ""; } /** * If the provided documentable object has documentation attached, this * will emit it to the output stream in HTML format. */ void t_html_generator::print_doc(t_doc* tdoc) { if (tdoc->has_doc()) { if (unsafe_) { f_out_ << tdoc->get_doc() << "
"; } else { f_out_ << "
" << escape_html(tdoc->get_doc()) << "

"; } } } bool t_html_generator::is_utf8_sequence(std::string const& str, size_t firstpos) { // leading char determines the length of the sequence unsigned char c = str.at(firstpos); int count = 0; if ((c & 0xE0) == 0xC0) { count = 1; } else if ((c & 0xF0) == 0xE0) { count = 2; } else if ((c & 0xF8) == 0xF0) { count = 3; } else if ((c & 0xFC) == 0xF8) { count = 4; } else if ((c & 0xFE) == 0xFC) { count = 5; } else { // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 leading byte", c, int(c)); return false; // no UTF-8 } // following chars size_t pos = firstpos + 1; while ((pos < str.length()) && (0 < count)) { c = str.at(pos); if ((c & 0xC0) != 0x80) { // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 following byte", c, int(c)); return false; // no UTF-8 } --count; ++pos; } // true if the sequence is complete return (0 == count); } void t_html_generator::detect_input_encoding(std::string const& str, size_t firstpos) { if (is_utf8_sequence(str, firstpos)) { pdebug("Input seems to be already UTF-8 encoded"); input_type_ = INPUT_UTF8; return; } // fallback pwarning(1, "Input is not UTF-8, treating as plain ANSI"); input_type_ = INPUT_PLAIN; } void t_html_generator::init_allowed__markup() { allowed_markup.clear(); // standalone tags allowed_markup["br"] = 1; allowed_markup["br/"] = 1; allowed_markup["img"] = 1; // paired tags allowed_markup["b"] = 1; allowed_markup["/b"] = 1; allowed_markup["u"] = 1; allowed_markup["/u"] = 1; allowed_markup["i"] = 1; allowed_markup["/i"] = 1; allowed_markup["s"] = 1; allowed_markup["/s"] = 1; allowed_markup["big"] = 1; allowed_markup["/big"] = 1; allowed_markup["small"] = 1; allowed_markup["/small"] = 1; allowed_markup["sup"] = 1; allowed_markup["/sup"] = 1; allowed_markup["sub"] = 1; allowed_markup["/sub"] = 1; allowed_markup["pre"] = 1; allowed_markup["/pre"] = 1; allowed_markup["tt"] = 1; allowed_markup["/tt"] = 1; allowed_markup["ul"] = 1; allowed_markup["/ul"] = 1; allowed_markup["ol"] = 1; allowed_markup["/ol"] = 1; allowed_markup["li"] = 1; allowed_markup["/li"] = 1; allowed_markup["a"] = 1; allowed_markup["/a"] = 1; allowed_markup["p"] = 1; allowed_markup["/p"] = 1; allowed_markup["code"] = 1; allowed_markup["/code"] = 1; allowed_markup["dl"] = 1; allowed_markup["/dl"] = 1; allowed_markup["dt"] = 1; allowed_markup["/dt"] = 1; allowed_markup["dd"] = 1; allowed_markup["/dd"] = 1; allowed_markup["h1"] = 1; allowed_markup["/h1"] = 1; allowed_markup["h2"] = 1; allowed_markup["/h2"] = 1; allowed_markup["h3"] = 1; allowed_markup["/h3"] = 1; allowed_markup["h4"] = 1; allowed_markup["/h4"] = 1; allowed_markup["h5"] = 1; allowed_markup["/h5"] = 1; allowed_markup["h6"] = 1; allowed_markup["/h6"] = 1; } std::string t_html_generator::escape_html_tags(std::string const& str) { std::ostringstream result; unsigned char c = '?'; size_t lastpos; size_t firstpos = 0; while (firstpos < str.length()) { // look for non-ASCII char lastpos = firstpos; while (lastpos < str.length()) { c = str.at(lastpos); if (('<' == c) || ('>' == c)) { break; } ++lastpos; } // copy what we got so far if (lastpos > firstpos) { result << str.substr(firstpos, lastpos - firstpos); firstpos = lastpos; } // reached the end? if (firstpos >= str.length()) { break; } // tag end without corresponding begin ++firstpos; if ('>' == c) { result << ">"; continue; } // extract the tag std::ostringstream tagstream; while (firstpos < str.length()) { c = str.at(firstpos); ++firstpos; if ('<' == c) { tagstream << "<"; // nested begin? } else if ('>' == c) { break; } else { tagstream << c; // not very efficient, but tags should be quite short } } // we allow for several markup in docstrings, all else will become escaped string tag_content = tagstream.str(); string tag_key = tag_content; size_t first_white = tag_key.find_first_of(" \t\f\v\n\r"); if (first_white != string::npos) { tag_key.erase(first_white); } for (char & i : tag_key) { i = tolower(i); } if (allowed_markup.find(tag_key) != allowed_markup.end()) { result << "<" << tag_content << ">"; } else { result << "<" << tagstream.str() << ">"; pverbose("illegal markup <%s> in doc-comment\n", tag_key.c_str()); } } return result.str(); } std::string t_html_generator::escape_html(std::string const& str) { // the generated HTML header says it is UTF-8 encoded // if UTF-8 input has been detected before, we don't need to change anything if (input_type_ == INPUT_UTF8) { return escape_html_tags(str); } // convert unsafe chars to their &#; equivalent std::ostringstream result; unsigned char c = '?'; unsigned int ic = 0; size_t lastpos; size_t firstpos = 0; while (firstpos < str.length()) { // look for non-ASCII char lastpos = firstpos; while (lastpos < str.length()) { c = str.at(lastpos); ic = c; if ((32 > ic) || (127 < ic)) { break; } ++lastpos; } // copy what we got so far if (lastpos > firstpos) { result << str.substr(firstpos, lastpos - firstpos); firstpos = lastpos; } // reached the end? if (firstpos >= str.length()) { break; } // some control code? if (ic <= 31) { switch (c) { case '\r': case '\n': case '\t': result << c; break; default: // silently consume all other ctrl chars break; } ++firstpos; continue; } // reached the end? if (firstpos >= str.length()) { break; } // try to detect input encoding if (input_type_ == INPUT_UNKNOWN) { detect_input_encoding(str, firstpos); if (input_type_ == INPUT_UTF8) { lastpos = str.length(); result << str.substr(firstpos, lastpos - firstpos); break; } } // convert the character to something useful based on the detected encoding switch (input_type_) { case INPUT_PLAIN: result << "&#" << ic << ";"; ++firstpos; break; default: throw "Unexpected or unrecognized input encoding"; } } return escape_html_tags(result.str()); } /** * Prints out the provided type in HTML */ int t_html_generator::print_type(t_type* ttype) { std::string::size_type len = 0; f_out_ << ""; if (ttype->is_container()) { if (ttype->is_list()) { f_out_ << "list<"; len = 6 + print_type(((t_list*)ttype)->get_elem_type()); f_out_ << ">"; } else if (ttype->is_set()) { f_out_ << "set<"; len = 5 + print_type(((t_set*)ttype)->get_elem_type()); f_out_ << ">"; } else if (ttype->is_map()) { f_out_ << "map<"; len = 5 + print_type(((t_map*)ttype)->get_key_type()); f_out_ << ", "; len += print_type(((t_map*)ttype)->get_val_type()); f_out_ << ">"; } } else if (ttype->is_base_type()) { f_out_ << (ttype->is_binary() ? "binary" : ttype->get_name()); len = ttype->get_name().size(); } else { string prog_name = ttype->get_program()->get_name(); string type_name = ttype->get_name(); f_out_ << "
is_typedef()) { f_out_ << "Typedef_"; } else if (ttype->is_struct() || ttype->is_xception()) { f_out_ << "Struct_"; } else if (ttype->is_enum()) { f_out_ << "Enum_"; } else if (ttype->is_service()) { f_out_ << "Svc_"; } f_out_ << type_name << "\">"; len = type_name.size(); if (ttype->get_program() != program_) { f_out_ << prog_name << "."; len += prog_name.size() + 1; } f_out_ << type_name << ""; } f_out_ << ""; return (int)len; } /** * Prints out an HTML representation of the provided constant value */ void t_html_generator::print_const_value(t_type* type, t_const_value* tvalue) { // if tvalue is an identifier, the constant content is already shown elsewhere if (tvalue->get_type() == t_const_value::CV_IDENTIFIER) { string fname = program_->get_name() + ".html"; string name = escape_html(tvalue->get_identifier()); f_out_ << "" + name + ""; return; } t_type* truetype = type; while (truetype->is_typedef()) { truetype = ((t_typedef*)truetype)->get_type(); } bool first = true; if (truetype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: f_out_ << '"' << escape_html(get_escaped_string(tvalue)) << '"'; break; case t_base_type::TYPE_BOOL: f_out_ << ((tvalue->get_integer() != 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I16: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I32: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I64: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (tvalue->get_type() == t_const_value::CV_INTEGER) { f_out_ << tvalue->get_integer(); } else { f_out_ << tvalue->get_double(); } break; default: f_out_ << "UNKNOWN BASE TYPE"; break; } } else if (truetype->is_enum()) { f_out_ << escape_html(truetype->get_name()) << "." << escape_html(tvalue->get_identifier_name()); } else if (truetype->is_struct() || truetype->is_xception()) { f_out_ << "{ "; const vector& fields = ((t_struct*)truetype)->get_members(); vector::const_iterator f_iter; const map& val = tvalue->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + truetype->get_name() + " has no field " + v_iter->first->get_string(); } if (!first) { f_out_ << ", "; } first = false; f_out_ << escape_html(v_iter->first->get_string()) << " = "; print_const_value(field_type, v_iter->second); } f_out_ << " }"; } else if (truetype->is_map()) { f_out_ << "{ "; map map_elems = tvalue->get_map(); map::iterator map_iter; for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_map*)truetype)->get_key_type(), map_iter->first); f_out_ << " = "; print_const_value(((t_map*)truetype)->get_val_type(), map_iter->second); } f_out_ << " }"; } else if (truetype->is_list()) { f_out_ << "{ "; vector list_elems = tvalue->get_list(); ; vector::iterator list_iter; for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_list*)truetype)->get_elem_type(), *list_iter); } f_out_ << " }"; } else if (truetype->is_set()) { f_out_ << "{ "; vector list_elems = tvalue->get_list(); ; vector::iterator list_iter; for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_set*)truetype)->get_elem_type(), *list_iter); } f_out_ << " }"; } else { f_out_ << "UNKNOWN TYPE"; } } /** * Prints out documentation for arguments/exceptions of a function, if any documentation has been * supplied. */ void t_html_generator::print_fn_args_doc(t_function* tfunction) { bool has_docs = false; vector args = tfunction->get_arglist()->get_members(); vector::iterator arg_iter = args.begin(); if (arg_iter != args.end()) { for (; arg_iter != args.end(); arg_iter++) { if ((*arg_iter)->has_doc() && !(*arg_iter)->get_doc().empty()) has_docs = true; } if (has_docs) { arg_iter = args.begin(); f_out_ << "

get_name() << "\">Parameters

" << '\n'; f_out_ << ""; f_out_ << ""; for (; arg_iter != args.end(); arg_iter++) { f_out_ << "" << '\n'; } f_out_ << "
NameDescription
" << (*arg_iter)->get_name(); f_out_ << ""; f_out_ << escape_html((*arg_iter)->get_doc()); f_out_ << "
"; } } has_docs = false; vector excepts = tfunction->get_xceptions()->get_members(); vector::iterator ex_iter = excepts.begin(); if (ex_iter != excepts.end()) { for (; ex_iter != excepts.end(); ex_iter++) { if ((*ex_iter)->has_doc() && !(*ex_iter)->get_doc().empty()) has_docs = true; } if (has_docs) { ex_iter = excepts.begin(); f_out_ << "

get_name() << "\">Exceptions

" << '\n'; f_out_ << ""; f_out_ << ""; for (; ex_iter != excepts.end(); ex_iter++) { f_out_ << "" << '\n'; } f_out_ << "
TypeDescription
" << (*ex_iter)->get_type()->get_name(); f_out_ << ""; f_out_ << escape_html((*ex_iter)->get_doc()); f_out_ << "
"; } } } /** * Generates a typedef. * * @param ttypedef The type definition */ void t_html_generator::generate_typedef(t_typedef* ttypedef) { string name = ttypedef->get_name(); f_out_ << "
"; f_out_ << "

Typedef: " << name << "

" << '\n'; f_out_ << "

Base type: "; print_type(ttypedef->get_type()); f_out_ << "

" << '\n'; print_doc(ttypedef); f_out_ << "
" << '\n'; } /** * Generates code for an enumerated type. * * @param tenum The enumeration */ void t_html_generator::generate_enum(t_enum* tenum) { string name = tenum->get_name(); f_out_ << "
"; f_out_ << "

Enumeration: " << name << "

" << '\n'; print_doc(tenum); vector values = tenum->get_constants(); vector::iterator val_iter; f_out_ << "
" << '\n'; for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { f_out_ << "" << '\n'; } f_out_ << "
"; f_out_ << (*val_iter)->get_name(); f_out_ << ""; f_out_ << (*val_iter)->get_value(); f_out_ << "" << '\n'; print_doc((*val_iter)); f_out_ << "
" << '\n'; } /** * Generates a constant value */ void t_html_generator::generate_const(t_const* tconst) { string name = tconst->get_name(); f_out_ << "" << name << ""; print_type(tconst->get_type()); f_out_ << ""; print_const_value(tconst->get_type(), tconst->get_value()); f_out_ << ""; if (tconst->has_doc()) { f_out_ << "
"; print_doc(tconst); f_out_ << "
"; } } /** * Generates a struct definition for a thrift data type. * * @param tstruct The struct definition */ void t_html_generator::generate_struct(t_struct* tstruct) { string name = tstruct->get_name(); f_out_ << "
"; f_out_ << "

"; if (tstruct->is_xception()) { f_out_ << "Exception: "; } else if (tstruct->is_union()) { f_out_ << "Union: "; } else { f_out_ << "Struct: "; } f_out_ << name << "

" << '\n'; vector members = tstruct->get_members(); vector::iterator mem_iter = members.begin(); f_out_ << ""; f_out_ << "" << '\n'; for (; mem_iter != members.end(); mem_iter++) { f_out_ << "" << '\n'; } f_out_ << "
KeyFieldTypeDescriptionRequirednessDefault value
" << (*mem_iter)->get_key() << ""; f_out_ << (*mem_iter)->get_name(); f_out_ << ""; print_type((*mem_iter)->get_type()); f_out_ << ""; f_out_ << escape_html((*mem_iter)->get_doc()); f_out_ << ""; if ((*mem_iter)->get_req() == t_field::T_OPTIONAL) { f_out_ << "optional"; } else if ((*mem_iter)->get_req() == t_field::T_REQUIRED) { f_out_ << "required"; } else { f_out_ << "default"; } f_out_ << ""; t_const_value* default_val = (*mem_iter)->get_value(); if (default_val != nullptr) { f_out_ << ""; print_const_value((*mem_iter)->get_type(), default_val); f_out_ << ""; } f_out_ << "

"; print_doc(tstruct); f_out_ << "
"; } /** * Exceptions are special structs * * @param tstruct The struct definition */ void t_html_generator::generate_xception(t_struct* txception) { generate_struct(txception); } /** * Generates the HTML block for a Thrift service. * * @param tservice The service definition */ void t_html_generator::generate_service(t_service* tservice) { f_out_ << "

Service: " << service_name_ << "

" << '\n'; if (tservice->get_extends()) { f_out_ << "
extends "; print_type(tservice->get_extends()); f_out_ << "
\n"; } print_doc(tservice); vector functions = tservice->get_functions(); vector::iterator fn_iter = functions.begin(); for (; fn_iter != functions.end(); fn_iter++) { string fn_name = (*fn_iter)->get_name(); f_out_ << "
"; f_out_ << "

Function: " << service_name_ << "." << fn_name << "

" << '\n'; f_out_ << "
";
    std::string::size_type offset = print_type((*fn_iter)->get_returntype());
    bool first = true;
    f_out_ << " " << fn_name << "(";
    offset += fn_name.size() + 2;
    vector args = (*fn_iter)->get_arglist()->get_members();
    vector::iterator arg_iter = args.begin();
    for (; arg_iter != args.end(); arg_iter++) {
      if (!first) {
        f_out_ << "," << '\n';
        for (std::string::size_type i = 0; i < offset; ++i) {
          f_out_ << " ";
        }
      }
      first = false;
      print_type((*arg_iter)->get_type());
      f_out_ << " " << (*arg_iter)->get_name();
      if ((*arg_iter)->get_value() != nullptr) {
        f_out_ << " = ";
        print_const_value((*arg_iter)->get_type(), (*arg_iter)->get_value());
      }
    }
    f_out_ << ")" << '\n';
    first = true;
    vector excepts = (*fn_iter)->get_xceptions()->get_members();
    vector::iterator ex_iter = excepts.begin();
    if (ex_iter != excepts.end()) {
      f_out_ << "    throws ";
      for (; ex_iter != excepts.end(); ex_iter++) {
        if (!first) {
          f_out_ << ", ";
        }
        first = false;
        print_type((*ex_iter)->get_type());
      }
      f_out_ << '\n';
    }
    f_out_ << "
"; print_doc(*fn_iter); print_fn_args_doc(*fn_iter); f_out_ << "
"; } } std::string t_html_generator::display_name() const { return "HTML"; } THRIFT_REGISTER_GENERATOR( html, "HTML", " standalone: Self-contained mode, includes all CSS in the HTML files.\n" " Generates no style.css file, but HTML files will be larger.\n" " noescape: Do not escape html in doc text.\n")