/* * 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 "t_generator.h" #include "platform.h" using namespace std; /** * 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) { out_dir_base_ = "gen-html"; escape_.clear(); escape_['&'] = "&"; escape_['<'] = "<"; escape_['>'] = ">"; escape_['"'] = """; escape_['\''] = "'"; } void generate_program(); 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(); void generate_css(); /** * Program-level generation functions */ void generate_typedef (t_typedef* ttypedef); void generate_enum (t_enum* tenum); void generate_const (t_const* tconst); void generate_struct (t_struct* tstruct); void generate_service (t_service* tservice); void generate_xception(t_struct* txception); void print_doc (t_doc* tdoc); int print_type (t_type* ttype); void print_const_value(t_const_value* tvalue); std::ofstream f_out_; }; /** * Emits the Table of Contents links at the top of the module's page */ void t_html_generator::generate_program_toc() { f_out_ << "" << "" << endl; generate_program_toc_row(program_); f_out_ << "
ModuleServicesData typesConstants
" << endl; } /** * 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 (vector::iterator iter = finished.begin(); iter != finished.end(); iter++) { if (tprog->get_path() == (*iter)->get_path()) { return; } } finished.push_back(tprog); generate_program_toc_row(tprog); vector includes = tprog->get_includes(); for (vector::iterator iter = includes.begin(); iter != includes.end(); iter++) { generate_program_toc_rows(*iter, 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_ << "" << endl << "" << 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 << "
" << endl; f_out_ << "
    " << endl; 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 (map::iterator html_iter = fn_html.begin(); html_iter != fn_html.end(); html_iter++) { f_out_ << html_iter->second << endl; } f_out_ << "
" << endl; } } f_out_ << "" << endl << ""; 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 // << "
" << endl; 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 // << "
" << endl; 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 //<< "
" << endl; string html = "" + name + ""; data_types.insert(pair(name, html)); } } for (map::iterator dt_iter = data_types.begin(); dt_iter != data_types.end(); dt_iter++) { f_out_ << dt_iter->second << "
" << endl; } f_out_ << "" << endl << ""; 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 (map::iterator con_iter = const_html.begin(); con_iter != const_html.end(); con_iter++) { f_out_ << con_iter->second << "
" << endl; } } f_out_ << "
" << endl << ""; } /** * 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()); string fname = get_out_dir() + program_->get_name() + ".html"; f_out_.open(fname.c_str()); f_out_ << "" << endl; f_out_ << "" << endl; f_out_ << "Thrift module: " << program_->get_name() << "" << endl << "

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

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

Constants

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

Enumerations

" << endl; // 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

" << endl; // 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

" << endl; // 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

" << endl; // 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_ << "" << endl; 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() { string index_fname = get_out_dir() + "index.html"; f_out_.open(index_fname.c_str()); f_out_ << "" << endl; f_out_ << "" << endl; f_out_ << "All Thrift declarations" << endl << "

All Thrift declarations

" << endl; f_out_ << "" << "" << endl; vector programs; generate_program_toc_rows(program_, programs); f_out_ << "
ModuleServicesData typesConstants
" << endl; f_out_ << "" << endl; f_out_.close(); } void t_html_generator::generate_css() { string css_fname = get_out_dir() + "style.css"; f_out_.open(css_fname.c_str()); f_out_ << "/* Auto-generated CSS for generated Thrift docs */" << endl; f_out_ << "body { font-family: Tahoma, sans-serif; }" << endl; f_out_ << "pre { background-color: #dddddd; padding: 6px; }" << endl; f_out_ << "h3,h4 { padding-top: 0px; margin-top: 0px; }" << endl; f_out_ << "div.definition { border: 1px solid gray; margin: 10px; padding: 10px; }" << endl; f_out_ << "div.extends { margin: -0.5em 0 1em 5em }" << endl; f_out_ << "table { border: 1px solid grey; border-collapse: collapse; }" << endl; f_out_ << "td { border: 1px solid grey; padding: 1px 6px; vertical-align: top; }" << endl; f_out_ << "th { border: 1px solid black; background-color: #bbbbbb;" << endl << " text-align: left; padding: 1px 6px; }" << endl; f_out_.close(); } /** * 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()) { string doc = tdoc->get_doc(); size_t index; while ((index = doc.find_first_of("\r\n")) != string::npos) { if (index == 0) { f_out_ << "

" << endl; } else { f_out_ << doc.substr(0, index) << endl; } if (index + 1 < doc.size() && doc.at(index) != doc.at(index + 1) && (doc.at(index + 1) == '\r' || doc.at(index + 1) == '\n')) { index++; } doc = doc.substr(index + 1); } f_out_ << doc << "
"; } } /** * Prints out the provided type in HTML */ int t_html_generator::print_type(t_type* ttype) { int 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->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 len; } /** * Prints out an HTML representation of the provided constant value */ void t_html_generator::print_const_value(t_const_value* tvalue) { bool first = true; switch (tvalue->get_type()) { case t_const_value::CV_INTEGER: f_out_ << tvalue->get_integer(); break; case t_const_value::CV_DOUBLE: f_out_ << tvalue->get_double(); break; case t_const_value::CV_STRING: f_out_ << '"' << get_escaped_string(tvalue) << '"'; break; case t_const_value::CV_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(map_iter->first); f_out_ << " = "; print_const_value(map_iter->second); } f_out_ << " }"; } break; case t_const_value::CV_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(*list_iter); } f_out_ << " }"; } break; default: f_out_ << "UNKNOWN"; break; } } /** * 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 << "

" << endl; f_out_ << "

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

" << endl; print_doc(ttypedef); f_out_ << "
" << endl; } /** * 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 << "

" << endl; print_doc(tenum); vector values = tenum->get_constants(); vector::iterator val_iter; f_out_ << "
" << endl; for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { f_out_ << "" << endl; } f_out_ << "
"; f_out_ << (*val_iter)->get_name(); f_out_ << ""; f_out_ << (*val_iter)->get_value(); f_out_ << "
" << endl; } /** * 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_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 { f_out_ << "Struct: "; } f_out_ << name << "

" << endl; vector members = tstruct->get_members(); vector::iterator mem_iter = members.begin(); f_out_ << ""; f_out_ << "" << endl; for ( ; mem_iter != members.end(); mem_iter++) { f_out_ << "" << endl; } f_out_ << "
FieldTypeRequiredDefault value
" << (*mem_iter)->get_name() << ""; print_type((*mem_iter)->get_type()); f_out_ << ""; if ((*mem_iter)->get_req() != t_field::T_OPTIONAL) { f_out_ << "yes"; } else { f_out_ << "no"; } f_out_ << ""; t_const_value* default_val = (*mem_iter)->get_value(); if (default_val != NULL) { print_const_value(default_val); } 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_ << "

" << endl; 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 << "

" << endl; f_out_ << "
";
    int 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();
    if (arg_iter != args.end()) {
      for ( ; arg_iter != args.end(); arg_iter++) {
	if (!first) {
	  f_out_ << "," << endl;
	  for (int 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() != NULL) {
	  f_out_ << " = ";
	  print_const_value((*arg_iter)->get_value());
	}
      }
    }
    f_out_ << ")" << endl;
    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_ << endl;
    }
    f_out_ << "
"; print_doc(*fn_iter); f_out_ << "
"; } } THRIFT_REGISTER_GENERATOR(html, "HTML", "");